• 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/struct_block_decoration.h"
16 #include "src/resolver/resolver.h"
17 #include "src/resolver/resolver_test_helper.h"
18 #include "src/sem/reference_type.h"
19 
20 #include "gmock/gmock.h"
21 
22 namespace tint {
23 namespace resolver {
24 namespace {
25 
26 struct ResolverVarLetTest : public resolver::TestHelper,
27                             public testing::Test {};
28 
TEST_F(ResolverVarLetTest,VarDeclWithoutConstructor)29 TEST_F(ResolverVarLetTest, VarDeclWithoutConstructor) {
30   // struct S { i : i32; }
31   // alias A = S;
32   // fn F(){
33   //   var i : i32;
34   //   var u : u32;
35   //   var f : f32;
36   //   var b : bool;
37   //   var s : S;
38   //   var a : A;
39   // }
40 
41   auto* S = Structure("S", {Member("i", ty.i32())});
42   auto* A = Alias("A", ty.Of(S));
43 
44   auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
45   auto* u = Var("u", ty.u32(), ast::StorageClass::kNone);
46   auto* f = Var("f", ty.f32(), ast::StorageClass::kNone);
47   auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone);
48   auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone);
49   auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone);
50 
51   Func("F", {}, ty.void_(),
52        {
53            Decl(i),
54            Decl(u),
55            Decl(f),
56            Decl(b),
57            Decl(s),
58            Decl(a),
59        });
60 
61   ASSERT_TRUE(r()->Resolve()) << r()->error();
62 
63   // `var` declarations are always of reference type
64   ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
65   ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
66   ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
67   ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
68   ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
69   ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
70 
71   EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
72   EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
73   EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
74   EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
75   EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
76   EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
77 
78   EXPECT_EQ(Sem().Get(i)->Constructor(), nullptr);
79   EXPECT_EQ(Sem().Get(u)->Constructor(), nullptr);
80   EXPECT_EQ(Sem().Get(f)->Constructor(), nullptr);
81   EXPECT_EQ(Sem().Get(b)->Constructor(), nullptr);
82   EXPECT_EQ(Sem().Get(s)->Constructor(), nullptr);
83   EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr);
84 }
85 
TEST_F(ResolverVarLetTest,VarDeclWithConstructor)86 TEST_F(ResolverVarLetTest, VarDeclWithConstructor) {
87   // struct S { i : i32; }
88   // alias A = S;
89   // fn F(){
90   //   var i : i32 = 1;
91   //   var u : u32 = 1u;
92   //   var f : f32 = 1.f;
93   //   var b : bool = true;
94   //   var s : S = S(1);
95   //   var a : A = A(1);
96   // }
97 
98   auto* S = Structure("S", {Member("i", ty.i32())});
99   auto* A = Alias("A", ty.Of(S));
100 
101   auto* i_c = Expr(1);
102   auto* u_c = Expr(1u);
103   auto* f_c = Expr(1.f);
104   auto* b_c = Expr(true);
105   auto* s_c = Construct(ty.Of(S), Expr(1));
106   auto* a_c = Construct(ty.Of(A), Expr(1));
107 
108   auto* i = Var("i", ty.i32(), ast::StorageClass::kNone, i_c);
109   auto* u = Var("u", ty.u32(), ast::StorageClass::kNone, u_c);
110   auto* f = Var("f", ty.f32(), ast::StorageClass::kNone, f_c);
111   auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone, b_c);
112   auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone, s_c);
113   auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone, a_c);
114 
115   Func("F", {}, ty.void_(),
116        {
117            Decl(i),
118            Decl(u),
119            Decl(f),
120            Decl(b),
121            Decl(s),
122            Decl(a),
123        });
124 
125   ASSERT_TRUE(r()->Resolve()) << r()->error();
126 
127   // `var` declarations are always of reference type
128   ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
129   ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
130   ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
131   ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
132   ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
133   ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
134 
135   EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
136   EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
137   EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
138   EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
139   EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
140   EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
141 
142   EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
143   EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
144   EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
145   EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
146   EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
147   EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
148 }
149 
TEST_F(ResolverVarLetTest,LetDecl)150 TEST_F(ResolverVarLetTest, LetDecl) {
151   // struct S { i : i32; }
152   // fn F(){
153   //   var v : i32;
154   //   let i : i32 = 1;
155   //   let u : u32 = 1u;
156   //   let f : f32 = 1.;
157   //   let b : bool = true;
158   //   let s : S = S(1);
159   //   let a : A = A(1);
160   //   let p : pointer<function, i32> = &v;
161   // }
162 
163   auto* S = Structure("S", {Member("i", ty.i32())});
164   auto* A = Alias("A", ty.Of(S));
165   auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
166 
167   auto* i_c = Expr(1);
168   auto* u_c = Expr(1u);
169   auto* f_c = Expr(1.f);
170   auto* b_c = Expr(true);
171   auto* s_c = Construct(ty.Of(S), Expr(1));
172   auto* a_c = Construct(ty.Of(A), Expr(1));
173   auto* p_c = AddressOf(v);
174 
175   auto* i = Const("i", ty.i32(), i_c);
176   auto* u = Const("u", ty.u32(), u_c);
177   auto* f = Const("f", ty.f32(), f_c);
178   auto* b = Const("b", ty.bool_(), b_c);
179   auto* s = Const("s", ty.Of(S), s_c);
180   auto* a = Const("a", ty.Of(A), a_c);
181   auto* p = Const("p", ty.pointer<i32>(ast::StorageClass::kFunction), p_c);
182 
183   Func("F", {}, ty.void_(),
184        {
185            Decl(v),
186            Decl(i),
187            Decl(u),
188            Decl(f),
189            Decl(b),
190            Decl(s),
191            Decl(a),
192            Decl(p),
193        });
194 
195   ASSERT_TRUE(r()->Resolve()) << r()->error();
196 
197   // `let` declarations are always of the storage type
198   ASSERT_TRUE(TypeOf(i)->Is<sem::I32>());
199   ASSERT_TRUE(TypeOf(u)->Is<sem::U32>());
200   ASSERT_TRUE(TypeOf(f)->Is<sem::F32>());
201   ASSERT_TRUE(TypeOf(b)->Is<sem::Bool>());
202   ASSERT_TRUE(TypeOf(s)->Is<sem::Struct>());
203   ASSERT_TRUE(TypeOf(a)->Is<sem::Struct>());
204   ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
205   ASSERT_TRUE(TypeOf(p)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
206 
207   EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
208   EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
209   EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
210   EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
211   EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
212   EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
213   EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c);
214 }
215 
TEST_F(ResolverVarLetTest,DefaultVarStorageClass)216 TEST_F(ResolverVarLetTest, DefaultVarStorageClass) {
217   // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
218 
219   auto* buf = Structure("S", {Member("m", ty.i32())},
220                         {create<ast::StructBlockDecoration>()});
221   auto* function = Var("f", ty.i32());
222   auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
223   auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
224   auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
225                          ast::DecorationList{
226                              create<ast::BindingDecoration>(0),
227                              create<ast::GroupDecoration>(0),
228                          });
229   auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
230                          ast::DecorationList{
231                              create<ast::BindingDecoration>(1),
232                              create<ast::GroupDecoration>(0),
233                          });
234   auto* handle = Global("h", ty.depth_texture(ast::TextureDimension::k2d),
235                         ast::DecorationList{
236                             create<ast::BindingDecoration>(2),
237                             create<ast::GroupDecoration>(0),
238                         });
239 
240   WrapInFunction(function);
241 
242   ASSERT_TRUE(r()->Resolve()) << r()->error();
243 
244   ASSERT_TRUE(TypeOf(function)->Is<sem::Reference>());
245   ASSERT_TRUE(TypeOf(private_)->Is<sem::Reference>());
246   ASSERT_TRUE(TypeOf(workgroup)->Is<sem::Reference>());
247   ASSERT_TRUE(TypeOf(uniform)->Is<sem::Reference>());
248   ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
249   ASSERT_TRUE(TypeOf(handle)->Is<sem::Reference>());
250 
251   EXPECT_EQ(TypeOf(function)->As<sem::Reference>()->Access(),
252             ast::Access::kReadWrite);
253   EXPECT_EQ(TypeOf(private_)->As<sem::Reference>()->Access(),
254             ast::Access::kReadWrite);
255   EXPECT_EQ(TypeOf(workgroup)->As<sem::Reference>()->Access(),
256             ast::Access::kReadWrite);
257   EXPECT_EQ(TypeOf(uniform)->As<sem::Reference>()->Access(),
258             ast::Access::kRead);
259   EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(),
260             ast::Access::kRead);
261   EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
262 }
263 
TEST_F(ResolverVarLetTest,ExplicitVarStorageClass)264 TEST_F(ResolverVarLetTest, ExplicitVarStorageClass) {
265   // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
266 
267   auto* buf = Structure("S", {Member("m", ty.i32())},
268                         {create<ast::StructBlockDecoration>()});
269   auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
270                          ast::Access::kReadWrite,
271                          ast::DecorationList{
272                              create<ast::BindingDecoration>(1),
273                              create<ast::GroupDecoration>(0),
274                          });
275 
276   ASSERT_TRUE(r()->Resolve()) << r()->error();
277 
278   ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
279 
280   EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(),
281             ast::Access::kReadWrite);
282 }
283 
TEST_F(ResolverVarLetTest,LetInheritsAccessFromOriginatingVariable)284 TEST_F(ResolverVarLetTest, LetInheritsAccessFromOriginatingVariable) {
285   // struct Inner {
286   //    arr: array<i32, 4>;
287   // }
288   // [[block]] struct S {
289   //    inner: Inner;
290   // }
291   // [[group(0), binding(0)]] var<storage, read_write> s : S;
292   // fn f() {
293   //   let p = &s.inner.arr[2];
294   // }
295   auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
296   auto* buf = Structure("S", {Member("inner", ty.Of(inner))},
297                         {create<ast::StructBlockDecoration>()});
298   auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage,
299                          ast::Access::kReadWrite,
300                          ast::DecorationList{
301                              create<ast::BindingDecoration>(0),
302                              create<ast::GroupDecoration>(0),
303                          });
304 
305   auto* expr =
306       IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 4);
307   auto* ptr = Const("p", nullptr, AddressOf(expr));
308 
309   WrapInFunction(ptr);
310 
311   ASSERT_TRUE(r()->Resolve()) << r()->error();
312 
313   ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
314   ASSERT_TRUE(TypeOf(ptr)->Is<sem::Pointer>());
315 
316   EXPECT_EQ(TypeOf(expr)->As<sem::Reference>()->Access(),
317             ast::Access::kReadWrite);
318   EXPECT_EQ(TypeOf(ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
319 }
320 
TEST_F(ResolverVarLetTest,LocalShadowsAlias)321 TEST_F(ResolverVarLetTest, LocalShadowsAlias) {
322   // type a = i32;
323   //
324   // fn X() {
325   //   var a = false;
326   // }
327   //
328   // fn Y() {
329   //   let a = true;
330   // }
331 
332   auto* t = Alias("a", ty.i32());
333   auto* v = Var("a", nullptr, Expr(false));
334   auto* l = Const("a", nullptr, Expr(false));
335   Func("X", {}, ty.void_(), {Decl(v)});
336   Func("Y", {}, ty.void_(), {Decl(l)});
337 
338   ASSERT_TRUE(r()->Resolve()) << r()->error();
339 
340   auto* type_t = Sem().Get(t);
341   auto* local_v = Sem().Get<sem::LocalVariable>(v);
342   auto* local_l = Sem().Get<sem::LocalVariable>(l);
343 
344   ASSERT_NE(local_v, nullptr);
345   ASSERT_NE(local_l, nullptr);
346 
347   EXPECT_EQ(local_v->Shadows(), type_t);
348   EXPECT_EQ(local_l->Shadows(), type_t);
349 }
350 
TEST_F(ResolverVarLetTest,LocalShadowsStruct)351 TEST_F(ResolverVarLetTest, LocalShadowsStruct) {
352   // struct a {
353   //   m : i32;
354   // };
355   //
356   // fn X() {
357   //   var a = true;
358   // }
359   //
360   // fn Y() {
361   //   let a = false;
362   // }
363 
364   auto* t = Structure("a", {Member("m", ty.i32())});
365   auto* v = Var("a", nullptr, Expr(false));
366   auto* l = Const("a", nullptr, Expr(false));
367   Func("X", {}, ty.void_(), {Decl(v)});
368   Func("Y", {}, ty.void_(), {Decl(l)});
369 
370   ASSERT_TRUE(r()->Resolve()) << r()->error();
371 
372   auto* type_t = Sem().Get(t);
373   auto* local_v = Sem().Get<sem::LocalVariable>(v);
374   auto* local_l = Sem().Get<sem::LocalVariable>(l);
375 
376   ASSERT_NE(local_v, nullptr);
377   ASSERT_NE(local_l, nullptr);
378 
379   EXPECT_EQ(local_v->Shadows(), type_t);
380   EXPECT_EQ(local_l->Shadows(), type_t);
381 }
382 
TEST_F(ResolverVarLetTest,LocalShadowsFunction)383 TEST_F(ResolverVarLetTest, LocalShadowsFunction) {
384   // fn a() {
385   //   var a = true;
386   // }
387   //
388   // fn b() {
389   //   let b = false;
390   // }
391 
392   auto* v = Var("a", nullptr, Expr(false));
393   auto* l = Const("b", nullptr, Expr(false));
394   auto* fa = Func("a", {}, ty.void_(), {Decl(v)});
395   auto* fb = Func("b", {}, ty.void_(), {Decl(l)});
396 
397   ASSERT_TRUE(r()->Resolve()) << r()->error();
398 
399   auto* local_v = Sem().Get<sem::LocalVariable>(v);
400   auto* local_l = Sem().Get<sem::LocalVariable>(l);
401   auto* func_a = Sem().Get(fa);
402   auto* func_b = Sem().Get(fb);
403 
404   ASSERT_NE(local_v, nullptr);
405   ASSERT_NE(local_l, nullptr);
406   ASSERT_NE(func_a, nullptr);
407   ASSERT_NE(func_b, nullptr);
408 
409   EXPECT_EQ(local_v->Shadows(), func_a);
410   EXPECT_EQ(local_l->Shadows(), func_b);
411 }
412 
TEST_F(ResolverVarLetTest,LocalShadowsGlobalVar)413 TEST_F(ResolverVarLetTest, LocalShadowsGlobalVar) {
414   // var<private> a : i32;
415   //
416   // fn X() {
417   //   var a = a;
418   // }
419   //
420   // fn Y() {
421   //   let a = a;
422   // }
423 
424   auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
425   auto* v = Var("a", nullptr, Expr("a"));
426   auto* l = Const("a", nullptr, Expr("a"));
427   Func("X", {}, ty.void_(), {Decl(v)});
428   Func("Y", {}, ty.void_(), {Decl(l)});
429 
430   ASSERT_TRUE(r()->Resolve()) << r()->error();
431 
432   auto* global = Sem().Get(g);
433   auto* local_v = Sem().Get<sem::LocalVariable>(v);
434   auto* local_l = Sem().Get<sem::LocalVariable>(l);
435 
436   ASSERT_NE(local_v, nullptr);
437   ASSERT_NE(local_l, nullptr);
438 
439   EXPECT_EQ(local_v->Shadows(), global);
440   EXPECT_EQ(local_l->Shadows(), global);
441 
442   auto* user_v =
443       Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
444   auto* user_l =
445       Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
446 
447   ASSERT_NE(user_v, nullptr);
448   ASSERT_NE(user_l, nullptr);
449 
450   EXPECT_EQ(user_v->Variable(), global);
451   EXPECT_EQ(user_l->Variable(), global);
452 }
453 
TEST_F(ResolverVarLetTest,LocalShadowsGlobalLet)454 TEST_F(ResolverVarLetTest, LocalShadowsGlobalLet) {
455   // let a : i32 = 1;
456   //
457   // fn X() {
458   //   var a = (a == 123);
459   // }
460   //
461   // fn Y() {
462   //   let a = (a == 321);
463   // }
464 
465   auto* g = GlobalConst("a", ty.i32(), Expr(1));
466   auto* v = Var("a", nullptr, Expr("a"));
467   auto* l = Const("a", nullptr, Expr("a"));
468   Func("X", {}, ty.void_(), {Decl(v)});
469   Func("Y", {}, ty.void_(), {Decl(l)});
470 
471   ASSERT_TRUE(r()->Resolve()) << r()->error();
472 
473   auto* global = Sem().Get(g);
474   auto* local_v = Sem().Get<sem::LocalVariable>(v);
475   auto* local_l = Sem().Get<sem::LocalVariable>(l);
476 
477   ASSERT_NE(local_v, nullptr);
478   ASSERT_NE(local_l, nullptr);
479 
480   EXPECT_EQ(local_v->Shadows(), global);
481   EXPECT_EQ(local_l->Shadows(), global);
482 
483   auto* user_v =
484       Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
485   auto* user_l =
486       Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
487 
488   ASSERT_NE(user_v, nullptr);
489   ASSERT_NE(user_l, nullptr);
490 
491   EXPECT_EQ(user_v->Variable(), global);
492   EXPECT_EQ(user_l->Variable(), global);
493 }
494 
TEST_F(ResolverVarLetTest,LocalShadowsLocalVar)495 TEST_F(ResolverVarLetTest, LocalShadowsLocalVar) {
496   // fn X() {
497   //   var a : i32;
498   //   {
499   //     var a = a;
500   //   }
501   //   {
502   //     let a = a;
503   //   }
504   // }
505 
506   auto* s = Var("a", ty.i32(), Expr(1));
507   auto* v = Var("a", nullptr, Expr("a"));
508   auto* l = Const("a", nullptr, Expr("a"));
509   Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
510 
511   ASSERT_TRUE(r()->Resolve()) << r()->error();
512 
513   auto* local_s = Sem().Get<sem::LocalVariable>(s);
514   auto* local_v = Sem().Get<sem::LocalVariable>(v);
515   auto* local_l = Sem().Get<sem::LocalVariable>(l);
516 
517   ASSERT_NE(local_s, nullptr);
518   ASSERT_NE(local_v, nullptr);
519   ASSERT_NE(local_l, nullptr);
520 
521   EXPECT_EQ(local_v->Shadows(), local_s);
522   EXPECT_EQ(local_l->Shadows(), local_s);
523 
524   auto* user_v =
525       Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
526   auto* user_l =
527       Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
528 
529   ASSERT_NE(user_v, nullptr);
530   ASSERT_NE(user_l, nullptr);
531 
532   EXPECT_EQ(user_v->Variable(), local_s);
533   EXPECT_EQ(user_l->Variable(), local_s);
534 }
535 
TEST_F(ResolverVarLetTest,LocalShadowsLocalLet)536 TEST_F(ResolverVarLetTest, LocalShadowsLocalLet) {
537   // fn X() {
538   //   let a = 1;
539   //   {
540   //     var a = (a == 123);
541   //   }
542   //   {
543   //     let a = (a == 321);
544   //   }
545   // }
546 
547   auto* s = Const("a", ty.i32(), Expr(1));
548   auto* v = Var("a", nullptr, Expr("a"));
549   auto* l = Const("a", nullptr, Expr("a"));
550   Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
551 
552   ASSERT_TRUE(r()->Resolve()) << r()->error();
553 
554   auto* local_s = Sem().Get<sem::LocalVariable>(s);
555   auto* local_v = Sem().Get<sem::LocalVariable>(v);
556   auto* local_l = Sem().Get<sem::LocalVariable>(l);
557 
558   ASSERT_NE(local_s, nullptr);
559   ASSERT_NE(local_v, nullptr);
560   ASSERT_NE(local_l, nullptr);
561 
562   EXPECT_EQ(local_v->Shadows(), local_s);
563   EXPECT_EQ(local_l->Shadows(), local_s);
564 
565   auto* user_v =
566       Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
567   auto* user_l =
568       Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
569 
570   ASSERT_NE(user_v, nullptr);
571   ASSERT_NE(user_l, nullptr);
572 
573   EXPECT_EQ(user_v->Variable(), local_s);
574   EXPECT_EQ(user_l->Variable(), local_s);
575 }
576 
TEST_F(ResolverVarLetTest,LocalShadowsParam)577 TEST_F(ResolverVarLetTest, LocalShadowsParam) {
578   // fn F(a : i32) {
579   //   {
580   //     var a = a;
581   //   }
582   //   {
583   //     let a = a;
584   //   }
585   // }
586 
587   auto* p = Param("a", ty.i32());
588   auto* v = Var("a", nullptr, Expr("a"));
589   auto* l = Const("a", nullptr, Expr("a"));
590   Func("X", {p}, ty.void_(), {Block(Decl(v)), Block(Decl(l))});
591 
592   ASSERT_TRUE(r()->Resolve()) << r()->error();
593 
594   auto* param = Sem().Get<sem::Parameter>(p);
595   auto* local_v = Sem().Get<sem::LocalVariable>(v);
596   auto* local_l = Sem().Get<sem::LocalVariable>(l);
597 
598   ASSERT_NE(param, nullptr);
599   ASSERT_NE(local_v, nullptr);
600   ASSERT_NE(local_l, nullptr);
601 
602   EXPECT_EQ(local_v->Shadows(), param);
603   EXPECT_EQ(local_l->Shadows(), param);
604 
605   auto* user_v =
606       Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
607   auto* user_l =
608       Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
609 
610   ASSERT_NE(user_v, nullptr);
611   ASSERT_NE(user_l, nullptr);
612 
613   EXPECT_EQ(user_v->Variable(), param);
614   EXPECT_EQ(user_l->Variable(), param);
615 }
616 
TEST_F(ResolverVarLetTest,ParamShadowsFunction)617 TEST_F(ResolverVarLetTest, ParamShadowsFunction) {
618   // fn a(a : bool) {
619   // }
620 
621   auto* p = Param("a", ty.bool_());
622   auto* f = Func("a", {p}, ty.void_(), {});
623 
624   ASSERT_TRUE(r()->Resolve()) << r()->error();
625 
626   auto* func = Sem().Get(f);
627   auto* param = Sem().Get<sem::Parameter>(p);
628 
629   ASSERT_NE(func, nullptr);
630   ASSERT_NE(param, nullptr);
631 
632   EXPECT_EQ(param->Shadows(), func);
633 }
634 
TEST_F(ResolverVarLetTest,ParamShadowsGlobalVar)635 TEST_F(ResolverVarLetTest, ParamShadowsGlobalVar) {
636   // var<private> a : i32;
637   //
638   // fn F(a : bool) {
639   // }
640 
641   auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
642   auto* p = Param("a", ty.bool_());
643   Func("F", {p}, ty.void_(), {});
644 
645   ASSERT_TRUE(r()->Resolve()) << r()->error();
646 
647   auto* global = Sem().Get(g);
648   auto* param = Sem().Get<sem::Parameter>(p);
649 
650   ASSERT_NE(global, nullptr);
651   ASSERT_NE(param, nullptr);
652 
653   EXPECT_EQ(param->Shadows(), global);
654 }
655 
TEST_F(ResolverVarLetTest,ParamShadowsGlobalLet)656 TEST_F(ResolverVarLetTest, ParamShadowsGlobalLet) {
657   // let a : i32 = 1;
658   //
659   // fn F(a : bool) {
660   // }
661 
662   auto* g = GlobalConst("a", ty.i32(), Expr(1));
663   auto* p = Param("a", ty.bool_());
664   Func("F", {p}, ty.void_(), {});
665 
666   ASSERT_TRUE(r()->Resolve()) << r()->error();
667 
668   auto* global = Sem().Get(g);
669   auto* param = Sem().Get<sem::Parameter>(p);
670 
671   ASSERT_NE(global, nullptr);
672   ASSERT_NE(param, nullptr);
673 
674   EXPECT_EQ(param->Shadows(), global);
675 }
676 
TEST_F(ResolverVarLetTest,ParamShadowsAlias)677 TEST_F(ResolverVarLetTest, ParamShadowsAlias) {
678   // type a = i32;
679   //
680   // fn F(a : a) {
681   // }
682 
683   auto* a = Alias("a", ty.i32());
684   auto* p = Param("a", ty.type_name("a"));
685   Func("F", {p}, ty.void_(), {});
686 
687   ASSERT_TRUE(r()->Resolve()) << r()->error();
688 
689   auto* alias = Sem().Get(a);
690   auto* param = Sem().Get<sem::Parameter>(p);
691 
692   ASSERT_NE(alias, nullptr);
693   ASSERT_NE(param, nullptr);
694 
695   EXPECT_EQ(param->Shadows(), alias);
696   EXPECT_EQ(param->Type(), alias);
697 }
698 
699 }  // namespace
700 }  // namespace resolver
701 }  // namespace tint
702