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