• 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/resolver/resolver.h"
16 
17 #include "gmock/gmock.h"
18 #include "gtest/gtest-spi.h"
19 #include "src/ast/assignment_statement.h"
20 #include "src/ast/bitcast_expression.h"
21 #include "src/ast/break_statement.h"
22 #include "src/ast/call_statement.h"
23 #include "src/ast/continue_statement.h"
24 #include "src/ast/discard_statement.h"
25 #include "src/ast/if_statement.h"
26 #include "src/ast/intrinsic_texture_helper_test.h"
27 #include "src/ast/loop_statement.h"
28 #include "src/ast/return_statement.h"
29 #include "src/ast/stage_decoration.h"
30 #include "src/ast/switch_statement.h"
31 #include "src/ast/unary_op_expression.h"
32 #include "src/ast/variable_decl_statement.h"
33 #include "src/resolver/resolver_test_helper.h"
34 #include "src/sem/call.h"
35 #include "src/sem/function.h"
36 #include "src/sem/member_accessor_expression.h"
37 #include "src/sem/sampled_texture_type.h"
38 #include "src/sem/statement.h"
39 #include "src/sem/variable.h"
40 
41 using ::testing::ElementsAre;
42 using ::testing::HasSubstr;
43 
44 namespace tint {
45 namespace resolver {
46 namespace {
47 
48 using ResolverValidationTest = ResolverTest;
49 
50 class FakeStmt : public Castable<FakeStmt, ast::Statement> {
51  public:
FakeStmt(ProgramID pid,Source src)52   FakeStmt(ProgramID pid, Source src) : Base(pid, src) {}
Clone(CloneContext *) const53   FakeStmt* Clone(CloneContext*) const override { return nullptr; }
54 };
55 
56 class FakeExpr : public Castable<FakeExpr, ast::Expression> {
57  public:
FakeExpr(ProgramID pid,Source src)58   FakeExpr(ProgramID pid, Source src) : Base(pid, src) {}
Clone(CloneContext *) const59   FakeExpr* Clone(CloneContext*) const override { return nullptr; }
60 };
61 
TEST_F(ResolverValidationTest,WorkgroupMemoryUsedInVertexStage)62 TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInVertexStage) {
63   Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
64   Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
65   auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
66 
67   Func(Source{{9, 10}}, "f0", ast::VariableList{}, ty.vec4<f32>(),
68        {stmt, Return(Expr("dst"))},
69        ast::DecorationList{Stage(ast::PipelineStage::kVertex)},
70        ast::DecorationList{Builtin(ast::Builtin::kPosition)});
71 
72   EXPECT_FALSE(r()->Resolve());
73   EXPECT_EQ(r()->error(),
74             "3:4 error: workgroup memory cannot be used by vertex pipeline "
75             "stage\n1:2 note: variable is declared here");
76 }
77 
TEST_F(ResolverValidationTest,WorkgroupMemoryUsedInFragmentStage)78 TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInFragmentStage) {
79   // var<workgroup> wg : vec4<f32>;
80   // var<workgroup> dst : vec4<f32>;
81   // fn f2(){ dst = wg; }
82   // fn f1() { f2(); }
83   // [[stage(fragment)]]
84   // fn f0() {
85   //  f1();
86   //}
87 
88   Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
89   Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
90   auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
91 
92   Func(Source{{5, 6}}, "f2", {}, ty.void_(), {stmt});
93   Func(Source{{7, 8}}, "f1", {}, ty.void_(), {CallStmt(Call("f2"))});
94   Func(Source{{9, 10}}, "f0", {}, ty.void_(), {CallStmt(Call("f1"))},
95        ast::DecorationList{Stage(ast::PipelineStage::kFragment)});
96 
97   EXPECT_FALSE(r()->Resolve());
98   EXPECT_EQ(
99       r()->error(),
100       R"(3:4 error: workgroup memory cannot be used by fragment pipeline stage
101 1:2 note: variable is declared here
102 5:6 note: called by function 'f2'
103 7:8 note: called by function 'f1'
104 9:10 note: called by entry point 'f0')");
105 }
106 
TEST_F(ResolverValidationTest,UnhandledStmt)107 TEST_F(ResolverValidationTest, UnhandledStmt) {
108   EXPECT_FATAL_FAILURE(
109       {
110         ProgramBuilder b;
111         b.WrapInFunction(b.create<FakeStmt>());
112         Program(std::move(b));
113       },
114       "internal compiler error: unhandled node type: tint::resolver::FakeStmt");
115 }
116 
TEST_F(ResolverValidationTest,Stmt_If_NonBool)117 TEST_F(ResolverValidationTest, Stmt_If_NonBool) {
118   // if (1.23f) {}
119 
120   WrapInFunction(If(Expr(Source{{12, 34}}, 1.23f), Block()));
121 
122   EXPECT_FALSE(r()->Resolve());
123 
124   EXPECT_EQ(r()->error(),
125             "12:34 error: if statement condition must be bool, got f32");
126 }
127 
TEST_F(ResolverValidationTest,Stmt_Else_NonBool)128 TEST_F(ResolverValidationTest, Stmt_Else_NonBool) {
129   // else (1.23f) {}
130 
131   WrapInFunction(
132       If(Expr(true), Block(), Else(Expr(Source{{12, 34}}, 1.23f), Block())));
133 
134   EXPECT_FALSE(r()->Resolve());
135 
136   EXPECT_EQ(r()->error(),
137             "12:34 error: else statement condition must be bool, got f32");
138 }
139 
TEST_F(ResolverValidationTest,Expr_ErrUnknownExprType)140 TEST_F(ResolverValidationTest, Expr_ErrUnknownExprType) {
141   EXPECT_FATAL_FAILURE(
142       {
143         ProgramBuilder b;
144         b.WrapInFunction(b.create<FakeExpr>());
145         Resolver(&b).Resolve();
146       },
147       "internal compiler error: unhandled expression type: "
148       "tint::resolver::FakeExpr");
149 }
150 
TEST_F(ResolverValidationTest,Expr_DontCall_Function)151 TEST_F(ResolverValidationTest, Expr_DontCall_Function) {
152   Func("func", {}, ty.void_(), {}, {});
153   WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "func"));
154 
155   EXPECT_FALSE(r()->Resolve());
156   EXPECT_EQ(r()->error(), "3:8 error: missing '(' for function call");
157 }
158 
TEST_F(ResolverValidationTest,Expr_DontCall_Intrinsic)159 TEST_F(ResolverValidationTest, Expr_DontCall_Intrinsic) {
160   WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "round"));
161 
162   EXPECT_FALSE(r()->Resolve());
163   EXPECT_EQ(r()->error(), "3:8 error: missing '(' for intrinsic call");
164 }
165 
TEST_F(ResolverValidationTest,Expr_DontCall_Type)166 TEST_F(ResolverValidationTest, Expr_DontCall_Type) {
167   Alias("T", ty.u32());
168   WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "T"));
169 
170   EXPECT_FALSE(r()->Resolve());
171   EXPECT_EQ(r()->error(),
172             "3:8 error: missing '(' for type constructor or cast");
173 }
174 
TEST_F(ResolverValidationTest,AssignmentStmt_InvalidLHS_IntrinsicFunctionName)175 TEST_F(ResolverValidationTest,
176        AssignmentStmt_InvalidLHS_IntrinsicFunctionName) {
177   // normalize = 2;
178 
179   auto* lhs = Expr(Source{{12, 34}}, "normalize");
180   auto* rhs = Expr(2);
181   auto* assign = Assign(lhs, rhs);
182   WrapInFunction(assign);
183 
184   EXPECT_FALSE(r()->Resolve());
185   EXPECT_EQ(r()->error(), "12:34 error: missing '(' for intrinsic call");
186 }
187 
TEST_F(ResolverValidationTest,UsingUndefinedVariable_Fail)188 TEST_F(ResolverValidationTest, UsingUndefinedVariable_Fail) {
189   // b = 2;
190 
191   auto* lhs = Expr(Source{{12, 34}}, "b");
192   auto* rhs = Expr(2);
193   auto* assign = Assign(lhs, rhs);
194   WrapInFunction(assign);
195 
196   EXPECT_FALSE(r()->Resolve());
197   EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'b'");
198 }
199 
TEST_F(ResolverValidationTest,UsingUndefinedVariableInBlockStatement_Fail)200 TEST_F(ResolverValidationTest, UsingUndefinedVariableInBlockStatement_Fail) {
201   // {
202   //  b = 2;
203   // }
204 
205   auto* lhs = Expr(Source{{12, 34}}, "b");
206   auto* rhs = Expr(2);
207 
208   auto* body = Block(Assign(lhs, rhs));
209   WrapInFunction(body);
210 
211   EXPECT_FALSE(r()->Resolve());
212   EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'b'");
213 }
214 
TEST_F(ResolverValidationTest,UsingUndefinedVariableGlobalVariable_Pass)215 TEST_F(ResolverValidationTest, UsingUndefinedVariableGlobalVariable_Pass) {
216   // var global_var: f32 = 2.1;
217   // fn my_func() {
218   //   global_var = 3.14;
219   //   return;
220   // }
221 
222   Global("global_var", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
223 
224   Func("my_func", ast::VariableList{}, ty.void_(),
225        {
226            Assign(Expr(Source{{12, 34}}, "global_var"), 3.14f),
227            Return(),
228        });
229 
230   EXPECT_TRUE(r()->Resolve()) << r()->error();
231 }
232 
TEST_F(ResolverValidationTest,UsingUndefinedVariableInnerScope_Fail)233 TEST_F(ResolverValidationTest, UsingUndefinedVariableInnerScope_Fail) {
234   // {
235   //   if (true) { var a : f32 = 2.0; }
236   //   a = 3.14;
237   // }
238   auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
239 
240   auto* cond = Expr(true);
241   auto* body = Block(Decl(var));
242 
243   SetSource(Source{{12, 34}});
244   auto* lhs = Expr(Source{{12, 34}}, "a");
245   auto* rhs = Expr(3.14f);
246 
247   auto* outer_body =
248       Block(create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
249             Assign(lhs, rhs));
250 
251   WrapInFunction(outer_body);
252 
253   EXPECT_FALSE(r()->Resolve());
254   EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
255 }
256 
TEST_F(ResolverValidationTest,UsingUndefinedVariableOuterScope_Pass)257 TEST_F(ResolverValidationTest, UsingUndefinedVariableOuterScope_Pass) {
258   // {
259   //   var a : f32 = 2.0;
260   //   if (true) { a = 3.14; }
261   // }
262   auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
263 
264   auto* lhs = Expr(Source{{12, 34}}, "a");
265   auto* rhs = Expr(3.14f);
266 
267   auto* cond = Expr(true);
268   auto* body = Block(Assign(lhs, rhs));
269 
270   auto* outer_body =
271       Block(Decl(var),
272             create<ast::IfStatement>(cond, body, ast::ElseStatementList{}));
273 
274   WrapInFunction(outer_body);
275 
276   EXPECT_TRUE(r()->Resolve()) << r()->error();
277 }
278 
TEST_F(ResolverValidationTest,UsingUndefinedVariableDifferentScope_Fail)279 TEST_F(ResolverValidationTest, UsingUndefinedVariableDifferentScope_Fail) {
280   // {
281   //  { var a : f32 = 2.0; }
282   //  { a = 3.14; }
283   // }
284   auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
285   auto* first_body = Block(Decl(var));
286 
287   auto* lhs = Expr(Source{{12, 34}}, "a");
288   auto* rhs = Expr(3.14f);
289   auto* second_body = Block(Assign(lhs, rhs));
290 
291   auto* outer_body = Block(first_body, second_body);
292 
293   WrapInFunction(outer_body);
294 
295   EXPECT_FALSE(r()->Resolve());
296   EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
297 }
298 
TEST_F(ResolverValidationTest,StorageClass_FunctionVariableWorkgroupClass)299 TEST_F(ResolverValidationTest, StorageClass_FunctionVariableWorkgroupClass) {
300   auto* var = Var("var", ty.i32(), ast::StorageClass::kWorkgroup);
301 
302   auto* stmt = Decl(var);
303   Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::DecorationList{});
304 
305   EXPECT_FALSE(r()->Resolve());
306 
307   EXPECT_EQ(r()->error(),
308             "error: function variable has a non-function storage class");
309 }
310 
TEST_F(ResolverValidationTest,StorageClass_FunctionVariableI32)311 TEST_F(ResolverValidationTest, StorageClass_FunctionVariableI32) {
312   auto* var = Var("s", ty.i32(), ast::StorageClass::kPrivate);
313 
314   auto* stmt = Decl(var);
315   Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::DecorationList{});
316 
317   EXPECT_FALSE(r()->Resolve());
318 
319   EXPECT_EQ(r()->error(),
320             "error: function variable has a non-function storage class");
321 }
322 
TEST_F(ResolverValidationTest,StorageClass_SamplerExplicitStorageClass)323 TEST_F(ResolverValidationTest, StorageClass_SamplerExplicitStorageClass) {
324   auto* t = ty.sampler(ast::SamplerKind::kSampler);
325   Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant,
326          ast::DecorationList{
327              create<ast::BindingDecoration>(0),
328              create<ast::GroupDecoration>(0),
329          });
330 
331   EXPECT_FALSE(r()->Resolve());
332 
333   EXPECT_EQ(
334       r()->error(),
335       R"(12:34 error: variables of type 'sampler' must not have a storage class)");
336 }
337 
TEST_F(ResolverValidationTest,StorageClass_TextureExplicitStorageClass)338 TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
339   auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
340   Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant,
341          ast::DecorationList{
342              create<ast::BindingDecoration>(0),
343              create<ast::GroupDecoration>(0),
344          });
345 
346   EXPECT_FALSE(r()->Resolve()) << r()->error();
347 
348   EXPECT_EQ(
349       r()->error(),
350       R"(12:34 error: variables of type 'texture_1d<f32>' must not have a storage class)");
351 }
352 
TEST_F(ResolverValidationTest,Expr_MemberAccessor_VectorSwizzle_BadChar)353 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
354   Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
355 
356   auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "xyqz");
357 
358   auto* mem = MemberAccessor("my_vec", ident);
359   WrapInFunction(mem);
360 
361   EXPECT_FALSE(r()->Resolve());
362   EXPECT_EQ(r()->error(), "3:5 error: invalid vector swizzle character");
363 }
364 
TEST_F(ResolverValidationTest,Expr_MemberAccessor_VectorSwizzle_MixedChars)365 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
366   Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
367 
368   auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "rgyw");
369 
370   auto* mem = MemberAccessor("my_vec", ident);
371   WrapInFunction(mem);
372 
373   EXPECT_FALSE(r()->Resolve());
374   EXPECT_EQ(
375       r()->error(),
376       "3:3 error: invalid mixing of vector swizzle characters rgba with xyzw");
377 }
378 
TEST_F(ResolverValidationTest,Expr_MemberAccessor_VectorSwizzle_BadLength)379 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
380   Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
381 
382   auto* ident = Expr(Source{{{3, 3}, {3, 8}}}, "zzzzz");
383   auto* mem = MemberAccessor("my_vec", ident);
384   WrapInFunction(mem);
385 
386   EXPECT_FALSE(r()->Resolve());
387   EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle size");
388 }
389 
TEST_F(ResolverValidationTest,Expr_MemberAccessor_VectorSwizzle_BadIndex)390 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
391   Global("my_vec", ty.vec2<f32>(), ast::StorageClass::kPrivate);
392 
393   auto* ident = Expr(Source{{3, 3}}, "z");
394   auto* mem = MemberAccessor("my_vec", ident);
395   WrapInFunction(mem);
396 
397   EXPECT_FALSE(r()->Resolve());
398   EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle member");
399 }
400 
TEST_F(ResolverValidationTest,Expr_MemberAccessor_BadParent)401 TEST_F(ResolverValidationTest, Expr_MemberAccessor_BadParent) {
402   // var param: vec4<f32>
403   // let ret: f32 = *(&param).x;
404   auto* param = Var("param", ty.vec4<f32>());
405   auto* x = Expr(Source{{{3, 3}, {3, 8}}}, "x");
406 
407   auto* addressOf_expr = AddressOf(Source{{12, 34}}, param);
408   auto* accessor_expr = MemberAccessor(addressOf_expr, x);
409   auto* star_p = Deref(accessor_expr);
410   auto* ret = Var("r", ty.f32(), star_p);
411   WrapInFunction(Decl(param), Decl(ret));
412 
413   EXPECT_FALSE(r()->Resolve());
414   EXPECT_EQ(r()->error(),
415             "12:34 error: invalid member accessor expression. Expected vector "
416             "or struct, got 'ptr<function, vec4<f32>, read_write>'");
417 }
418 
TEST_F(ResolverValidationTest,EXpr_MemberAccessor_FuncGoodParent)419 TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncGoodParent) {
420   // fn func(p: ptr<function, vec4<f32>>) -> f32 {
421   //     let x: f32 = (*p).z;
422   //     return x;
423   // }
424   auto* p =
425       Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
426   auto* star_p = Deref(p);
427   auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
428   auto* accessor_expr = MemberAccessor(star_p, z);
429   auto* x = Var("x", ty.f32(), accessor_expr);
430   Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
431   EXPECT_TRUE(r()->Resolve()) << r()->error();
432 }
433 
TEST_F(ResolverValidationTest,EXpr_MemberAccessor_FuncBadParent)434 TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncBadParent) {
435   // fn func(p: ptr<function, vec4<f32>>) -> f32 {
436   //     let x: f32 = *p.z;
437   //     return x;
438   // }
439   auto* p =
440       Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
441   auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
442   auto* accessor_expr = MemberAccessor(p, z);
443   auto* star_p = Deref(accessor_expr);
444   auto* x = Var("x", ty.f32(), star_p);
445   Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
446 
447   EXPECT_FALSE(r()->Resolve());
448   EXPECT_EQ(
449       r()->error(),
450       "error: invalid member accessor expression. "
451       "Expected vector or struct, got 'ptr<function, vec4<f32>, read_write>'");
452 }
453 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInLoopBodyBeforeDeclAndAfterDecl_UsageInContinuing)454 TEST_F(ResolverValidationTest,
455        Stmt_Loop_ContinueInLoopBodyBeforeDeclAndAfterDecl_UsageInContinuing) {
456   // loop  {
457   //     continue; // Bypasses z decl
458   //     var z : i32; // unreachable
459   //
460   //     continuing {
461   //         z = 2;
462   //     }
463   // }
464 
465   auto error_loc = Source{{12, 34}};
466   auto* body =
467       Block(Continue(),
468             Decl(error_loc, Var("z", ty.i32(), ast::StorageClass::kNone)));
469   auto* continuing = Block(Assign(Expr("z"), 2));
470   auto* loop_stmt = Loop(body, continuing);
471   WrapInFunction(loop_stmt);
472 
473   EXPECT_FALSE(r()->Resolve());
474   EXPECT_EQ(r()->error(),
475             R"(12:34 warning: code is unreachable
476 error: continue statement bypasses declaration of 'z'
477 note: identifier 'z' declared here
478 note: identifier 'z' referenced in continuing block here)");
479 }
480 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing_InBlocks)481 TEST_F(ResolverValidationTest,
482        Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing_InBlocks) {
483   // loop  {
484   //     var z : i32;
485   //     {{{continue;}}}
486   //     continue; // Ok
487   //
488   //     continuing {
489   //         z = 2;
490   //     }
491   // }
492 
493   auto* body = Block(Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),
494                      Block(Block(Block(Continue()))));
495   auto* continuing = Block(Assign(Expr("z"), 2));
496   auto* loop_stmt = Loop(body, continuing);
497   WrapInFunction(loop_stmt);
498 
499   ASSERT_TRUE(r()->Resolve()) << r()->error();
500 }
501 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuing)502 TEST_F(ResolverValidationTest,
503        Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuing) {
504   // loop  {
505   //     if (true) {
506   //         continue; // Still bypasses z decl (if we reach here)
507   //     }
508   //     var z : i32;
509   //     continuing {
510   //         z = 2;
511   //     }
512   // }
513 
514   auto cont_loc = Source{{12, 34}};
515   auto decl_loc = Source{{56, 78}};
516   auto ref_loc = Source{{90, 12}};
517   auto* body =
518       Block(If(Expr(true), Block(Continue(cont_loc))),
519             Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
520   auto* continuing = Block(Assign(Expr(ref_loc, "z"), 2));
521   auto* loop_stmt = Loop(body, continuing);
522   WrapInFunction(loop_stmt);
523 
524   EXPECT_FALSE(r()->Resolve()) << r()->error();
525   EXPECT_EQ(r()->error(),
526             R"(12:34 error: continue statement bypasses declaration of 'z'
527 56:78 note: identifier 'z' declared here
528 90:12 note: identifier 'z' referenced in continuing block here)");
529 }
530 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingSubscope)531 TEST_F(
532     ResolverValidationTest,
533     Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingSubscope) {
534   // loop  {
535   //     if (true) {
536   //         continue; // Still bypasses z decl (if we reach here)
537   //     }
538   //     var z : i32;
539   //     continuing {
540   //         if (true) {
541   //             z = 2; // Must fail even if z is in a sub-scope
542   //         }
543   //     }
544   // }
545 
546   auto cont_loc = Source{{12, 34}};
547   auto decl_loc = Source{{56, 78}};
548   auto ref_loc = Source{{90, 12}};
549   auto* body =
550       Block(If(Expr(true), Block(Continue(cont_loc))),
551             Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
552 
553   auto* continuing =
554       Block(If(Expr(true), Block(Assign(Expr(ref_loc, "z"), 2))));
555   auto* loop_stmt = Loop(body, continuing);
556   WrapInFunction(loop_stmt);
557 
558   EXPECT_FALSE(r()->Resolve()) << r()->error();
559   EXPECT_EQ(r()->error(),
560             R"(12:34 error: continue statement bypasses declaration of 'z'
561 56:78 note: identifier 'z' declared here
562 90:12 note: identifier 'z' referenced in continuing block here)");
563 }
564 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageOutsideBlock)565 TEST_F(ResolverValidationTest,
566        Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageOutsideBlock) {
567   // loop  {
568   //     if (true) {
569   //         continue; // bypasses z decl (if we reach here)
570   //     }
571   //     var z : i32;
572   //     continuing {
573   //         // Must fail even if z is used in an expression that isn't
574   //         // directly contained inside a block.
575   //         if (z < 2) {
576   //         }
577   //     }
578   // }
579 
580   auto cont_loc = Source{{12, 34}};
581   auto decl_loc = Source{{56, 78}};
582   auto ref_loc = Source{{90, 12}};
583   auto* body =
584       Block(If(Expr(true), Block(Continue(cont_loc))),
585             Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
586   auto* compare = create<ast::BinaryExpression>(ast::BinaryOp::kLessThan,
587                                                 Expr(ref_loc, "z"), Expr(2));
588   auto* continuing = Block(If(compare, Block()));
589   auto* loop_stmt = Loop(body, continuing);
590   WrapInFunction(loop_stmt);
591 
592   EXPECT_FALSE(r()->Resolve()) << r()->error();
593   EXPECT_EQ(r()->error(),
594             R"(12:34 error: continue statement bypasses declaration of 'z'
595 56:78 note: identifier 'z' declared here
596 90:12 note: identifier 'z' referenced in continuing block here)");
597 }
598 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingLoop)599 TEST_F(ResolverValidationTest,
600        Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingLoop) {
601   // loop  {
602   //     if (true) {
603   //         continue; // Still bypasses z decl (if we reach here)
604   //     }
605   //     var z : i32;
606   //     continuing {
607   //         loop {
608   //             z = 2; // Must fail even if z is in a sub-scope
609   //         }
610   //     }
611   // }
612 
613   auto cont_loc = Source{{12, 34}};
614   auto decl_loc = Source{{56, 78}};
615   auto ref_loc = Source{{90, 12}};
616   auto* body =
617       Block(If(Expr(true), Block(Continue(cont_loc))),
618             Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
619 
620   auto* continuing = Block(Loop(Block(Assign(Expr(ref_loc, "z"), 2))));
621   auto* loop_stmt = Loop(body, continuing);
622   WrapInFunction(loop_stmt);
623 
624   EXPECT_FALSE(r()->Resolve()) << r()->error();
625   EXPECT_EQ(r()->error(),
626             R"(12:34 error: continue statement bypasses declaration of 'z'
627 56:78 note: identifier 'z' declared here
628 90:12 note: identifier 'z' referenced in continuing block here)");
629 }
630 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuing)631 TEST_F(ResolverValidationTest,
632        Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuing) {
633   // loop  {
634   //     loop {
635   //         if (true) { continue; } // OK: not part of the outer loop
636   //         break;
637   //     }
638   //     var z : i32;
639   //
640   //     continuing {
641   //         z = 2;
642   //     }
643   // }
644 
645   auto* inner_loop = Loop(Block(    //
646       If(true, Block(Continue())),  //
647       Break()));
648   auto* body =
649       Block(inner_loop, Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
650   auto* continuing = Block(Assign("z", 2));
651   auto* loop_stmt = Loop(body, continuing);
652   WrapInFunction(loop_stmt);
653 
654   EXPECT_TRUE(r()->Resolve()) << r()->error();
655 }
656 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingSubscope)657 TEST_F(ResolverValidationTest,
658        Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingSubscope) {
659   // loop  {
660   //     loop {
661   //         if (true) { continue; } // OK: not part of the outer loop
662   //         break;
663   //     }
664   //     var z : i32;
665   //
666   //     continuing {
667   //         if (true) {
668   //             z = 2;
669   //         }
670   //     }
671   // }
672 
673   auto* inner_loop = Loop(Block(If(true, Block(Continue())),  //
674                                 Break()));
675   auto* body =
676       Block(inner_loop, Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
677   auto* continuing = Block(If(Expr(true), Block(Assign("z", 2))));
678   auto* loop_stmt = Loop(body, continuing);
679   WrapInFunction(loop_stmt);
680 
681   EXPECT_TRUE(r()->Resolve()) << r()->error();
682 }
683 
TEST_F(ResolverValidationTest,Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingLoop)684 TEST_F(ResolverValidationTest,
685        Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingLoop) {
686   // loop  {
687   //     loop {
688   //         if (true) { continue; } // OK: not part of the outer loop
689   //         break;
690   //     }
691   //     var z : i32;
692   //
693   //     continuing {
694   //         loop {
695   //             z = 2;
696   //         }
697   //     }
698   // }
699 
700   auto* inner_loop = Loop(Block(If(true, Block(Continue())),  //
701                                 Break()));
702   auto* body =
703       Block(inner_loop, Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
704   auto* continuing = Block(Loop(Block(Assign("z", 2))));
705   auto* loop_stmt = Loop(body, continuing);
706   WrapInFunction(loop_stmt);
707 
708   EXPECT_TRUE(r()->Resolve()) << r()->error();
709 }
710 
TEST_F(ResolverTest,Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing)711 TEST_F(ResolverTest, Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing) {
712   // loop  {
713   //     var z : i32;
714   //     if (true) { continue; }
715   //
716   //     continuing {
717   //         z = 2;
718   //     }
719   // }
720 
721   auto error_loc = Source{{12, 34}};
722   auto* body = Block(Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),
723                      If(true, Block(Continue())));
724   auto* continuing = Block(Assign(Expr(error_loc, "z"), 2));
725   auto* loop_stmt = Loop(body, continuing);
726   WrapInFunction(loop_stmt);
727 
728   EXPECT_TRUE(r()->Resolve());
729 }
730 
TEST_F(ResolverTest,Stmt_Loop_ReturnInContinuing_Direct)731 TEST_F(ResolverTest, Stmt_Loop_ReturnInContinuing_Direct) {
732   // loop  {
733   //   continuing {
734   //     return;
735   //   }
736   // }
737 
738   WrapInFunction(Loop(  // loop
739       Block(),          //   loop block
740       Block(            //   loop continuing block
741           Return(Source{{12, 34}}))));
742 
743   EXPECT_FALSE(r()->Resolve());
744   EXPECT_EQ(
745       r()->error(),
746       R"(12:34 error: continuing blocks must not contain a return statement)");
747 }
748 
TEST_F(ResolverTest,Stmt_Loop_ReturnInContinuing_Indirect)749 TEST_F(ResolverTest, Stmt_Loop_ReturnInContinuing_Indirect) {
750   // loop {
751   //   continuing {
752   //     loop {
753   //       return;
754   //     }
755   //   }
756   // }
757 
758   WrapInFunction(Loop(         // outer loop
759       Block(),                 //   outer loop block
760       Block(Source{{56, 78}},  //   outer loop continuing block
761             Loop(              //     inner loop
762                 Block(         //       inner loop block
763                     Return(Source{{12, 34}}))))));
764 
765   EXPECT_FALSE(r()->Resolve());
766   EXPECT_EQ(
767       r()->error(),
768       R"(12:34 error: continuing blocks must not contain a return statement
769 56:78 note: see continuing block here)");
770 }
771 
TEST_F(ResolverTest,Stmt_Loop_DiscardInContinuing_Direct)772 TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Direct) {
773   // loop  {
774   //   continuing {
775   //     discard;
776   //   }
777   // }
778 
779   WrapInFunction(Loop(  // loop
780       Block(),          //   loop block
781       Block(            //   loop continuing block
782           Discard(Source{{12, 34}}))));
783 
784   EXPECT_FALSE(r()->Resolve());
785   EXPECT_EQ(
786       r()->error(),
787       R"(12:34 error: continuing blocks must not contain a discard statement)");
788 }
789 
TEST_F(ResolverTest,Stmt_Loop_DiscardInContinuing_Indirect)790 TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Indirect) {
791   // loop {
792   //   continuing {
793   //     loop { discard; }
794   //   }
795   // }
796 
797   WrapInFunction(Loop(         // outer loop
798       Block(),                 //   outer loop block
799       Block(Source{{56, 78}},  //   outer loop continuing block
800             Loop(              //     inner loop
801                 Block(         //       inner loop block
802                     Discard(Source{{12, 34}}))))));
803 
804   EXPECT_FALSE(r()->Resolve());
805   EXPECT_EQ(
806       r()->error(),
807       R"(12:34 error: continuing blocks must not contain a discard statement
808 56:78 note: see continuing block here)");
809 }
810 
TEST_F(ResolverTest,Stmt_Loop_DiscardInContinuing_Indirect_ViaCall)811 TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Indirect_ViaCall) {
812   // fn MayDiscard() { if (true) { discard; } }
813   // fn F() { MayDiscard(); }
814   // loop {
815   //   continuing {
816   //     loop { F(); }
817   //   }
818   // }
819 
820   Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
821   Func("SomeFunc", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
822 
823   WrapInFunction(Loop(         // outer loop
824       Block(),                 //   outer loop block
825       Block(Source{{56, 78}},  //   outer loop continuing block
826             Loop(              //     inner loop
827                 Block(         //       inner loop block
828                     CallStmt(Call(Source{{12, 34}}, "SomeFunc")))))));
829 
830   EXPECT_FALSE(r()->Resolve());
831   EXPECT_EQ(
832       r()->error(),
833       R"(12:34 error: cannot call a function that may discard inside a continuing block
834 56:78 note: see continuing block here)");
835 }
836 
TEST_F(ResolverTest,Stmt_Loop_ContinueInContinuing_Direct)837 TEST_F(ResolverTest, Stmt_Loop_ContinueInContinuing_Direct) {
838   // loop  {
839   //     continuing {
840   //         continue;
841   //     }
842   // }
843 
844   WrapInFunction(Loop(         // loop
845       Block(),                 //   loop block
846       Block(Source{{56, 78}},  //   loop continuing block
847             Continue(Source{{12, 34}}))));
848 
849   EXPECT_FALSE(r()->Resolve());
850   EXPECT_EQ(
851       r()->error(),
852       "12:34 error: continuing blocks must not contain a continue statement");
853 }
854 
TEST_F(ResolverTest,Stmt_Loop_ContinueInContinuing_Indirect)855 TEST_F(ResolverTest, Stmt_Loop_ContinueInContinuing_Indirect) {
856   // loop {
857   //   continuing {
858   //     loop {
859   //       continue;
860   //     }
861   //   }
862   // }
863 
864   WrapInFunction(Loop(  // outer loop
865       Block(),          //   outer loop block
866       Block(            //   outer loop continuing block
867           Loop(         //     inner loop
868               Block(    //       inner loop block
869                   Continue(Source{{12, 34}}))))));
870 
871   EXPECT_TRUE(r()->Resolve()) << r()->error();
872 }
873 
TEST_F(ResolverTest,Stmt_ForLoop_ReturnInContinuing_Direct)874 TEST_F(ResolverTest, Stmt_ForLoop_ReturnInContinuing_Direct) {
875   // for(;; return) {
876   //   break;
877   // }
878 
879   WrapInFunction(For(nullptr, nullptr, Return(Source{{12, 34}}),  //
880                      Block(Break())));
881 
882   EXPECT_FALSE(r()->Resolve());
883   EXPECT_EQ(
884       r()->error(),
885       R"(12:34 error: continuing blocks must not contain a return statement)");
886 }
887 
TEST_F(ResolverTest,Stmt_ForLoop_ReturnInContinuing_Indirect)888 TEST_F(ResolverTest, Stmt_ForLoop_ReturnInContinuing_Indirect) {
889   // for(;; loop { return }) {
890   //   break;
891   // }
892 
893   WrapInFunction(For(nullptr, nullptr,
894                      Loop(Source{{56, 78}},                  //
895                           Block(Return(Source{{12, 34}}))),  //
896                      Block(Break())));
897 
898   EXPECT_FALSE(r()->Resolve());
899   EXPECT_EQ(
900       r()->error(),
901       R"(12:34 error: continuing blocks must not contain a return statement
902 56:78 note: see continuing block here)");
903 }
904 
TEST_F(ResolverTest,Stmt_ForLoop_DiscardInContinuing_Direct)905 TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Direct) {
906   // for(;; discard) {
907   //   break;
908   // }
909 
910   WrapInFunction(For(nullptr, nullptr, Discard(Source{{12, 34}}),  //
911                      Block(Break())));
912 
913   EXPECT_FALSE(r()->Resolve());
914   EXPECT_EQ(
915       r()->error(),
916       R"(12:34 error: continuing blocks must not contain a discard statement)");
917 }
918 
TEST_F(ResolverTest,Stmt_ForLoop_DiscardInContinuing_Indirect)919 TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Indirect) {
920   // for(;; loop { discard }) {
921   //   break;
922   // }
923 
924   WrapInFunction(For(nullptr, nullptr,
925                      Loop(Source{{56, 78}},                   //
926                           Block(Discard(Source{{12, 34}}))),  //
927                      Block(Break())));
928 
929   EXPECT_FALSE(r()->Resolve());
930   EXPECT_EQ(
931       r()->error(),
932       R"(12:34 error: continuing blocks must not contain a discard statement
933 56:78 note: see continuing block here)");
934 }
935 
TEST_F(ResolverTest,Stmt_ForLoop_DiscardInContinuing_Indirect_ViaCall)936 TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Indirect_ViaCall) {
937   // fn MayDiscard() { if (true) { discard; } }
938   // fn F() { MayDiscard(); }
939   // for(;; loop { F() }) {
940   //   break;
941   // }
942 
943   Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
944   Func("F", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
945 
946   WrapInFunction(For(nullptr, nullptr,
947                      Loop(Source{{56, 78}},                               //
948                           Block(CallStmt(Call(Source{{12, 34}}, "F")))),  //
949                      Block(Break())));
950 
951   EXPECT_FALSE(r()->Resolve());
952   EXPECT_EQ(
953       r()->error(),
954       R"(12:34 error: cannot call a function that may discard inside a continuing block
955 56:78 note: see continuing block here)");
956 }
957 
TEST_F(ResolverTest,Stmt_ForLoop_ContinueInContinuing_Direct)958 TEST_F(ResolverTest, Stmt_ForLoop_ContinueInContinuing_Direct) {
959   // for(;; continue) {
960   //   break;
961   // }
962 
963   WrapInFunction(For(nullptr, nullptr, Continue(Source{{12, 34}}),  //
964                      Block(Break())));
965 
966   EXPECT_FALSE(r()->Resolve());
967   EXPECT_EQ(
968       r()->error(),
969       "12:34 error: continuing blocks must not contain a continue statement");
970 }
971 
TEST_F(ResolverTest,Stmt_ForLoop_ContinueInContinuing_Indirect)972 TEST_F(ResolverTest, Stmt_ForLoop_ContinueInContinuing_Indirect) {
973   // for(;; loop { continue }) {
974   //   break;
975   // }
976 
977   WrapInFunction(For(nullptr, nullptr,
978                      Loop(                                    //
979                          Block(Continue(Source{{12, 34}}))),  //
980                      Block(Break())));
981 
982   EXPECT_TRUE(r()->Resolve()) << r()->error();
983 }
984 
TEST_F(ResolverTest,Stmt_ForLoop_CondIsBoolRef)985 TEST_F(ResolverTest, Stmt_ForLoop_CondIsBoolRef) {
986   // var cond : bool = true;
987   // for (; cond; ) {
988   // }
989 
990   auto* cond = Var("cond", ty.bool_(), Expr(true));
991   WrapInFunction(Decl(cond), For(nullptr, "cond", nullptr, Block()));
992   EXPECT_TRUE(r()->Resolve()) << r()->error();
993 }
994 
TEST_F(ResolverTest,Stmt_ForLoop_CondIsNotBool)995 TEST_F(ResolverTest, Stmt_ForLoop_CondIsNotBool) {
996   // for (; 1.0f; ) {
997   // }
998 
999   WrapInFunction(For(nullptr, Expr(Source{{12, 34}}, 1.0f), nullptr, Block()));
1000 
1001   EXPECT_FALSE(r()->Resolve());
1002   EXPECT_EQ(r()->error(),
1003             "12:34 error: for-loop condition must be bool, got f32");
1004 }
1005 
TEST_F(ResolverValidationTest,Stmt_ContinueInLoop)1006 TEST_F(ResolverValidationTest, Stmt_ContinueInLoop) {
1007   WrapInFunction(Loop(Block(Continue(Source{{12, 34}}))));
1008   EXPECT_TRUE(r()->Resolve()) << r()->error();
1009 }
1010 
TEST_F(ResolverValidationTest,Stmt_ContinueNotInLoop)1011 TEST_F(ResolverValidationTest, Stmt_ContinueNotInLoop) {
1012   WrapInFunction(Continue(Source{{12, 34}}));
1013   EXPECT_FALSE(r()->Resolve());
1014   EXPECT_EQ(r()->error(), "12:34 error: continue statement must be in a loop");
1015 }
1016 
TEST_F(ResolverValidationTest,Stmt_BreakInLoop)1017 TEST_F(ResolverValidationTest, Stmt_BreakInLoop) {
1018   WrapInFunction(Loop(Block(create<ast::BreakStatement>(Source{{12, 34}}))));
1019   EXPECT_TRUE(r()->Resolve()) << r()->error();
1020 }
1021 
TEST_F(ResolverValidationTest,Stmt_BreakInSwitch)1022 TEST_F(ResolverValidationTest, Stmt_BreakInSwitch) {
1023   WrapInFunction(Loop(Block(Switch(
1024       Expr(1),
1025       Case(Expr(1), Block(create<ast::BreakStatement>(Source{{12, 34}}))),
1026       DefaultCase()))));
1027   EXPECT_TRUE(r()->Resolve()) << r()->error();
1028 }
1029 
TEST_F(ResolverValidationTest,Stmt_BreakNotInLoopOrSwitch)1030 TEST_F(ResolverValidationTest, Stmt_BreakNotInLoopOrSwitch) {
1031   WrapInFunction(create<ast::BreakStatement>(Source{{12, 34}}));
1032   EXPECT_FALSE(r()->Resolve());
1033   EXPECT_EQ(r()->error(),
1034             "12:34 error: break statement must be in a loop or switch case");
1035 }
1036 
TEST_F(ResolverValidationTest,StructMemberDuplicateName)1037 TEST_F(ResolverValidationTest, StructMemberDuplicateName) {
1038   Structure("S", {Member(Source{{12, 34}}, "a", ty.i32()),
1039                   Member(Source{{56, 78}}, "a", ty.i32())});
1040   EXPECT_FALSE(r()->Resolve());
1041   EXPECT_EQ(r()->error(),
1042             "56:78 error: redefinition of 'a'\n12:34 note: previous definition "
1043             "is here");
1044 }
TEST_F(ResolverValidationTest,StructMemberDuplicateNameDifferentTypes)1045 TEST_F(ResolverValidationTest, StructMemberDuplicateNameDifferentTypes) {
1046   Structure("S", {Member(Source{{12, 34}}, "a", ty.bool_()),
1047                   Member(Source{{12, 34}}, "a", ty.vec3<f32>())});
1048   EXPECT_FALSE(r()->Resolve());
1049   EXPECT_EQ(r()->error(),
1050             "12:34 error: redefinition of 'a'\n12:34 note: previous definition "
1051             "is here");
1052 }
TEST_F(ResolverValidationTest,StructMemberDuplicateNamePass)1053 TEST_F(ResolverValidationTest, StructMemberDuplicateNamePass) {
1054   Structure("S", {Member("a", ty.i32()), Member("b", ty.f32())});
1055   Structure("S1", {Member("a", ty.i32()), Member("b", ty.f32())});
1056   EXPECT_TRUE(r()->Resolve());
1057 }
1058 
TEST_F(ResolverValidationTest,NonPOTStructMemberAlignDecoration)1059 TEST_F(ResolverValidationTest, NonPOTStructMemberAlignDecoration) {
1060   Structure("S", {
1061                      Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 3)}),
1062                  });
1063 
1064   EXPECT_FALSE(r()->Resolve());
1065   EXPECT_EQ(
1066       r()->error(),
1067       "12:34 error: align value must be a positive, power-of-two integer");
1068 }
1069 
TEST_F(ResolverValidationTest,ZeroStructMemberAlignDecoration)1070 TEST_F(ResolverValidationTest, ZeroStructMemberAlignDecoration) {
1071   Structure("S", {
1072                      Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 0)}),
1073                  });
1074 
1075   EXPECT_FALSE(r()->Resolve());
1076   EXPECT_EQ(
1077       r()->error(),
1078       "12:34 error: align value must be a positive, power-of-two integer");
1079 }
1080 
TEST_F(ResolverValidationTest,ZeroStructMemberSizeDecoration)1081 TEST_F(ResolverValidationTest, ZeroStructMemberSizeDecoration) {
1082   Structure("S", {
1083                      Member("a", ty.f32(), {MemberSize(Source{{12, 34}}, 0)}),
1084                  });
1085 
1086   EXPECT_FALSE(r()->Resolve());
1087   EXPECT_EQ(r()->error(),
1088             "12:34 error: size must be at least as big as the type's size (4)");
1089 }
1090 
TEST_F(ResolverValidationTest,OffsetAndSizeDecoration)1091 TEST_F(ResolverValidationTest, OffsetAndSizeDecoration) {
1092   Structure("S", {
1093                      Member(Source{{12, 34}}, "a", ty.f32(),
1094                             {MemberOffset(0), MemberSize(4)}),
1095                  });
1096 
1097   EXPECT_FALSE(r()->Resolve());
1098   EXPECT_EQ(r()->error(),
1099             "12:34 error: offset decorations cannot be used with align or size "
1100             "decorations");
1101 }
1102 
TEST_F(ResolverValidationTest,OffsetAndAlignDecoration)1103 TEST_F(ResolverValidationTest, OffsetAndAlignDecoration) {
1104   Structure("S", {
1105                      Member(Source{{12, 34}}, "a", ty.f32(),
1106                             {MemberOffset(0), MemberAlign(4)}),
1107                  });
1108 
1109   EXPECT_FALSE(r()->Resolve());
1110   EXPECT_EQ(r()->error(),
1111             "12:34 error: offset decorations cannot be used with align or size "
1112             "decorations");
1113 }
1114 
TEST_F(ResolverValidationTest,OffsetAndAlignAndSizeDecoration)1115 TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeDecoration) {
1116   Structure("S", {
1117                      Member(Source{{12, 34}}, "a", ty.f32(),
1118                             {MemberOffset(0), MemberAlign(4), MemberSize(4)}),
1119                  });
1120 
1121   EXPECT_FALSE(r()->Resolve());
1122   EXPECT_EQ(r()->error(),
1123             "12:34 error: offset decorations cannot be used with align or size "
1124             "decorations");
1125 }
1126 
TEST_F(ResolverTest,Expr_Constructor_Cast_Pointer)1127 TEST_F(ResolverTest, Expr_Constructor_Cast_Pointer) {
1128   auto* vf = Var("vf", ty.f32());
1129   auto* c =
1130       Construct(Source{{12, 34}}, ty.pointer<i32>(ast::StorageClass::kFunction),
1131                 ExprList(vf));
1132   auto* ip = Const("ip", ty.pointer<i32>(ast::StorageClass::kFunction), c);
1133   WrapInFunction(Decl(vf), Decl(ip));
1134 
1135   EXPECT_FALSE(r()->Resolve());
1136   EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
1137 }
1138 
1139 }  // namespace
1140 }  // namespace resolver
1141 }  // namespace tint
1142 
1143 TINT_INSTANTIATE_TYPEINFO(tint::resolver::FakeStmt);
1144 TINT_INSTANTIATE_TYPEINFO(tint::resolver::FakeExpr);
1145