• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/ast/break_statement.h"
16 #include "src/ast/continue_statement.h"
17 #include "src/ast/fallthrough_statement.h"
18 #include "src/ast/switch_statement.h"
19 #include "src/resolver/resolver_test_helper.h"
20 
21 namespace tint {
22 namespace {
23 
24 class ResolverControlBlockValidationTest : public resolver::TestHelper,
25                                            public testing::Test {};
26 
TEST_F(ResolverControlBlockValidationTest,SwitchSelectorExpressionNoneIntegerType_Fail)27 TEST_F(ResolverControlBlockValidationTest,
28        SwitchSelectorExpressionNoneIntegerType_Fail) {
29   // var a : f32 = 3.14;
30   // switch (a) {
31   //   default: {}
32   // }
33   auto* var = Var("a", ty.f32(), Expr(3.14f));
34 
35   auto* block = Block(Decl(var), Switch(Expr(Source{{12, 34}}, "a"),  //
36                                         DefaultCase()));
37 
38   WrapInFunction(block);
39 
40   EXPECT_FALSE(r()->Resolve());
41   EXPECT_EQ(r()->error(),
42             "12:34 error: switch statement selector expression must be of a "
43             "scalar integer type");
44 }
45 
TEST_F(ResolverControlBlockValidationTest,SwitchWithoutDefault_Fail)46 TEST_F(ResolverControlBlockValidationTest, SwitchWithoutDefault_Fail) {
47   // var a : i32 = 2;
48   // switch (a) {
49   //   case 1: {}
50   // }
51   auto* var = Var("a", ty.i32(), Expr(2));
52 
53   auto* block = Block(Decl(var),                     //
54                       Switch(Source{{12, 34}}, "a",  //
55                              Case(Expr(1))));
56 
57   WrapInFunction(block);
58 
59   EXPECT_FALSE(r()->Resolve());
60   EXPECT_EQ(r()->error(),
61             "12:34 error: switch statement must have a default clause");
62 }
63 
TEST_F(ResolverControlBlockValidationTest,SwitchWithTwoDefault_Fail)64 TEST_F(ResolverControlBlockValidationTest, SwitchWithTwoDefault_Fail) {
65   // var a : i32 = 2;
66   // switch (a) {
67   //   default: {}
68   //   case 1: {}
69   //   default: {}
70   // }
71   auto* var = Var("a", ty.i32(), Expr(2));
72 
73   auto* block = Block(Decl(var),             //
74                       Switch("a",            //
75                              DefaultCase(),  //
76                              Case(Expr(1)),  //
77                              DefaultCase(Source{{12, 34}})));
78 
79   WrapInFunction(block);
80 
81   EXPECT_FALSE(r()->Resolve());
82   EXPECT_EQ(
83       r()->error(),
84       "12:34 error: switch statement must have exactly one default clause");
85 }
86 
TEST_F(ResolverControlBlockValidationTest,UnreachableCode_Loop_continue)87 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_Loop_continue) {
88   // loop {
89   //   var z: i32;
90   //   continue;
91   //   z = 1;
92   // }
93   auto* decl_z = Decl(Var("z", ty.i32()));
94   auto* cont = Continue();
95   auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
96   WrapInFunction(Loop(Block(decl_z, cont, assign_z)));
97 
98   ASSERT_TRUE(r()->Resolve()) << r()->error();
99   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
100   EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
101   EXPECT_TRUE(Sem().Get(cont)->IsReachable());
102   EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
103 }
104 
TEST_F(ResolverControlBlockValidationTest,UnreachableCode_Loop_continue_InBlocks)105 TEST_F(ResolverControlBlockValidationTest,
106        UnreachableCode_Loop_continue_InBlocks) {
107   // loop {
108   //   var z: i32;
109   //   {{{continue;}}}
110   //   z = 1;
111   // }
112   auto* decl_z = Decl(Var("z", ty.i32()));
113   auto* cont = Continue();
114   auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
115   WrapInFunction(Loop(Block(decl_z, Block(Block(Block(cont))), assign_z)));
116 
117   ASSERT_TRUE(r()->Resolve()) << r()->error();
118   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
119   EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
120   EXPECT_TRUE(Sem().Get(cont)->IsReachable());
121   EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
122 }
123 
TEST_F(ResolverControlBlockValidationTest,UnreachableCode_ForLoop_continue)124 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_ForLoop_continue) {
125   // for (;;) {
126   //   var z: i32;
127   //   continue;
128   //   z = 1;
129   // }
130   auto* decl_z = Decl(Var("z", ty.i32()));
131   auto* cont = Continue();
132   auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
133   WrapInFunction(For(nullptr, nullptr, nullptr,  //
134                      Block(decl_z, cont, assign_z)));
135 
136   ASSERT_TRUE(r()->Resolve()) << r()->error();
137   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
138   EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
139   EXPECT_TRUE(Sem().Get(cont)->IsReachable());
140   EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
141 }
142 
TEST_F(ResolverControlBlockValidationTest,UnreachableCode_ForLoop_continue_InBlocks)143 TEST_F(ResolverControlBlockValidationTest,
144        UnreachableCode_ForLoop_continue_InBlocks) {
145   // for (;;) {
146   //   var z: i32;
147   //   {{{continue;}}}
148   //   z = 1;
149   // }
150   auto* decl_z = Decl(Var("z", ty.i32()));
151   auto* cont = Continue();
152   auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
153   WrapInFunction(For(nullptr, nullptr, nullptr,
154                      Block(decl_z, Block(Block(Block(cont))), assign_z)));
155 
156   ASSERT_TRUE(r()->Resolve()) << r()->error();
157   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
158   EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
159   EXPECT_TRUE(Sem().Get(cont)->IsReachable());
160   EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
161 }
162 
TEST_F(ResolverControlBlockValidationTest,UnreachableCode_break)163 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_break) {
164   // switch (1) {
165   //   case 1: {
166   //     var z: i32;
167   //     break;
168   //     z = 1;
169   //   default: {}
170   // }
171   auto* decl_z = Decl(Var("z", ty.i32()));
172   auto* brk = Break();
173   auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
174   WrapInFunction(                                                     //
175       Loop(Block(Switch(1,                                            //
176                         Case(Expr(1), Block(decl_z, brk, assign_z)),  //
177                         DefaultCase()))));
178 
179   ASSERT_TRUE(r()->Resolve()) << r()->error();
180   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
181   EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
182   EXPECT_TRUE(Sem().Get(brk)->IsReachable());
183   EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
184 }
185 
TEST_F(ResolverControlBlockValidationTest,UnreachableCode_break_InBlocks)186 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_break_InBlocks) {
187   // loop {
188   //   switch (1) {
189   //     case 1: { {{{break;}}} var a : u32 = 2;}
190   //     default: {}
191   //   }
192   // }
193   auto* decl_z = Decl(Var("z", ty.i32()));
194   auto* brk = Break();
195   auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
196   WrapInFunction(Loop(Block(
197       Switch(1,  //
198              Case(Expr(1), Block(decl_z, Block(Block(Block(brk))), assign_z)),
199              DefaultCase()))));
200 
201   ASSERT_TRUE(r()->Resolve()) << r()->error();
202   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
203   EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
204   EXPECT_TRUE(Sem().Get(brk)->IsReachable());
205   EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
206 }
207 
TEST_F(ResolverControlBlockValidationTest,SwitchConditionTypeMustMatchSelectorType2_Fail)208 TEST_F(ResolverControlBlockValidationTest,
209        SwitchConditionTypeMustMatchSelectorType2_Fail) {
210   // var a : u32 = 2;
211   // switch (a) {
212   //   case 1: {}
213   //   default: {}
214   // }
215   auto* var = Var("a", ty.i32(), Expr(2));
216 
217   auto* block = Block(Decl(var), Switch("a",                                 //
218                                         Case(Source{{12, 34}}, {Expr(1u)}),  //
219                                         DefaultCase()));
220   WrapInFunction(block);
221 
222   EXPECT_FALSE(r()->Resolve());
223   EXPECT_EQ(r()->error(),
224             "12:34 error: the case selector values must have the same type as "
225             "the selector expression.");
226 }
227 
TEST_F(ResolverControlBlockValidationTest,SwitchConditionTypeMustMatchSelectorType_Fail)228 TEST_F(ResolverControlBlockValidationTest,
229        SwitchConditionTypeMustMatchSelectorType_Fail) {
230   // var a : u32 = 2;
231   // switch (a) {
232   //   case -1: {}
233   //   default: {}
234   // }
235   auto* var = Var("a", ty.u32(), Expr(2u));
236 
237   auto* block = Block(Decl(var),                                  //
238                       Switch("a",                                 //
239                              Case(Source{{12, 34}}, {Expr(-1)}),  //
240                              DefaultCase()));
241   WrapInFunction(block);
242 
243   EXPECT_FALSE(r()->Resolve());
244   EXPECT_EQ(r()->error(),
245             "12:34 error: the case selector values must have the same type as "
246             "the selector expression.");
247 }
248 
TEST_F(ResolverControlBlockValidationTest,NonUniqueCaseSelectorValueUint_Fail)249 TEST_F(ResolverControlBlockValidationTest,
250        NonUniqueCaseSelectorValueUint_Fail) {
251   // var a : u32 = 3;
252   // switch (a) {
253   //   case 0u: {}
254   //   case 2u, 3u, 2u: {}
255   //   default: {}
256   // }
257   auto* var = Var("a", ty.u32(), Expr(3u));
258 
259   auto* block = Block(Decl(var),   //
260                       Switch("a",  //
261                              Case(Expr(0u)),
262                              Case({
263                                  Expr(Source{{12, 34}}, 2u),
264                                  Expr(3u),
265                                  Expr(Source{{56, 78}}, 2u),
266                              }),
267                              DefaultCase()));
268   WrapInFunction(block);
269 
270   EXPECT_FALSE(r()->Resolve());
271   EXPECT_EQ(r()->error(),
272             "56:78 error: duplicate switch case '2'\n"
273             "12:34 note: previous case declared here");
274 }
275 
TEST_F(ResolverControlBlockValidationTest,NonUniqueCaseSelectorValueSint_Fail)276 TEST_F(ResolverControlBlockValidationTest,
277        NonUniqueCaseSelectorValueSint_Fail) {
278   // var a : i32 = 2;
279   // switch (a) {
280   //   case -10: {}
281   //   case 0,1,2,-10: {}
282   //   default: {}
283   // }
284   auto* var = Var("a", ty.i32(), Expr(2));
285 
286   auto* block = Block(Decl(var),   //
287                       Switch("a",  //
288                              Case(Expr(Source{{12, 34}}, -10)),
289                              Case({
290                                  Expr(0),
291                                  Expr(1),
292                                  Expr(2),
293                                  Expr(Source{{56, 78}}, -10),
294                              }),
295                              DefaultCase()));
296   WrapInFunction(block);
297 
298   EXPECT_FALSE(r()->Resolve());
299   EXPECT_EQ(r()->error(),
300             "56:78 error: duplicate switch case '-10'\n"
301             "12:34 note: previous case declared here");
302 }
303 
TEST_F(ResolverControlBlockValidationTest,LastClauseLastStatementIsFallthrough_Fail)304 TEST_F(ResolverControlBlockValidationTest,
305        LastClauseLastStatementIsFallthrough_Fail) {
306   // var a : i32 = 2;
307   // switch (a) {
308   //   default: { fallthrough; }
309   // }
310   auto* var = Var("a", ty.i32(), Expr(2));
311   auto* fallthrough = create<ast::FallthroughStatement>(Source{{12, 34}});
312   auto* block = Block(Decl(var),   //
313                       Switch("a",  //
314                              DefaultCase(Block(fallthrough))));
315   WrapInFunction(block);
316 
317   EXPECT_FALSE(r()->Resolve());
318   EXPECT_EQ(r()->error(),
319             "12:34 error: a fallthrough statement must not be used in the last "
320             "switch case");
321 }
322 
TEST_F(ResolverControlBlockValidationTest,SwitchCase_Pass)323 TEST_F(ResolverControlBlockValidationTest, SwitchCase_Pass) {
324   // var a : i32 = 2;
325   // switch (a) {
326   //   default: {}
327   //   case 5: {}
328   // }
329   auto* var = Var("a", ty.i32(), Expr(2));
330 
331   auto* block = Block(Decl(var),                             //
332                       Switch("a",                            //
333                              DefaultCase(Source{{12, 34}}),  //
334                              Case(Expr(5))));
335   WrapInFunction(block);
336 
337   EXPECT_TRUE(r()->Resolve()) << r()->error();
338 }
339 
TEST_F(ResolverControlBlockValidationTest,SwitchCaseAlias_Pass)340 TEST_F(ResolverControlBlockValidationTest, SwitchCaseAlias_Pass) {
341   // type MyInt = u32;
342   // var v: MyInt;
343   // switch(v){
344   //   default: {}
345   // }
346 
347   auto* my_int = Alias("MyInt", ty.u32());
348   auto* var = Var("a", ty.Of(my_int), Expr(2u));
349   auto* block = Block(Decl(var),  //
350                       Switch("a", DefaultCase(Source{{12, 34}})));
351 
352   WrapInFunction(block);
353 
354   EXPECT_TRUE(r()->Resolve()) << r()->error();
355 }
356 
357 }  // namespace
358 }  // namespace tint
359