• 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/discard_statement.h"
16 #include "src/ast/return_statement.h"
17 #include "src/ast/stage_decoration.h"
18 #include "src/resolver/resolver.h"
19 #include "src/resolver/resolver_test_helper.h"
20 
21 #include "gmock/gmock.h"
22 
23 namespace tint {
24 namespace {
25 
26 class ResolverFunctionValidationTest : public resolver::TestHelper,
27                                        public testing::Test {};
28 
TEST_F(ResolverFunctionValidationTest,DuplicateParameterName)29 TEST_F(ResolverFunctionValidationTest, DuplicateParameterName) {
30   // fn func_a(common_name : f32) { }
31   // fn func_b(common_name : f32) { }
32   Func("func_a", {Param("common_name", ty.f32())}, ty.void_(), {});
33   Func("func_b", {Param("common_name", ty.f32())}, ty.void_(), {});
34 
35   ASSERT_TRUE(r()->Resolve()) << r()->error();
36 }
37 
TEST_F(ResolverFunctionValidationTest,ParameterMayShadowGlobal)38 TEST_F(ResolverFunctionValidationTest, ParameterMayShadowGlobal) {
39   // var<private> common_name : f32;
40   // fn func(common_name : f32) { }
41   Global("common_name", ty.f32(), ast::StorageClass::kPrivate);
42   Func("func", {Param("common_name", ty.f32())}, ty.void_(), {});
43 
44   ASSERT_TRUE(r()->Resolve()) << r()->error();
45 }
46 
TEST_F(ResolverFunctionValidationTest,LocalConflictsWithParameter)47 TEST_F(ResolverFunctionValidationTest, LocalConflictsWithParameter) {
48   // fn func(common_name : f32) {
49   //   let common_name = 1;
50   // }
51   Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
52        {Decl(Const(Source{{56, 78}}, "common_name", nullptr, Expr(1)))});
53 
54   EXPECT_FALSE(r()->Resolve());
55   EXPECT_EQ(r()->error(), R"(56:78 error: redeclaration of 'common_name'
56 12:34 note: 'common_name' previously declared here)");
57 }
58 
TEST_F(ResolverFunctionValidationTest,NestedLocalMayShadowParameter)59 TEST_F(ResolverFunctionValidationTest, NestedLocalMayShadowParameter) {
60   // fn func(common_name : f32) {
61   //   {
62   //     let common_name = 1;
63   //   }
64   // }
65   Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
66        {Block(Decl(Const(Source{{56, 78}}, "common_name", nullptr, Expr(1))))});
67 
68   ASSERT_TRUE(r()->Resolve()) << r()->error();
69 }
70 
TEST_F(ResolverFunctionValidationTest,VoidFunctionEndWithoutReturnStatement_Pass)71 TEST_F(ResolverFunctionValidationTest,
72        VoidFunctionEndWithoutReturnStatement_Pass) {
73   // fn func { var a:i32 = 2; }
74   auto* var = Var("a", ty.i32(), Expr(2));
75 
76   Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
77        ast::StatementList{
78            Decl(var),
79        });
80 
81   ASSERT_TRUE(r()->Resolve()) << r()->error();
82 }
83 
TEST_F(ResolverFunctionValidationTest,FunctionUsingSameVariableName_Pass)84 TEST_F(ResolverFunctionValidationTest, FunctionUsingSameVariableName_Pass) {
85   // fn func() -> i32 {
86   //   var func:i32 = 0;
87   //   return func;
88   // }
89 
90   auto* var = Var("func", ty.i32(), Expr(0));
91   Func("func", ast::VariableList{}, ty.i32(),
92        ast::StatementList{
93            Decl(var),
94            Return(Source{{12, 34}}, Expr("func")),
95        },
96        ast::DecorationList{});
97 
98   ASSERT_TRUE(r()->Resolve()) << r()->error();
99 }
100 
TEST_F(ResolverFunctionValidationTest,FunctionNameSameAsFunctionScopeVariableName_Pass)101 TEST_F(ResolverFunctionValidationTest,
102        FunctionNameSameAsFunctionScopeVariableName_Pass) {
103   // fn a() -> void { var b:i32 = 0; }
104   // fn b() -> i32 { return 2; }
105 
106   auto* var = Var("b", ty.i32(), Expr(0));
107   Func("a", ast::VariableList{}, ty.void_(),
108        ast::StatementList{
109            Decl(var),
110        },
111        ast::DecorationList{});
112 
113   Func(Source{{12, 34}}, "b", ast::VariableList{}, ty.i32(),
114        ast::StatementList{
115            Return(2),
116        },
117        ast::DecorationList{});
118 
119   ASSERT_TRUE(r()->Resolve()) << r()->error();
120 }
121 
TEST_F(ResolverFunctionValidationTest,UnreachableCode_return)122 TEST_F(ResolverFunctionValidationTest, UnreachableCode_return) {
123   // fn func() -> {
124   //  var a : i32;
125   //  return;
126   //  a = 2;
127   //}
128 
129   auto* decl_a = Decl(Var("a", ty.i32()));
130   auto* ret = Return();
131   auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
132 
133   Func("func", ast::VariableList{}, ty.void_(), {decl_a, ret, assign_a});
134 
135   ASSERT_TRUE(r()->Resolve());
136 
137   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
138   EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
139   EXPECT_TRUE(Sem().Get(ret)->IsReachable());
140   EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
141 }
142 
TEST_F(ResolverFunctionValidationTest,UnreachableCode_return_InBlocks)143 TEST_F(ResolverFunctionValidationTest, UnreachableCode_return_InBlocks) {
144   // fn func() -> {
145   //  var a : i32;
146   //  {{{return;}}}
147   //  a = 2;
148   //}
149 
150   auto* decl_a = Decl(Var("a", ty.i32()));
151   auto* ret = Return();
152   auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
153 
154   Func("func", ast::VariableList{}, ty.void_(),
155        {decl_a, Block(Block(Block(ret))), assign_a});
156 
157   ASSERT_TRUE(r()->Resolve());
158   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
159   EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
160   EXPECT_TRUE(Sem().Get(ret)->IsReachable());
161   EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
162 }
163 
TEST_F(ResolverFunctionValidationTest,UnreachableCode_discard)164 TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard) {
165   // fn func() -> {
166   //  var a : i32;
167   //  discard;
168   //  a = 2;
169   //}
170 
171   auto* decl_a = Decl(Var("a", ty.i32()));
172   auto* discard = Discard();
173   auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
174 
175   Func("func", ast::VariableList{}, ty.void_(), {decl_a, discard, assign_a});
176 
177   ASSERT_TRUE(r()->Resolve());
178   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
179   EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
180   EXPECT_TRUE(Sem().Get(discard)->IsReachable());
181   EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
182 }
183 
TEST_F(ResolverFunctionValidationTest,UnreachableCode_discard_InBlocks)184 TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard_InBlocks) {
185   // fn func() -> {
186   //  var a : i32;
187   //  {{{discard;}}}
188   //  a = 2;
189   //}
190 
191   auto* decl_a = Decl(Var("a", ty.i32()));
192   auto* discard = Discard();
193   auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
194 
195   Func("func", ast::VariableList{}, ty.void_(),
196        {decl_a, Block(Block(Block(discard))), assign_a});
197 
198   ASSERT_TRUE(r()->Resolve());
199   EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
200   EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
201   EXPECT_TRUE(Sem().Get(discard)->IsReachable());
202   EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
203 }
204 
TEST_F(ResolverFunctionValidationTest,FunctionEndWithoutReturnStatement_Fail)205 TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatement_Fail) {
206   // fn func() -> int { var a:i32 = 2; }
207 
208   auto* var = Var("a", ty.i32(), Expr(2));
209 
210   Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
211        ast::StatementList{
212            Decl(var),
213        },
214        ast::DecorationList{});
215 
216   EXPECT_FALSE(r()->Resolve());
217   EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
218 }
219 
TEST_F(ResolverFunctionValidationTest,VoidFunctionEndWithoutReturnStatementEmptyBody_Pass)220 TEST_F(ResolverFunctionValidationTest,
221        VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
222   // fn func {}
223 
224   Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
225        ast::StatementList{});
226 
227   ASSERT_TRUE(r()->Resolve()) << r()->error();
228 }
229 
TEST_F(ResolverFunctionValidationTest,FunctionEndWithoutReturnStatementEmptyBody_Fail)230 TEST_F(ResolverFunctionValidationTest,
231        FunctionEndWithoutReturnStatementEmptyBody_Fail) {
232   // fn func() -> int {}
233 
234   Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
235        ast::StatementList{}, ast::DecorationList{});
236 
237   EXPECT_FALSE(r()->Resolve());
238   EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
239 }
240 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementType_Pass)241 TEST_F(ResolverFunctionValidationTest,
242        FunctionTypeMustMatchReturnStatementType_Pass) {
243   // fn func { return; }
244 
245   Func("func", ast::VariableList{}, ty.void_(),
246        ast::StatementList{
247            Return(),
248        });
249 
250   ASSERT_TRUE(r()->Resolve()) << r()->error();
251 }
252 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementType_fail)253 TEST_F(ResolverFunctionValidationTest,
254        FunctionTypeMustMatchReturnStatementType_fail) {
255   // fn func { return 2; }
256   Func("func", ast::VariableList{}, ty.void_(),
257        ast::StatementList{
258            Return(Source{{12, 34}}, Expr(2)),
259        },
260        ast::DecorationList{});
261 
262   EXPECT_FALSE(r()->Resolve());
263   EXPECT_EQ(r()->error(),
264             "12:34 error: return statement type must match its function return "
265             "type, returned 'i32', expected 'void'");
266 }
267 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementType_void_fail)268 TEST_F(ResolverFunctionValidationTest,
269        FunctionTypeMustMatchReturnStatementType_void_fail) {
270   // fn v { return; }
271   // fn func { return v(); }
272   Func("v", {}, ty.void_(), {Return()});
273   Func("func", {}, ty.void_(),
274        {
275            Return(Call(Source{{12, 34}}, "v")),
276        });
277 
278   EXPECT_FALSE(r()->Resolve());
279   EXPECT_EQ(r()->error(), "12:34 error: function 'v' does not return a value");
280 }
281 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementTypeMissing_fail)282 TEST_F(ResolverFunctionValidationTest,
283        FunctionTypeMustMatchReturnStatementTypeMissing_fail) {
284   // fn func() -> f32 { return; }
285   Func("func", ast::VariableList{}, ty.f32(),
286        ast::StatementList{
287            Return(Source{{12, 34}}, nullptr),
288        },
289        ast::DecorationList{});
290 
291   EXPECT_FALSE(r()->Resolve());
292   EXPECT_EQ(r()->error(),
293             "12:34 error: return statement type must match its function return "
294             "type, returned 'void', expected 'f32'");
295 }
296 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementTypeF32_pass)297 TEST_F(ResolverFunctionValidationTest,
298        FunctionTypeMustMatchReturnStatementTypeF32_pass) {
299   // fn func() -> f32 { return 2.0; }
300   Func("func", ast::VariableList{}, ty.f32(),
301        ast::StatementList{
302            Return(Source{{12, 34}}, Expr(2.f)),
303        },
304        ast::DecorationList{});
305 
306   ASSERT_TRUE(r()->Resolve()) << r()->error();
307 }
308 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementTypeF32_fail)309 TEST_F(ResolverFunctionValidationTest,
310        FunctionTypeMustMatchReturnStatementTypeF32_fail) {
311   // fn func() -> f32 { return 2; }
312   Func("func", ast::VariableList{}, ty.f32(),
313        ast::StatementList{
314            Return(Source{{12, 34}}, Expr(2)),
315        },
316        ast::DecorationList{});
317 
318   EXPECT_FALSE(r()->Resolve());
319   EXPECT_EQ(r()->error(),
320             "12:34 error: return statement type must match its function return "
321             "type, returned 'i32', expected 'f32'");
322 }
323 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementTypeF32Alias_pass)324 TEST_F(ResolverFunctionValidationTest,
325        FunctionTypeMustMatchReturnStatementTypeF32Alias_pass) {
326   // type myf32 = f32;
327   // fn func() -> myf32 { return 2.0; }
328   auto* myf32 = Alias("myf32", ty.f32());
329   Func("func", ast::VariableList{}, ty.Of(myf32),
330        ast::StatementList{
331            Return(Source{{12, 34}}, Expr(2.f)),
332        },
333        ast::DecorationList{});
334 
335   ASSERT_TRUE(r()->Resolve()) << r()->error();
336 }
337 
TEST_F(ResolverFunctionValidationTest,FunctionTypeMustMatchReturnStatementTypeF32Alias_fail)338 TEST_F(ResolverFunctionValidationTest,
339        FunctionTypeMustMatchReturnStatementTypeF32Alias_fail) {
340   // type myf32 = f32;
341   // fn func() -> myf32 { return 2; }
342   auto* myf32 = Alias("myf32", ty.f32());
343   Func("func", ast::VariableList{}, ty.Of(myf32),
344        ast::StatementList{
345            Return(Source{{12, 34}}, Expr(2u)),
346        },
347        ast::DecorationList{});
348 
349   EXPECT_FALSE(r()->Resolve());
350   EXPECT_EQ(r()->error(),
351             "12:34 error: return statement type must match its function return "
352             "type, returned 'u32', expected 'f32'");
353 }
354 
TEST_F(ResolverFunctionValidationTest,CannotCallEntryPoint)355 TEST_F(ResolverFunctionValidationTest, CannotCallEntryPoint) {
356   // [[stage(compute), workgroup_size(1)]] fn entrypoint() {}
357   // fn func() { return entrypoint(); }
358   Func("entrypoint", ast::VariableList{}, ty.void_(), {},
359        {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
360 
361   Func("func", ast::VariableList{}, ty.void_(),
362        {
363            CallStmt(Call(Source{{12, 34}}, "entrypoint")),
364        });
365 
366   EXPECT_FALSE(r()->Resolve());
367   EXPECT_EQ(
368       r()->error(),
369 
370       R"(12:34 error: entry point functions cannot be the target of a function call)");
371 }
372 
TEST_F(ResolverFunctionValidationTest,PipelineStage_MustBeUnique_Fail)373 TEST_F(ResolverFunctionValidationTest, PipelineStage_MustBeUnique_Fail) {
374   // [[stage(fragment)]]
375   // [[stage(vertex)]]
376   // fn main() { return; }
377   Func(Source{{12, 34}}, "main", ast::VariableList{}, ty.void_(),
378        ast::StatementList{
379            Return(),
380        },
381        ast::DecorationList{
382            Stage(Source{{12, 34}}, ast::PipelineStage::kVertex),
383            Stage(Source{{56, 78}}, ast::PipelineStage::kFragment),
384        });
385 
386   EXPECT_FALSE(r()->Resolve());
387   EXPECT_EQ(r()->error(),
388             R"(56:78 error: duplicate stage decoration
389 12:34 note: first decoration declared here)");
390 }
391 
TEST_F(ResolverFunctionValidationTest,NoPipelineEntryPoints)392 TEST_F(ResolverFunctionValidationTest, NoPipelineEntryPoints) {
393   Func("vtx_func", ast::VariableList{}, ty.void_(),
394        ast::StatementList{
395            Return(),
396        },
397        ast::DecorationList{});
398 
399   ASSERT_TRUE(r()->Resolve()) << r()->error();
400 }
401 
TEST_F(ResolverFunctionValidationTest,FunctionVarInitWithParam)402 TEST_F(ResolverFunctionValidationTest, FunctionVarInitWithParam) {
403   // fn foo(bar : f32){
404   //   var baz : f32 = bar;
405   // }
406 
407   auto* bar = Param("bar", ty.f32());
408   auto* baz = Var("baz", ty.f32(), Expr("bar"));
409 
410   Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
411        ast::DecorationList{});
412 
413   ASSERT_TRUE(r()->Resolve()) << r()->error();
414 }
415 
TEST_F(ResolverFunctionValidationTest,FunctionConstInitWithParam)416 TEST_F(ResolverFunctionValidationTest, FunctionConstInitWithParam) {
417   // fn foo(bar : f32){
418   //   let baz : f32 = bar;
419   // }
420 
421   auto* bar = Param("bar", ty.f32());
422   auto* baz = Const("baz", ty.f32(), Expr("bar"));
423 
424   Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
425        ast::DecorationList{});
426 
427   ASSERT_TRUE(r()->Resolve()) << r()->error();
428 }
429 
TEST_F(ResolverFunctionValidationTest,FunctionParamsConst)430 TEST_F(ResolverFunctionValidationTest, FunctionParamsConst) {
431   Func("foo", {Param(Sym("arg"), ty.i32())}, ty.void_(),
432        {Assign(Expr(Source{{12, 34}}, "arg"), Expr(1)), Return()});
433 
434   EXPECT_FALSE(r()->Resolve());
435   EXPECT_EQ(r()->error(),
436             "12:34 error: cannot assign to function parameter\nnote: 'arg' is "
437             "declared here:");
438 }
439 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_GoodType_ConstU32)440 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_ConstU32) {
441   // let x = 4u;
442   // let x = 8u;
443   // [[stage(compute), workgroup_size(x, y, 16u)]]
444   // fn main() {}
445   auto* x = GlobalConst("x", ty.u32(), Expr(4u));
446   auto* y = GlobalConst("y", ty.u32(), Expr(8u));
447   auto* func = Func("main", {}, ty.void_(), {},
448                     {Stage(ast::PipelineStage::kCompute),
449                      WorkgroupSize(Expr("x"), Expr("y"), Expr(16u))});
450 
451   ASSERT_TRUE(r()->Resolve()) << r()->error();
452 
453   auto* sem_func = Sem().Get(func);
454   auto* sem_x = Sem().Get<sem::GlobalVariable>(x);
455   auto* sem_y = Sem().Get<sem::GlobalVariable>(y);
456 
457   ASSERT_NE(sem_func, nullptr);
458   ASSERT_NE(sem_x, nullptr);
459   ASSERT_NE(sem_y, nullptr);
460 
461   EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_x));
462   EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_y));
463 }
464 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_GoodType_U32)465 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_U32) {
466   // [[stage(compute), workgroup_size(1u, 2u, 3u)]
467   // fn main() {}
468 
469   Func("main", {}, ty.void_(), {},
470        {Stage(ast::PipelineStage::kCompute),
471         WorkgroupSize(Source{{12, 34}}, Expr(1u), Expr(2u), Expr(3u))});
472 
473   ASSERT_TRUE(r()->Resolve()) << r()->error();
474 }
475 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_MismatchTypeU32)476 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchTypeU32) {
477   // [[stage(compute), workgroup_size(1u, 2u, 3)]
478   // fn main() {}
479 
480   Func("main", {}, ty.void_(), {},
481        {Stage(ast::PipelineStage::kCompute),
482         WorkgroupSize(Expr(1u), Expr(2u), Expr(Source{{12, 34}}, 3))});
483 
484   EXPECT_FALSE(r()->Resolve());
485   EXPECT_EQ(r()->error(),
486             "12:34 error: workgroup_size arguments must be of the same type, "
487             "either i32 or u32");
488 }
489 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_MismatchTypeI32)490 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchTypeI32) {
491   // [[stage(compute), workgroup_size(1, 2u, 3)]
492   // fn main() {}
493 
494   Func("main", {}, ty.void_(), {},
495        {Stage(ast::PipelineStage::kCompute),
496         WorkgroupSize(Expr(1), Expr(Source{{12, 34}}, 2u), Expr(3))});
497 
498   EXPECT_FALSE(r()->Resolve());
499   EXPECT_EQ(r()->error(),
500             "12:34 error: workgroup_size arguments must be of the same type, "
501             "either i32 or u32");
502 }
503 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Const_TypeMismatch)504 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch) {
505   // let x = 64u;
506   // [[stage(compute), workgroup_size(1, x)]
507   // fn main() {}
508   GlobalConst("x", ty.u32(), Expr(64u));
509   Func("main", {}, ty.void_(), {},
510        {Stage(ast::PipelineStage::kCompute),
511         WorkgroupSize(Expr(1), Expr(Source{{12, 34}}, "x"))});
512 
513   EXPECT_FALSE(r()->Resolve());
514   EXPECT_EQ(r()->error(),
515             "12:34 error: workgroup_size arguments must be of the same type, "
516             "either i32 or u32");
517 }
518 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Const_TypeMismatch2)519 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch2) {
520   // let x = 64u;
521   // let y = 32;
522   // [[stage(compute), workgroup_size(x, y)]
523   // fn main() {}
524   GlobalConst("x", ty.u32(), Expr(64u));
525   GlobalConst("y", ty.i32(), Expr(32));
526   Func("main", {}, ty.void_(), {},
527        {Stage(ast::PipelineStage::kCompute),
528         WorkgroupSize(Expr("x"), Expr(Source{{12, 34}}, "y"))});
529 
530   EXPECT_FALSE(r()->Resolve());
531   EXPECT_EQ(r()->error(),
532             "12:34 error: workgroup_size arguments must be of the same type, "
533             "either i32 or u32");
534 }
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Mismatch_ConstU32)535 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Mismatch_ConstU32) {
536   // let x = 4u;
537   // let x = 8u;
538   // [[stage(compute), workgroup_size(x, y, 16]
539   // fn main() {}
540   GlobalConst("x", ty.u32(), Expr(4u));
541   GlobalConst("y", ty.u32(), Expr(8u));
542   Func("main", {}, ty.void_(), {},
543        {Stage(ast::PipelineStage::kCompute),
544         WorkgroupSize(Expr("x"), Expr("y"), Expr(Source{{12, 34}}, 16))});
545 
546   EXPECT_FALSE(r()->Resolve());
547   EXPECT_EQ(r()->error(),
548             "12:34 error: workgroup_size arguments must be of the same type, "
549             "either i32 or u32");
550 }
551 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Literal_BadType)552 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_BadType) {
553   // [[stage(compute), workgroup_size(64.0)]
554   // fn main() {}
555 
556   Func("main", {}, ty.void_(), {},
557        {Stage(ast::PipelineStage::kCompute),
558         WorkgroupSize(Expr(Source{{12, 34}}, 64.f))});
559 
560   EXPECT_FALSE(r()->Resolve());
561   EXPECT_EQ(r()->error(),
562             "12:34 error: workgroup_size argument must be either literal or "
563             "module-scope constant of type i32 or u32");
564 }
565 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Literal_Negative)566 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Negative) {
567   // [[stage(compute), workgroup_size(-2)]
568   // fn main() {}
569 
570   Func("main", {}, ty.void_(), {},
571        {Stage(ast::PipelineStage::kCompute),
572         WorkgroupSize(Expr(Source{{12, 34}}, -2))});
573 
574   EXPECT_FALSE(r()->Resolve());
575   EXPECT_EQ(r()->error(),
576             "12:34 error: workgroup_size argument must be at least 1");
577 }
578 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Literal_Zero)579 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Zero) {
580   // [[stage(compute), workgroup_size(0)]
581   // fn main() {}
582 
583   Func("main", {}, ty.void_(), {},
584        {Stage(ast::PipelineStage::kCompute),
585         WorkgroupSize(Expr(Source{{12, 34}}, 0))});
586 
587   EXPECT_FALSE(r()->Resolve());
588   EXPECT_EQ(r()->error(),
589             "12:34 error: workgroup_size argument must be at least 1");
590 }
591 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Const_BadType)592 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_BadType) {
593   // let x = 64.0;
594   // [[stage(compute), workgroup_size(x)]
595   // fn main() {}
596   GlobalConst("x", ty.f32(), Expr(64.f));
597   Func("main", {}, ty.void_(), {},
598        {Stage(ast::PipelineStage::kCompute),
599         WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
600 
601   EXPECT_FALSE(r()->Resolve());
602   EXPECT_EQ(r()->error(),
603             "12:34 error: workgroup_size argument must be either literal or "
604             "module-scope constant of type i32 or u32");
605 }
606 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Const_Negative)607 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Negative) {
608   // let x = -2;
609   // [[stage(compute), workgroup_size(x)]
610   // fn main() {}
611   GlobalConst("x", ty.i32(), Expr(-2));
612   Func("main", {}, ty.void_(), {},
613        {Stage(ast::PipelineStage::kCompute),
614         WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
615 
616   EXPECT_FALSE(r()->Resolve());
617   EXPECT_EQ(r()->error(),
618             "12:34 error: workgroup_size argument must be at least 1");
619 }
620 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Const_Zero)621 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Zero) {
622   // let x = 0;
623   // [[stage(compute), workgroup_size(x)]
624   // fn main() {}
625   GlobalConst("x", ty.i32(), Expr(0));
626   Func("main", {}, ty.void_(), {},
627        {Stage(ast::PipelineStage::kCompute),
628         WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
629 
630   EXPECT_FALSE(r()->Resolve());
631   EXPECT_EQ(r()->error(),
632             "12:34 error: workgroup_size argument must be at least 1");
633 }
634 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_Const_NestedZeroValueConstructor)635 TEST_F(ResolverFunctionValidationTest,
636        WorkgroupSize_Const_NestedZeroValueConstructor) {
637   // let x = i32(i32(i32()));
638   // [[stage(compute), workgroup_size(x)]
639   // fn main() {}
640   GlobalConst("x", ty.i32(),
641               Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32()))));
642   Func("main", {}, ty.void_(), {},
643        {Stage(ast::PipelineStage::kCompute),
644         WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
645 
646   EXPECT_FALSE(r()->Resolve());
647   EXPECT_EQ(r()->error(),
648             "12:34 error: workgroup_size argument must be at least 1");
649 }
650 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_NonConst)651 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
652   // var<private> x = 0;
653   // [[stage(compute), workgroup_size(x)]
654   // fn main() {}
655   Global("x", ty.i32(), ast::StorageClass::kPrivate, Expr(64));
656   Func("main", {}, ty.void_(), {},
657        {Stage(ast::PipelineStage::kCompute),
658         WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
659 
660   EXPECT_FALSE(r()->Resolve());
661   EXPECT_EQ(r()->error(),
662             "12:34 error: workgroup_size argument must be either literal or "
663             "module-scope constant of type i32 or u32");
664 }
665 
TEST_F(ResolverFunctionValidationTest,WorkgroupSize_InvalidExpr)666 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr) {
667   // [[stage(compute), workgroup_size(i32(1))]
668   // fn main() {}
669   Func("main", {}, ty.void_(), {},
670        {Stage(ast::PipelineStage::kCompute),
671         WorkgroupSize(Construct(Source{{12, 34}}, ty.i32(), 1))});
672 
673   EXPECT_FALSE(r()->Resolve());
674   EXPECT_EQ(r()->error(),
675             "12:34 error: workgroup_size argument must be either a literal or "
676             "a module-scope constant");
677 }
678 
TEST_F(ResolverFunctionValidationTest,ReturnIsConstructible_NonPlain)679 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
680   auto* ret_type =
681       ty.pointer(Source{{12, 34}}, ty.i32(), ast::StorageClass::kFunction);
682   Func("f", {}, ret_type, {});
683 
684   EXPECT_FALSE(r()->Resolve());
685   EXPECT_EQ(r()->error(),
686             "12:34 error: function return type must be a constructible type");
687 }
688 
TEST_F(ResolverFunctionValidationTest,ReturnIsConstructible_AtomicInt)689 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_AtomicInt) {
690   auto* ret_type = ty.atomic(Source{{12, 34}}, ty.i32());
691   Func("f", {}, ret_type, {});
692 
693   EXPECT_FALSE(r()->Resolve());
694   EXPECT_EQ(r()->error(),
695             "12:34 error: function return type must be a constructible type");
696 }
697 
TEST_F(ResolverFunctionValidationTest,ReturnIsConstructible_ArrayOfAtomic)698 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_ArrayOfAtomic) {
699   auto* ret_type = ty.array(Source{{12, 34}}, ty.atomic(ty.i32()), 10);
700   Func("f", {}, ret_type, {});
701 
702   EXPECT_FALSE(r()->Resolve());
703   EXPECT_EQ(r()->error(),
704             "12:34 error: function return type must be a constructible type");
705 }
706 
TEST_F(ResolverFunctionValidationTest,ReturnIsConstructible_StructOfAtomic)707 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_StructOfAtomic) {
708   Structure("S", {Member("m", ty.atomic(ty.i32()))});
709   auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
710   Func("f", {}, ret_type, {});
711 
712   EXPECT_FALSE(r()->Resolve());
713   EXPECT_EQ(r()->error(),
714             "12:34 error: function return type must be a constructible type");
715 }
716 
TEST_F(ResolverFunctionValidationTest,ReturnIsConstructible_RuntimeArray)717 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_RuntimeArray) {
718   auto* ret_type = ty.array(Source{{12, 34}}, ty.i32());
719   Func("f", {}, ret_type, {});
720 
721   EXPECT_FALSE(r()->Resolve());
722   EXPECT_EQ(r()->error(),
723             "12:34 error: function return type must be a constructible type");
724 }
725 
TEST_F(ResolverFunctionValidationTest,ParameterStoreType_NonAtomicFree)726 TEST_F(ResolverFunctionValidationTest, ParameterStoreType_NonAtomicFree) {
727   Structure("S", {Member("m", ty.atomic(ty.i32()))});
728   auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
729   auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
730   Func("f", ast::VariableList{bar}, ty.void_(), {});
731 
732   EXPECT_FALSE(r()->Resolve());
733   EXPECT_EQ(r()->error(),
734             "12:34 error: store type of function parameter must be a "
735             "constructible type");
736 }
737 
TEST_F(ResolverFunctionValidationTest,ParameterSotreType_AtomicFree)738 TEST_F(ResolverFunctionValidationTest, ParameterSotreType_AtomicFree) {
739   Structure("S", {Member("m", ty.i32())});
740   auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
741   auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
742   Func("f", ast::VariableList{bar}, ty.void_(), {});
743 
744   ASSERT_TRUE(r()->Resolve()) << r()->error();
745 }
746 
TEST_F(ResolverFunctionValidationTest,ParametersAtLimit)747 TEST_F(ResolverFunctionValidationTest, ParametersAtLimit) {
748   ast::VariableList params;
749   for (int i = 0; i < 255; i++) {
750     params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
751   }
752   Func(Source{{12, 34}}, "f", params, ty.void_(), {});
753 
754   ASSERT_TRUE(r()->Resolve()) << r()->error();
755 }
756 
TEST_F(ResolverFunctionValidationTest,ParametersOverLimit)757 TEST_F(ResolverFunctionValidationTest, ParametersOverLimit) {
758   ast::VariableList params;
759   for (int i = 0; i < 256; i++) {
760     params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
761   }
762   Func(Source{{12, 34}}, "f", params, ty.void_(), {});
763 
764   EXPECT_FALSE(r()->Resolve());
765   EXPECT_EQ(r()->error(),
766             "12:34 error: functions may declare at most 255 parameters");
767 }
768 
769 struct TestParams {
770   ast::StorageClass storage_class;
771   bool should_pass;
772 };
773 
774 struct TestWithParams : resolver::ResolverTestWithParam<TestParams> {};
775 
776 using ResolverFunctionParameterValidationTest = TestWithParams;
TEST_P(ResolverFunctionParameterValidationTest,StorageClass)777 TEST_P(ResolverFunctionParameterValidationTest, StorageClass) {
778   auto& param = GetParam();
779   auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.storage_class);
780   auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
781   Func("f", ast::VariableList{arg}, ty.void_(), {});
782 
783   if (param.should_pass) {
784     ASSERT_TRUE(r()->Resolve()) << r()->error();
785   } else {
786     std::stringstream ss;
787     ss << param.storage_class;
788     EXPECT_FALSE(r()->Resolve());
789     EXPECT_EQ(r()->error(),
790               "12:34 error: function parameter of pointer type cannot be in '" +
791                   ss.str() + "' storage class");
792   }
793 }
794 INSTANTIATE_TEST_SUITE_P(
795     ResolverTest,
796     ResolverFunctionParameterValidationTest,
797     testing::Values(TestParams{ast::StorageClass::kNone, false},
798                     TestParams{ast::StorageClass::kInput, false},
799                     TestParams{ast::StorageClass::kOutput, false},
800                     TestParams{ast::StorageClass::kUniform, false},
801                     TestParams{ast::StorageClass::kWorkgroup, true},
802                     TestParams{ast::StorageClass::kUniformConstant, false},
803                     TestParams{ast::StorageClass::kStorage, false},
804                     TestParams{ast::StorageClass::kImage, false},
805                     TestParams{ast::StorageClass::kPrivate, true},
806                     TestParams{ast::StorageClass::kFunction, true}));
807 
808 }  // namespace
809 }  // namespace tint
810