• 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/override_decoration.h"
16 #include "src/ast/return_statement.h"
17 #include "src/ast/stage_decoration.h"
18 #include "src/ast/struct_block_decoration.h"
19 #include "src/resolver/resolver.h"
20 #include "src/resolver/resolver_test_helper.h"
21 #include "src/sem/multisampled_texture_type.h"
22 #include "src/sem/storage_texture_type.h"
23 
24 #include "gmock/gmock.h"
25 
26 namespace tint {
27 namespace resolver {
28 namespace {
29 
30 // Helpers and typedefs
31 template <typename T>
32 using DataType = builder::DataType<T>;
33 template <typename T>
34 using vec2 = builder::vec2<T>;
35 template <typename T>
36 using vec3 = builder::vec3<T>;
37 template <typename T>
38 using vec4 = builder::vec4<T>;
39 template <typename T>
40 using mat2x2 = builder::mat2x2<T>;
41 template <typename T>
42 using mat3x3 = builder::mat3x3<T>;
43 template <typename T>
44 using mat4x4 = builder::mat4x4<T>;
45 template <int N, typename T>
46 using array = builder::array<N, T>;
47 template <typename T>
48 using alias = builder::alias<T>;
49 template <typename T>
50 using alias1 = builder::alias1<T>;
51 template <typename T>
52 using alias2 = builder::alias2<T>;
53 template <typename T>
54 using alias3 = builder::alias3<T>;
55 using f32 = builder::f32;
56 using i32 = builder::i32;
57 using u32 = builder::u32;
58 
59 class ResolverTypeValidationTest : public resolver::TestHelper,
60                                    public testing::Test {};
61 
TEST_F(ResolverTypeValidationTest,VariableDeclNoConstructor_Pass)62 TEST_F(ResolverTypeValidationTest, VariableDeclNoConstructor_Pass) {
63   // {
64   // var a :i32;
65   // a = 2;
66   // }
67   auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, nullptr);
68   auto* lhs = Expr("a");
69   auto* rhs = Expr(2);
70 
71   auto* body =
72       Block(Decl(var), Assign(Source{Source::Location{12, 34}}, lhs, rhs));
73 
74   WrapInFunction(body);
75 
76   EXPECT_TRUE(r()->Resolve()) << r()->error();
77   ASSERT_NE(TypeOf(lhs), nullptr);
78   ASSERT_NE(TypeOf(rhs), nullptr);
79 }
80 
TEST_F(ResolverTypeValidationTest,GlobalConstantNoConstructor_Pass)81 TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Pass) {
82   // [[override(0)]] let a :i32;
83   GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr,
84               ast::DecorationList{create<ast::OverrideDecoration>(0)});
85 
86   EXPECT_TRUE(r()->Resolve()) << r()->error();
87 }
88 
TEST_F(ResolverTypeValidationTest,GlobalVariableWithStorageClass_Pass)89 TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) {
90   // var<private> global_var: f32;
91   Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kPrivate);
92 
93   EXPECT_TRUE(r()->Resolve()) << r()->error();
94 }
95 
TEST_F(ResolverTypeValidationTest,GlobalConstantWithStorageClass_Fail)96 TEST_F(ResolverTypeValidationTest, GlobalConstantWithStorageClass_Fail) {
97   // const<private> global_var: f32;
98   AST().AddGlobalVariable(create<ast::Variable>(
99       Source{{12, 34}}, Symbols().Register("global_var"),
100       ast::StorageClass::kPrivate, ast::Access::kUndefined, ty.f32(), true,
101       Expr(1.23f), ast::DecorationList{}));
102 
103   EXPECT_FALSE(r()->Resolve());
104   EXPECT_EQ(r()->error(),
105             "12:34 error: global constants shouldn't have a storage class");
106 }
107 
TEST_F(ResolverTypeValidationTest,GlobalConstNoStorageClass_Pass)108 TEST_F(ResolverTypeValidationTest, GlobalConstNoStorageClass_Pass) {
109   // let global_var: f32;
110   GlobalConst(Source{{12, 34}}, "global_var", ty.f32(), Construct(ty.f32()));
111 
112   EXPECT_TRUE(r()->Resolve()) << r()->error();
113 }
114 
TEST_F(ResolverTypeValidationTest,GlobalVariableUnique_Pass)115 TEST_F(ResolverTypeValidationTest, GlobalVariableUnique_Pass) {
116   // var global_var0 : f32 = 0.1;
117   // var global_var1 : i32 = 0;
118 
119   Global("global_var0", ty.f32(), ast::StorageClass::kPrivate, Expr(0.1f));
120 
121   Global(Source{{12, 34}}, "global_var1", ty.f32(), ast::StorageClass::kPrivate,
122          Expr(1.0f));
123 
124   EXPECT_TRUE(r()->Resolve()) << r()->error();
125 }
126 
TEST_F(ResolverTypeValidationTest,GlobalVariableFunctionVariableNotUnique_Pass)127 TEST_F(ResolverTypeValidationTest,
128        GlobalVariableFunctionVariableNotUnique_Pass) {
129   // fn my_func() {
130   //   var a: f32 = 2.0;
131   // }
132   // var a: f32 = 2.1;
133 
134   auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
135 
136   Func("my_func", ast::VariableList{}, ty.void_(), {Decl(var)});
137 
138   Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
139 
140   EXPECT_TRUE(r()->Resolve()) << r()->error();
141 }
142 
TEST_F(ResolverTypeValidationTest,RedeclaredIdentifierInnerScope_Pass)143 TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierInnerScope_Pass) {
144   // {
145   // if (true) { var a : f32 = 2.0; }
146   // var a : f32 = 3.14;
147   // }
148   auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
149 
150   auto* cond = Expr(true);
151   auto* body = Block(Decl(var));
152 
153   auto* var_a_float = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(3.1f));
154 
155   auto* outer_body =
156       Block(create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
157             Decl(Source{{12, 34}}, var_a_float));
158 
159   WrapInFunction(outer_body);
160 
161   EXPECT_TRUE(r()->Resolve());
162 }
163 
TEST_F(ResolverTypeValidationTest,RedeclaredIdentifierInnerScopeBlock_Pass)164 TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierInnerScopeBlock_Pass) {
165   // {
166   //  { var a : f32; }
167   //  var a : f32;
168   // }
169   auto* var_inner = Var("a", ty.f32(), ast::StorageClass::kNone);
170   auto* inner = Block(Decl(Source{{12, 34}}, var_inner));
171 
172   auto* var_outer = Var("a", ty.f32(), ast::StorageClass::kNone);
173   auto* outer_body = Block(inner, Decl(var_outer));
174 
175   WrapInFunction(outer_body);
176 
177   EXPECT_TRUE(r()->Resolve()) << r()->error();
178 }
179 
TEST_F(ResolverTypeValidationTest,RedeclaredIdentifierDifferentFunctions_Pass)180 TEST_F(ResolverTypeValidationTest,
181        RedeclaredIdentifierDifferentFunctions_Pass) {
182   // func0 { var a : f32 = 2.0; return; }
183   // func1 { var a : f32 = 3.0; return; }
184   auto* var0 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
185 
186   auto* var1 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(1.0f));
187 
188   Func("func0", ast::VariableList{}, ty.void_(),
189        ast::StatementList{
190            Decl(Source{{12, 34}}, var0),
191            Return(),
192        },
193        ast::DecorationList{});
194 
195   Func("func1", ast::VariableList{}, ty.void_(),
196        ast::StatementList{
197            Decl(Source{{13, 34}}, var1),
198            Return(),
199        });
200 
201   EXPECT_TRUE(r()->Resolve()) << r()->error();
202 }
203 
TEST_F(ResolverTypeValidationTest,ArraySize_UnsignedLiteral_Pass)204 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Pass) {
205   // var<private> a : array<f32, 4u>;
206   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4u)),
207          ast::StorageClass::kPrivate);
208   EXPECT_TRUE(r()->Resolve()) << r()->error();
209 }
210 
TEST_F(ResolverTypeValidationTest,ArraySize_SignedLiteral_Pass)211 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Pass) {
212   // var<private> a : array<f32, 4>;
213   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4)),
214          ast::StorageClass::kPrivate);
215   EXPECT_TRUE(r()->Resolve()) << r()->error();
216 }
217 
TEST_F(ResolverTypeValidationTest,ArraySize_UnsignedConstant_Pass)218 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConstant_Pass) {
219   // let size = 4u;
220   // var<private> a : array<f32, size>;
221   GlobalConst("size", nullptr, Expr(4u));
222   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
223          ast::StorageClass::kPrivate);
224   EXPECT_TRUE(r()->Resolve()) << r()->error();
225 }
226 
TEST_F(ResolverTypeValidationTest,ArraySize_SignedConstant_Pass)227 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Pass) {
228   // let size = 4;
229   // var<private> a : array<f32, size>;
230   GlobalConst("size", nullptr, Expr(4));
231   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
232          ast::StorageClass::kPrivate);
233   EXPECT_TRUE(r()->Resolve()) << r()->error();
234 }
235 
TEST_F(ResolverTypeValidationTest,ArraySize_UnsignedLiteral_Zero)236 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Zero) {
237   // var<private> a : array<f32, 0u>;
238   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0u)),
239          ast::StorageClass::kPrivate);
240   EXPECT_FALSE(r()->Resolve());
241   EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
242 }
243 
TEST_F(ResolverTypeValidationTest,ArraySize_SignedLiteral_Zero)244 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Zero) {
245   // var<private> a : array<f32, 0>;
246   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0)),
247          ast::StorageClass::kPrivate);
248   EXPECT_FALSE(r()->Resolve());
249   EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
250 }
251 
TEST_F(ResolverTypeValidationTest,ArraySize_SignedLiteral_Negative)252 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Negative) {
253   // var<private> a : array<f32, -10>;
254   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10)),
255          ast::StorageClass::kPrivate);
256   EXPECT_FALSE(r()->Resolve());
257   EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
258 }
259 
TEST_F(ResolverTypeValidationTest,ArraySize_UnsignedConstant_Zero)260 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConstant_Zero) {
261   // let size = 0u;
262   // var<private> a : array<f32, size>;
263   GlobalConst("size", nullptr, Expr(0u));
264   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
265          ast::StorageClass::kPrivate);
266   EXPECT_FALSE(r()->Resolve());
267   EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
268 }
269 
TEST_F(ResolverTypeValidationTest,ArraySize_SignedConstant_Zero)270 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Zero) {
271   // let size = 0;
272   // var<private> a : array<f32, size>;
273   GlobalConst("size", nullptr, Expr(0));
274   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
275          ast::StorageClass::kPrivate);
276   EXPECT_FALSE(r()->Resolve());
277   EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
278 }
279 
TEST_F(ResolverTypeValidationTest,ArraySize_SignedConstant_Negative)280 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Negative) {
281   // let size = -10;
282   // var<private> a : array<f32, size>;
283   GlobalConst("size", nullptr, Expr(-10));
284   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
285          ast::StorageClass::kPrivate);
286   EXPECT_FALSE(r()->Resolve());
287   EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
288 }
289 
TEST_F(ResolverTypeValidationTest,ArraySize_FloatLiteral)290 TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
291   // var<private> a : array<f32, 10.0>;
292   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10.f)),
293          ast::StorageClass::kPrivate);
294   EXPECT_FALSE(r()->Resolve());
295   EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
296 }
297 
TEST_F(ResolverTypeValidationTest,ArraySize_IVecLiteral)298 TEST_F(ResolverTypeValidationTest, ArraySize_IVecLiteral) {
299   // var<private> a : array<f32, vec2<i32>(10, 10)>;
300   Global(
301       "a",
302       ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10, 10)),
303       ast::StorageClass::kPrivate);
304   EXPECT_FALSE(r()->Resolve());
305   EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
306 }
307 
TEST_F(ResolverTypeValidationTest,ArraySize_FloatConstant)308 TEST_F(ResolverTypeValidationTest, ArraySize_FloatConstant) {
309   // let size = 10.0;
310   // var<private> a : array<f32, size>;
311   GlobalConst("size", nullptr, Expr(10.f));
312   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
313          ast::StorageClass::kPrivate);
314   EXPECT_FALSE(r()->Resolve());
315   EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
316 }
317 
TEST_F(ResolverTypeValidationTest,ArraySize_IVecConstant)318 TEST_F(ResolverTypeValidationTest, ArraySize_IVecConstant) {
319   // let size = vec2<i32>(100, 100);
320   // var<private> a : array<f32, size>;
321   GlobalConst("size", nullptr, Construct(ty.vec2<i32>(), 100, 100));
322   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
323          ast::StorageClass::kPrivate);
324   EXPECT_FALSE(r()->Resolve());
325   EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
326 }
327 
TEST_F(ResolverTypeValidationTest,ArraySize_TooBig_ImplicitStride)328 TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
329   // var<private> a : array<f32, 0x40000000>;
330   Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x40000000),
331          ast::StorageClass::kPrivate);
332   EXPECT_FALSE(r()->Resolve());
333   EXPECT_EQ(r()->error(),
334             "12:34 error: array size in bytes must not exceed 0xffffffff, but "
335             "is 0x100000000");
336 }
337 
TEST_F(ResolverTypeValidationTest,ArraySize_TooBig_ExplicitStride)338 TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ExplicitStride) {
339   // var<private> a : [[stride(8)]] array<f32, 0x20000000>;
340   Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x20000000, 8),
341          ast::StorageClass::kPrivate);
342   EXPECT_FALSE(r()->Resolve());
343   EXPECT_EQ(r()->error(),
344             "12:34 error: array size in bytes must not exceed 0xffffffff, but "
345             "is 0x100000000");
346 }
347 
TEST_F(ResolverTypeValidationTest,ArraySize_OverridableConstant)348 TEST_F(ResolverTypeValidationTest, ArraySize_OverridableConstant) {
349   // [[override]] let size = 10;
350   // var<private> a : array<f32, size>;
351   GlobalConst("size", nullptr, Expr(10), {Override()});
352   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
353          ast::StorageClass::kPrivate);
354   EXPECT_FALSE(r()->Resolve());
355   EXPECT_EQ(
356       r()->error(),
357       "12:34 error: array size expression must not be pipeline-overridable");
358 }
359 
TEST_F(ResolverTypeValidationTest,ArraySize_ModuleVar)360 TEST_F(ResolverTypeValidationTest, ArraySize_ModuleVar) {
361   // var<private> size : i32 = 10;
362   // var<private> a : array<f32, size>;
363   Global("size", ty.i32(), Expr(10), ast::StorageClass::kPrivate);
364   Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
365          ast::StorageClass::kPrivate);
366   EXPECT_FALSE(r()->Resolve());
367   EXPECT_EQ(
368       r()->error(),
369       "12:34 error: array size identifier must be a module-scope constant");
370 }
371 
TEST_F(ResolverTypeValidationTest,ArraySize_FunctionConstant)372 TEST_F(ResolverTypeValidationTest, ArraySize_FunctionConstant) {
373   // {
374   //   let size = 10;
375   //   var a : array<f32, size>;
376   // }
377   auto* size = Const("size", nullptr, Expr(10));
378   auto* a = Var("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")));
379   WrapInFunction(Block(Decl(size), Decl(a)));
380   EXPECT_FALSE(r()->Resolve());
381   EXPECT_EQ(
382       r()->error(),
383       "12:34 error: array size identifier must be a module-scope constant");
384 }
385 
TEST_F(ResolverTypeValidationTest,ArraySize_InvalidExpr)386 TEST_F(ResolverTypeValidationTest, ArraySize_InvalidExpr) {
387   // var a : array<f32, i32(4)>;
388   auto* size = Const("size", nullptr, Expr(10));
389   auto* a =
390       Var("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.i32(), 4)));
391   WrapInFunction(Block(Decl(size), Decl(a)));
392   EXPECT_FALSE(r()->Resolve());
393   EXPECT_EQ(r()->error(),
394             "12:34 error: array size expression must be either a literal or a "
395             "module-scope constant");
396 }
397 
TEST_F(ResolverTypeValidationTest,RuntimeArrayInFunction_Fail)398 TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
399   /// [[stage(vertex)]]
400   // fn func() { var a : array<i32>; }
401 
402   auto* var =
403       Var(Source{{12, 34}}, "a", ty.array<i32>(), ast::StorageClass::kNone);
404 
405   Func("func", ast::VariableList{}, ty.void_(),
406        ast::StatementList{
407            Decl(var),
408        },
409        ast::DecorationList{
410            Stage(ast::PipelineStage::kVertex),
411        });
412 
413   EXPECT_FALSE(r()->Resolve());
414   EXPECT_EQ(r()->error(),
415             "12:34 error: runtime arrays may only appear as the last member of "
416             "a struct");
417 }
418 
TEST_F(ResolverTypeValidationTest,Struct_TooBig)419 TEST_F(ResolverTypeValidationTest, Struct_TooBig) {
420   // struct Foo {
421   //   a: array<f32, 0x20000000>;
422   //   b: array<f32, 0x20000000>;
423   // };
424 
425   Structure(Source{{12, 34}}, "Foo",
426             {
427                 Member("a", ty.array<f32, 0x20000000>()),
428                 Member("b", ty.array<f32, 0x20000000>()),
429             });
430 
431   WrapInFunction();
432 
433   EXPECT_FALSE(r()->Resolve());
434   EXPECT_EQ(r()->error(),
435             "12:34 error: struct size in bytes must not exceed 0xffffffff, but "
436             "is 0x100000000");
437 }
438 
TEST_F(ResolverTypeValidationTest,Struct_MemberOffset_TooBig)439 TEST_F(ResolverTypeValidationTest, Struct_MemberOffset_TooBig) {
440   // struct Foo {
441   //   a: array<f32, 0x3fffffff>;
442   //   b: f32;
443   //   c: f32;
444   // };
445 
446   Structure("Foo", {
447                        Member("a", ty.array<f32, 0x3fffffff>()),
448                        Member("b", ty.f32()),
449                        Member(Source{{12, 34}}, "c", ty.f32()),
450                    });
451 
452   WrapInFunction();
453 
454   EXPECT_FALSE(r()->Resolve());
455   EXPECT_EQ(r()->error(),
456             "12:34 error: struct member has byte offset 0x100000000, but must "
457             "not exceed 0xffffffff");
458 }
459 
TEST_F(ResolverTypeValidationTest,RuntimeArrayIsLast_Pass)460 TEST_F(ResolverTypeValidationTest, RuntimeArrayIsLast_Pass) {
461   // [[block]]
462   // struct Foo {
463   //   vf: f32;
464   //   rt: array<f32>;
465   // };
466 
467   Structure("Foo",
468             {
469                 Member("vf", ty.f32()),
470                 Member("rt", ty.array<f32>()),
471             },
472             {create<ast::StructBlockDecoration>()});
473 
474   WrapInFunction();
475 
476   EXPECT_TRUE(r()->Resolve()) << r()->error();
477 }
478 
TEST_F(ResolverTypeValidationTest,RuntimeArrayIsLastNoBlock_Fail)479 TEST_F(ResolverTypeValidationTest, RuntimeArrayIsLastNoBlock_Fail) {
480   // struct Foo {
481   //   vf: f32;
482   //   rt: array<f32>;
483   // };
484 
485   Structure("Foo", {
486                        Member("vf", ty.f32()),
487                        Member(Source{{12, 34}}, "rt", ty.array<f32>()),
488                    });
489 
490   WrapInFunction();
491 
492   EXPECT_FALSE(r()->Resolve()) << r()->error();
493   EXPECT_EQ(r()->error(),
494             "12:34 error: a struct containing a runtime-sized array requires "
495             "the [[block]] attribute: 'Foo'");
496 }
497 
TEST_F(ResolverTypeValidationTest,RuntimeArrayIsNotLast_Fail)498 TEST_F(ResolverTypeValidationTest, RuntimeArrayIsNotLast_Fail) {
499   // [[block]]
500   // struct Foo {
501   //   rt: array<f32>;
502   //   vf: f32;
503   // };
504 
505   Structure("Foo",
506             {
507                 Member(Source{{12, 34}}, "rt", ty.array<f32>()),
508                 Member("vf", ty.f32()),
509             },
510             {create<ast::StructBlockDecoration>()});
511 
512   WrapInFunction();
513 
514   EXPECT_FALSE(r()->Resolve()) << r()->error();
515   EXPECT_EQ(
516       r()->error(),
517       R"(12:34 error: runtime arrays may only appear as the last member of a struct)");
518 }
519 
TEST_F(ResolverTypeValidationTest,RuntimeArrayAsGlobalVariable)520 TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
521   Global(Source{{56, 78}}, "g", ty.array<i32>(), ast::StorageClass::kPrivate);
522 
523   ASSERT_FALSE(r()->Resolve());
524 
525   EXPECT_EQ(
526       r()->error(),
527       R"(56:78 error: runtime arrays may only appear as the last member of a struct)");
528 }
529 
TEST_F(ResolverTypeValidationTest,RuntimeArrayAsLocalVariable)530 TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
531   auto* v = Var(Source{{56, 78}}, "g", ty.array<i32>());
532   WrapInFunction(v);
533 
534   ASSERT_FALSE(r()->Resolve());
535 
536   EXPECT_EQ(
537       r()->error(),
538       R"(56:78 error: runtime arrays may only appear as the last member of a struct)");
539 }
540 
TEST_F(ResolverTypeValidationTest,RuntimeArrayAsParameter_Fail)541 TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
542   // fn func(a : array<u32>) {}
543   // [[stage(vertex)]] fn main() {}
544 
545   auto* param = Param(Source{{12, 34}}, "a", ty.array<i32>());
546 
547   Func("func", ast::VariableList{param}, ty.void_(),
548        ast::StatementList{
549            Return(),
550        },
551        ast::DecorationList{});
552 
553   Func("main", ast::VariableList{}, ty.void_(),
554        ast::StatementList{
555            Return(),
556        },
557        ast::DecorationList{
558            Stage(ast::PipelineStage::kVertex),
559        });
560 
561   EXPECT_FALSE(r()->Resolve()) << r()->error();
562   EXPECT_EQ(r()->error(),
563             "12:34 error: runtime arrays may only appear as the last member of "
564             "a struct");
565 }
566 
TEST_F(ResolverTypeValidationTest,AliasRuntimeArrayIsNotLast_Fail)567 TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsNotLast_Fail) {
568   // [[block]]
569   // type RTArr = array<u32>;
570   // struct s {
571   //  b: RTArr;
572   //  a: u32;
573   //}
574 
575   auto* alias = Alias("RTArr", ty.array<u32>());
576   Structure("s",
577             {
578                 Member(Source{{12, 34}}, "b", ty.Of(alias)),
579                 Member("a", ty.u32()),
580             },
581             {create<ast::StructBlockDecoration>()});
582 
583   WrapInFunction();
584 
585   EXPECT_FALSE(r()->Resolve()) << r()->error();
586   EXPECT_EQ(r()->error(),
587             "12:34 error: runtime arrays may only appear as the last member of "
588             "a struct");
589 }
590 
TEST_F(ResolverTypeValidationTest,AliasRuntimeArrayIsLast_Pass)591 TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsLast_Pass) {
592   // [[block]]
593   // type RTArr = array<u32>;
594   // struct s {
595   //  a: u32;
596   //  b: RTArr;
597   //}
598 
599   auto* alias = Alias("RTArr", ty.array<u32>());
600   Structure("s",
601             {
602                 Member("a", ty.u32()),
603                 Member("b", ty.Of(alias)),
604             },
605             {create<ast::StructBlockDecoration>()});
606 
607   WrapInFunction();
608 
609   EXPECT_TRUE(r()->Resolve()) << r()->error();
610 }
611 
TEST_F(ResolverTypeValidationTest,ArrayOfNonStorableType)612 TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
613   auto* tex_ty = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
614   Global("arr", ty.array(Source{{12, 34}}, tex_ty, 4),
615          ast::StorageClass::kPrivate);
616 
617   EXPECT_FALSE(r()->Resolve());
618   EXPECT_EQ(r()->error(),
619             "12:34 error: texture_2d<f32> cannot be used as an element type of "
620             "an array");
621 }
622 
623 namespace GetCanonicalTests {
624 struct Params {
625   builder::ast_type_func_ptr create_ast_type;
626   builder::sem_type_func_ptr create_sem_type;
627 };
628 
629 template <typename T>
ParamsFor()630 constexpr Params ParamsFor() {
631   return Params{DataType<T>::AST, DataType<T>::Sem};
632 }
633 
634 static constexpr Params cases[] = {
635     ParamsFor<bool>(),
636     ParamsFor<alias<bool>>(),
637     ParamsFor<alias1<alias<bool>>>(),
638 
639     ParamsFor<vec3<f32>>(),
640     ParamsFor<alias<vec3<f32>>>(),
641     ParamsFor<alias1<alias<vec3<f32>>>>(),
642 
643     ParamsFor<vec3<alias<f32>>>(),
644     ParamsFor<alias1<vec3<alias<f32>>>>(),
645     ParamsFor<alias2<alias1<vec3<alias<f32>>>>>(),
646     ParamsFor<alias3<alias2<vec3<alias1<alias<f32>>>>>>(),
647 
648     ParamsFor<mat3x3<alias<f32>>>(),
649     ParamsFor<alias1<mat3x3<alias<f32>>>>(),
650     ParamsFor<alias2<alias1<mat3x3<alias<f32>>>>>(),
651     ParamsFor<alias3<alias2<mat3x3<alias1<alias<f32>>>>>>(),
652 
653     ParamsFor<alias1<alias<bool>>>(),
654     ParamsFor<alias1<alias<vec3<f32>>>>(),
655     ParamsFor<alias1<alias<mat3x3<f32>>>>(),
656 };
657 
658 using CanonicalTest = ResolverTestWithParam<Params>;
TEST_P(CanonicalTest,All)659 TEST_P(CanonicalTest, All) {
660   auto& params = GetParam();
661 
662   auto* type = params.create_ast_type(*this);
663 
664   auto* var = Var("v", type);
665   auto* expr = Expr("v");
666   WrapInFunction(var, expr);
667 
668   EXPECT_TRUE(r()->Resolve()) << r()->error();
669 
670   auto* got = TypeOf(expr)->UnwrapRef();
671   auto* expected = params.create_sem_type(*this);
672 
673   EXPECT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
674                            << "expected: " << FriendlyName(expected) << "\n";
675 }
676 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
677                          CanonicalTest,
678                          testing::ValuesIn(cases));
679 
680 }  // namespace GetCanonicalTests
681 
682 namespace MultisampledTextureTests {
683 struct DimensionParams {
684   ast::TextureDimension dim;
685   bool is_valid;
686 };
687 
688 static constexpr DimensionParams dimension_cases[] = {
689     DimensionParams{ast::TextureDimension::k1d, false},
690     DimensionParams{ast::TextureDimension::k2d, true},
691     DimensionParams{ast::TextureDimension::k2dArray, false},
692     DimensionParams{ast::TextureDimension::k3d, false},
693     DimensionParams{ast::TextureDimension::kCube, false},
694     DimensionParams{ast::TextureDimension::kCubeArray, false}};
695 
696 using MultisampledTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
TEST_P(MultisampledTextureDimensionTest,All)697 TEST_P(MultisampledTextureDimensionTest, All) {
698   auto& params = GetParam();
699   Global(Source{{12, 34}}, "a", ty.multisampled_texture(params.dim, ty.i32()),
700          ast::StorageClass::kNone, nullptr,
701          ast::DecorationList{GroupAndBinding(0, 0)});
702 
703   if (params.is_valid) {
704     EXPECT_TRUE(r()->Resolve()) << r()->error();
705   } else {
706     EXPECT_FALSE(r()->Resolve());
707     EXPECT_EQ(r()->error(),
708               "12:34 error: only 2d multisampled textures are supported");
709   }
710 }
711 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
712                          MultisampledTextureDimensionTest,
713                          testing::ValuesIn(dimension_cases));
714 
715 struct TypeParams {
716   builder::ast_type_func_ptr type_func;
717   bool is_valid;
718 };
719 
720 template <typename T>
TypeParamsFor(bool is_valid)721 constexpr TypeParams TypeParamsFor(bool is_valid) {
722   return TypeParams{DataType<T>::AST, is_valid};
723 }
724 
725 static constexpr TypeParams type_cases[] = {
726     TypeParamsFor<bool>(false),
727     TypeParamsFor<i32>(true),
728     TypeParamsFor<u32>(true),
729     TypeParamsFor<f32>(true),
730 
731     TypeParamsFor<alias<bool>>(false),
732     TypeParamsFor<alias<i32>>(true),
733     TypeParamsFor<alias<u32>>(true),
734     TypeParamsFor<alias<f32>>(true),
735 
736     TypeParamsFor<vec3<f32>>(false),
737     TypeParamsFor<mat3x3<f32>>(false),
738 
739     TypeParamsFor<alias<vec3<f32>>>(false),
740     TypeParamsFor<alias<mat3x3<f32>>>(false),
741 };
742 
743 using MultisampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
TEST_P(MultisampledTextureTypeTest,All)744 TEST_P(MultisampledTextureTypeTest, All) {
745   auto& params = GetParam();
746   Global(Source{{12, 34}}, "a",
747          ty.multisampled_texture(ast::TextureDimension::k2d,
748                                  params.type_func(*this)),
749          ast::StorageClass::kNone, nullptr,
750          ast::DecorationList{GroupAndBinding(0, 0)});
751 
752   if (params.is_valid) {
753     EXPECT_TRUE(r()->Resolve()) << r()->error();
754   } else {
755     EXPECT_FALSE(r()->Resolve());
756     EXPECT_EQ(r()->error(),
757               "12:34 error: texture_multisampled_2d<type>: type must be f32, "
758               "i32 or u32");
759   }
760 }
761 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
762                          MultisampledTextureTypeTest,
763                          testing::ValuesIn(type_cases));
764 
765 }  // namespace MultisampledTextureTests
766 
767 namespace StorageTextureTests {
768 struct DimensionParams {
769   ast::TextureDimension dim;
770   bool is_valid;
771 };
772 
773 static constexpr DimensionParams Dimension_cases[] = {
774     DimensionParams{ast::TextureDimension::k1d, true},
775     DimensionParams{ast::TextureDimension::k2d, true},
776     DimensionParams{ast::TextureDimension::k2dArray, true},
777     DimensionParams{ast::TextureDimension::k3d, true},
778     DimensionParams{ast::TextureDimension::kCube, false},
779     DimensionParams{ast::TextureDimension::kCubeArray, false}};
780 
781 using StorageTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
TEST_P(StorageTextureDimensionTest,All)782 TEST_P(StorageTextureDimensionTest, All) {
783   // [[group(0), binding(0)]]
784   // var a : texture_storage_*<ru32int, write>;
785   auto& params = GetParam();
786 
787   auto* st =
788       ty.storage_texture(Source{{12, 34}}, params.dim,
789                          ast::ImageFormat::kR32Uint, ast::Access::kWrite);
790 
791   Global("a", st, ast::StorageClass::kNone,
792          ast::DecorationList{GroupAndBinding(0, 0)});
793 
794   if (params.is_valid) {
795     EXPECT_TRUE(r()->Resolve()) << r()->error();
796   } else {
797     EXPECT_FALSE(r()->Resolve());
798     EXPECT_EQ(
799         r()->error(),
800         "12:34 error: cube dimensions for storage textures are not supported");
801   }
802 }
803 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
804                          StorageTextureDimensionTest,
805                          testing::ValuesIn(Dimension_cases));
806 
807 struct FormatParams {
808   ast::ImageFormat format;
809   bool is_valid;
810 };
811 
812 static constexpr FormatParams format_cases[] = {
813     FormatParams{ast::ImageFormat::kBgra8Unorm, false},
814     FormatParams{ast::ImageFormat::kBgra8UnormSrgb, false},
815     FormatParams{ast::ImageFormat::kR16Float, false},
816     FormatParams{ast::ImageFormat::kR16Sint, false},
817     FormatParams{ast::ImageFormat::kR16Uint, false},
818     FormatParams{ast::ImageFormat::kR32Float, true},
819     FormatParams{ast::ImageFormat::kR32Sint, true},
820     FormatParams{ast::ImageFormat::kR32Uint, true},
821     FormatParams{ast::ImageFormat::kR8Sint, false},
822     FormatParams{ast::ImageFormat::kR8Snorm, false},
823     FormatParams{ast::ImageFormat::kR8Uint, false},
824     FormatParams{ast::ImageFormat::kR8Unorm, false},
825     FormatParams{ast::ImageFormat::kRg11B10Float, false},
826     FormatParams{ast::ImageFormat::kRg16Float, false},
827     FormatParams{ast::ImageFormat::kRg16Sint, false},
828     FormatParams{ast::ImageFormat::kRg16Uint, false},
829     FormatParams{ast::ImageFormat::kRg32Float, true},
830     FormatParams{ast::ImageFormat::kRg32Sint, true},
831     FormatParams{ast::ImageFormat::kRg32Uint, true},
832     FormatParams{ast::ImageFormat::kRg8Sint, false},
833     FormatParams{ast::ImageFormat::kRg8Snorm, false},
834     FormatParams{ast::ImageFormat::kRg8Uint, false},
835     FormatParams{ast::ImageFormat::kRg8Unorm, false},
836     FormatParams{ast::ImageFormat::kRgb10A2Unorm, false},
837     FormatParams{ast::ImageFormat::kRgba16Float, true},
838     FormatParams{ast::ImageFormat::kRgba16Sint, true},
839     FormatParams{ast::ImageFormat::kRgba16Uint, true},
840     FormatParams{ast::ImageFormat::kRgba32Float, true},
841     FormatParams{ast::ImageFormat::kRgba32Sint, true},
842     FormatParams{ast::ImageFormat::kRgba32Uint, true},
843     FormatParams{ast::ImageFormat::kRgba8Sint, true},
844     FormatParams{ast::ImageFormat::kRgba8Snorm, true},
845     FormatParams{ast::ImageFormat::kRgba8Uint, true},
846     FormatParams{ast::ImageFormat::kRgba8Unorm, true},
847     FormatParams{ast::ImageFormat::kRgba8UnormSrgb, false}};
848 
849 using StorageTextureFormatTest = ResolverTestWithParam<FormatParams>;
TEST_P(StorageTextureFormatTest,All)850 TEST_P(StorageTextureFormatTest, All) {
851   auto& params = GetParam();
852   // [[group(0), binding(0)]]
853   // var a : texture_storage_1d<*, write>;
854   // [[group(0), binding(1)]]
855   // var b : texture_storage_2d<*, write>;
856   // [[group(0), binding(2)]]
857   // var c : texture_storage_2d_array<*, write>;
858   // [[group(0), binding(3)]]
859   // var d : texture_storage_3d<*, write>;
860 
861   auto* st_a = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
862                                   params.format, ast::Access::kWrite);
863   Global("a", st_a, ast::StorageClass::kNone,
864          ast::DecorationList{GroupAndBinding(0, 0)});
865 
866   auto* st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format,
867                                   ast::Access::kWrite);
868   Global("b", st_b, ast::StorageClass::kNone,
869          ast::DecorationList{GroupAndBinding(0, 1)});
870 
871   auto* st_c = ty.storage_texture(ast::TextureDimension::k2dArray,
872                                   params.format, ast::Access::kWrite);
873   Global("c", st_c, ast::StorageClass::kNone,
874          ast::DecorationList{GroupAndBinding(0, 2)});
875 
876   auto* st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format,
877                                   ast::Access::kWrite);
878   Global("d", st_d, ast::StorageClass::kNone,
879          ast::DecorationList{GroupAndBinding(0, 3)});
880 
881   if (params.is_valid) {
882     EXPECT_TRUE(r()->Resolve()) << r()->error();
883   } else {
884     EXPECT_FALSE(r()->Resolve());
885     EXPECT_EQ(r()->error(),
886               "12:34 error: image format must be one of the texel formats "
887               "specified for storage textues in "
888               "https://gpuweb.github.io/gpuweb/wgsl/#texel-formats");
889   }
890 }
891 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
892                          StorageTextureFormatTest,
893                          testing::ValuesIn(format_cases));
894 
895 using StorageTextureAccessTest = ResolverTest;
896 
TEST_F(StorageTextureAccessTest,MissingAccess_Fail)897 TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
898   // [[group(0), binding(0)]]
899   // var a : texture_storage_1d<ru32int>;
900 
901   auto* st =
902       ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
903                          ast::ImageFormat::kR32Uint, ast::Access::kUndefined);
904 
905   Global("a", st, ast::StorageClass::kNone,
906          ast::DecorationList{GroupAndBinding(0, 0)});
907 
908   EXPECT_FALSE(r()->Resolve());
909   EXPECT_EQ(r()->error(),
910             "12:34 error: storage texture missing access control");
911 }
912 
TEST_F(StorageTextureAccessTest,RWAccess_Fail)913 TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
914   // [[group(0), binding(0)]]
915   // var a : texture_storage_1d<ru32int, read_write>;
916 
917   auto* st =
918       ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
919                          ast::ImageFormat::kR32Uint, ast::Access::kReadWrite);
920 
921   Global("a", st, ast::StorageClass::kNone, nullptr,
922          ast::DecorationList{GroupAndBinding(0, 0)});
923 
924   EXPECT_FALSE(r()->Resolve());
925   EXPECT_EQ(r()->error(),
926             "12:34 error: storage textures currently only support 'write' "
927             "access control");
928 }
929 
TEST_F(StorageTextureAccessTest,ReadOnlyAccess_Fail)930 TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
931   // [[group(0), binding(0)]]
932   // var a : texture_storage_1d<ru32int, read>;
933 
934   auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
935                                 ast::ImageFormat::kR32Uint, ast::Access::kRead);
936 
937   Global("a", st, ast::StorageClass::kNone, nullptr,
938          ast::DecorationList{GroupAndBinding(0, 0)});
939 
940   EXPECT_FALSE(r()->Resolve());
941   EXPECT_EQ(r()->error(),
942             "12:34 error: storage textures currently only support 'write' "
943             "access control");
944 }
945 
TEST_F(StorageTextureAccessTest,WriteOnlyAccess_Pass)946 TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
947   // [[group(0), binding(0)]]
948   // var a : texture_storage_1d<ru32int, write>;
949 
950   auto* st =
951       ty.storage_texture(ast::TextureDimension::k1d, ast::ImageFormat::kR32Uint,
952                          ast::Access::kWrite);
953 
954   Global("a", st, ast::StorageClass::kNone, nullptr,
955          ast::DecorationList{GroupAndBinding(0, 0)});
956 
957   EXPECT_TRUE(r()->Resolve()) << r()->error();
958 }
959 
960 }  // namespace StorageTextureTests
961 
962 namespace MatrixTests {
963 struct Params {
964   uint32_t columns;
965   uint32_t rows;
966   builder::ast_type_func_ptr elem_ty;
967 };
968 
969 template <typename T>
ParamsFor(uint32_t columns,uint32_t rows)970 constexpr Params ParamsFor(uint32_t columns, uint32_t rows) {
971   return Params{columns, rows, DataType<T>::AST};
972 }
973 
974 using ValidMatrixTypes = ResolverTestWithParam<Params>;
TEST_P(ValidMatrixTypes,Okay)975 TEST_P(ValidMatrixTypes, Okay) {
976   // var a : matNxM<EL_TY>;
977   auto& params = GetParam();
978   Global("a", ty.mat(params.elem_ty(*this), params.columns, params.rows),
979          ast::StorageClass::kPrivate);
980   EXPECT_TRUE(r()->Resolve()) << r()->error();
981 }
982 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
983                          ValidMatrixTypes,
984                          testing::Values(ParamsFor<f32>(2, 2),
985                                          ParamsFor<f32>(2, 3),
986                                          ParamsFor<f32>(2, 4),
987                                          ParamsFor<f32>(3, 2),
988                                          ParamsFor<f32>(3, 3),
989                                          ParamsFor<f32>(3, 4),
990                                          ParamsFor<f32>(4, 2),
991                                          ParamsFor<f32>(4, 3),
992                                          ParamsFor<f32>(4, 4),
993                                          ParamsFor<alias<f32>>(4, 2),
994                                          ParamsFor<alias<f32>>(4, 3),
995                                          ParamsFor<alias<f32>>(4, 4)));
996 
997 using InvalidMatrixElementTypes = ResolverTestWithParam<Params>;
TEST_P(InvalidMatrixElementTypes,InvalidElementType)998 TEST_P(InvalidMatrixElementTypes, InvalidElementType) {
999   // var a : matNxM<EL_TY>;
1000   auto& params = GetParam();
1001   Global("a",
1002          ty.mat(Source{{12, 34}}, params.elem_ty(*this), params.columns,
1003                 params.rows),
1004          ast::StorageClass::kPrivate);
1005   EXPECT_FALSE(r()->Resolve());
1006   EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32'");
1007 }
1008 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
1009                          InvalidMatrixElementTypes,
1010                          testing::Values(ParamsFor<bool>(4, 2),
1011                                          ParamsFor<i32>(4, 3),
1012                                          ParamsFor<u32>(4, 4),
1013                                          ParamsFor<vec2<f32>>(2, 2),
1014                                          ParamsFor<vec3<i32>>(2, 3),
1015                                          ParamsFor<vec4<u32>>(2, 4),
1016                                          ParamsFor<mat2x2<f32>>(3, 2),
1017                                          ParamsFor<mat3x3<f32>>(3, 3),
1018                                          ParamsFor<mat4x4<f32>>(3, 4),
1019                                          ParamsFor<array<2, f32>>(4, 2)));
1020 }  // namespace MatrixTests
1021 
1022 namespace VectorTests {
1023 struct Params {
1024   uint32_t width;
1025   builder::ast_type_func_ptr elem_ty;
1026 };
1027 
1028 template <typename T>
ParamsFor(uint32_t width)1029 constexpr Params ParamsFor(uint32_t width) {
1030   return Params{width, DataType<T>::AST};
1031 }
1032 
1033 using ValidVectorTypes = ResolverTestWithParam<Params>;
TEST_P(ValidVectorTypes,Okay)1034 TEST_P(ValidVectorTypes, Okay) {
1035   // var a : vecN<EL_TY>;
1036   auto& params = GetParam();
1037   Global("a", ty.vec(params.elem_ty(*this), params.width),
1038          ast::StorageClass::kPrivate);
1039   EXPECT_TRUE(r()->Resolve()) << r()->error();
1040 }
1041 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
1042                          ValidVectorTypes,
1043                          testing::Values(ParamsFor<bool>(2),
1044                                          ParamsFor<f32>(2),
1045                                          ParamsFor<i32>(2),
1046                                          ParamsFor<u32>(2),
1047                                          ParamsFor<bool>(3),
1048                                          ParamsFor<f32>(3),
1049                                          ParamsFor<i32>(3),
1050                                          ParamsFor<u32>(3),
1051                                          ParamsFor<bool>(4),
1052                                          ParamsFor<f32>(4),
1053                                          ParamsFor<i32>(4),
1054                                          ParamsFor<u32>(4),
1055                                          ParamsFor<alias<bool>>(4),
1056                                          ParamsFor<alias<f32>>(4),
1057                                          ParamsFor<alias<i32>>(4),
1058                                          ParamsFor<alias<u32>>(4)));
1059 
1060 using InvalidVectorElementTypes = ResolverTestWithParam<Params>;
TEST_P(InvalidVectorElementTypes,InvalidElementType)1061 TEST_P(InvalidVectorElementTypes, InvalidElementType) {
1062   // var a : vecN<EL_TY>;
1063   auto& params = GetParam();
1064   Global("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
1065          ast::StorageClass::kPrivate);
1066   EXPECT_FALSE(r()->Resolve());
1067   EXPECT_EQ(
1068       r()->error(),
1069       "12:34 error: vector element type must be 'bool', 'f32', 'i32' or 'u32'");
1070 }
1071 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
1072                          InvalidVectorElementTypes,
1073                          testing::Values(ParamsFor<vec2<f32>>(2),
1074                                          ParamsFor<vec3<i32>>(2),
1075                                          ParamsFor<vec4<u32>>(2),
1076                                          ParamsFor<mat2x2<f32>>(2),
1077                                          ParamsFor<mat3x3<f32>>(2),
1078                                          ParamsFor<mat4x4<f32>>(2),
1079                                          ParamsFor<array<2, f32>>(2)));
1080 }  // namespace VectorTests
1081 
1082 }  // namespace
1083 }  // namespace resolver
1084 }  // namespace tint
1085