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