tint/resolver: Tidy up variable_test.cc

Split tests up by variable type, and group them.

Change-Id: I4a9ae620883cd2acc05745b54f85df7b3fe7ac3d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94602
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-06-24 22:21:39 +00:00 committed by Dawn LUCI CQ
parent 0490ee8e42
commit ebed939759
1 changed files with 331 additions and 241 deletions

View File

@ -25,7 +25,10 @@ namespace {
struct ResolverVariableTest : public resolver::TestHelper, public testing::Test {}; struct ResolverVariableTest : public resolver::TestHelper, public testing::Test {};
TEST_F(ResolverVariableTest, VarDeclWithoutConstructor) { ////////////////////////////////////////////////////////////////////////////////////////////////////
// Function-scope 'var'
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_F(ResolverVariableTest, LocalVar_NoConstructor) {
// struct S { i : i32; } // struct S { i : i32; }
// alias A = S; // alias A = S;
// fn F(){ // fn F(){
@ -82,7 +85,7 @@ TEST_F(ResolverVariableTest, VarDeclWithoutConstructor) {
EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr); EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr);
} }
TEST_F(ResolverVariableTest, VarDeclWithConstructor) { TEST_F(ResolverVariableTest, LocalVar_WithConstructor) {
// struct S { i : i32; } // struct S { i : i32; }
// alias A = S; // alias A = S;
// fn F(){ // fn F(){
@ -131,6 +134,13 @@ TEST_F(ResolverVariableTest, VarDeclWithConstructor) {
ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>()); ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>()); ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
EXPECT_EQ(TypeOf(i)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(u)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(f)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(b)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(s)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(a)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>()); EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>()); EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>()); EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
@ -146,7 +156,191 @@ TEST_F(ResolverVariableTest, VarDeclWithConstructor) {
EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c); EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
} }
TEST_F(ResolverVariableTest, LetDecl) { TEST_F(ResolverVariableTest, LocalVar_ShadowsAlias) {
// type a = i32;
//
// fn F() {
// var a = false;
// }
auto* t = Alias("a", ty.i32());
auto* v = Var("a", nullptr, Expr(false));
Func("F", {}, ty.void_(), {Decl(v)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* type_t = Sem().Get(t);
auto* local = Sem().Get<sem::LocalVariable>(v);
ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), type_t);
}
TEST_F(ResolverVariableTest, LocalVar_ShadowsStruct) {
// struct a {
// m : i32;
// };
//
// fn F() {
// var a = true;
// }
auto* t = Structure("a", {Member("m", ty.i32())});
auto* v = Var("a", nullptr, Expr(false));
Func("F", {}, ty.void_(), {Decl(v)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* type_t = Sem().Get(t);
auto* local = Sem().Get<sem::LocalVariable>(v);
ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), type_t);
}
TEST_F(ResolverVariableTest, LocalVar_ShadowsFunction) {
// fn a() {
// var a = true;
// }
auto* v = Var("a", nullptr, Expr(false));
auto* f = Func("a", {}, ty.void_(), {Decl(v)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* func = Sem().Get(f);
ASSERT_NE(func, nullptr);
auto* local = Sem().Get<sem::LocalVariable>(v);
ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), func);
}
TEST_F(ResolverVariableTest, LocalVar_ShadowsGlobalVar) {
// var<private> a : i32;
//
// fn F() {
// var a = a;
// }
auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
auto* v = Var("a", nullptr, Expr("a"));
Func("F", {}, ty.void_(), {Decl(v)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* global = Sem().Get(g);
auto* local = Sem().Get<sem::LocalVariable>(v);
ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), global);
auto* user_v = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
EXPECT_EQ(user_v->Variable(), global);
}
TEST_F(ResolverVariableTest, LocalVar_ShadowsGlobalLet) {
// let a : i32 = 1;
//
// fn X() {
// var a = (a == 123);
// }
auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
auto* v = Var("a", nullptr, Expr("a"));
Func("F", {}, ty.void_(), {Decl(v)});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* global = Sem().Get(g);
auto* local = Sem().Get<sem::LocalVariable>(v);
ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), global);
auto* user_v = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
EXPECT_EQ(user_v->Variable(), global);
}
TEST_F(ResolverVariableTest, LocalVar_ShadowsLocalVar) {
// fn F() {
// var a : i32; // x
// {
// var a = a; // y
// }
// }
auto* x = Var("a", ty.i32(), Expr(1_i));
auto* y = Var("a", nullptr, Expr("a"));
Func("F", {}, ty.void_(), {Decl(x), Block(Decl(y))});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* local_x = Sem().Get<sem::LocalVariable>(x);
auto* local_y = Sem().Get<sem::LocalVariable>(y);
ASSERT_NE(local_x, nullptr);
ASSERT_NE(local_y, nullptr);
EXPECT_EQ(local_y->Shadows(), local_x);
auto* user_y = Sem().Get<sem::VariableUser>(local_y->Declaration()->constructor);
ASSERT_NE(user_y, nullptr);
EXPECT_EQ(user_y->Variable(), local_x);
}
TEST_F(ResolverVariableTest, LocalVar_ShadowsLocalLet) {
// fn F() {
// let a = 1;
// {
// var a = (a == 123);
// }
// }
auto* l = Let("a", ty.i32(), Expr(1_i));
auto* v = Var("a", nullptr, Expr("a"));
Func("X", {}, ty.void_(), {Decl(l), Block(Decl(v))});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* local_l = Sem().Get<sem::LocalVariable>(l);
auto* local_v = Sem().Get<sem::LocalVariable>(v);
ASSERT_NE(local_l, nullptr);
ASSERT_NE(local_v, nullptr);
EXPECT_EQ(local_v->Shadows(), local_l);
auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
EXPECT_EQ(user_v->Variable(), local_l);
}
TEST_F(ResolverVariableTest, LocalVar_ShadowsParam) {
// fn F(a : i32) {
// {
// var a = a;
// }
// }
auto* p = Param("a", ty.i32());
auto* v = Var("a", nullptr, Expr("a"));
Func("X", {p}, ty.void_(), {Block(Decl(v))});
ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* param = Sem().Get<sem::Parameter>(p);
auto* local = Sem().Get<sem::LocalVariable>(v);
ASSERT_NE(param, nullptr);
ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), param);
auto* user_v = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
EXPECT_EQ(user_v->Variable(), param);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function-scope 'let'
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_F(ResolverVariableTest, LocalLet) {
// struct S { i : i32; } // struct S { i : i32; }
// fn F(){ // fn F(){
// var v : i32; // var v : i32;
@ -212,66 +406,7 @@ TEST_F(ResolverVariableTest, LetDecl) {
EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c); EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c);
} }
TEST_F(ResolverVariableTest, DefaultVarStorageClass) { TEST_F(ResolverVariableTest, LocalLet_InheritsAccessFromOriginatingVariable) {
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
auto* buf = Structure("S", {Member("m", ty.i32())});
auto* function = Var("f", ty.i32());
auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
ast::AttributeList{
create<ast::BindingAttribute>(0),
create<ast::GroupAttribute>(0),
});
auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
ast::AttributeList{
create<ast::BindingAttribute>(1),
create<ast::GroupAttribute>(0),
});
auto* handle = Global("h", ty.depth_texture(ast::TextureDimension::k2d),
ast::AttributeList{
create<ast::BindingAttribute>(2),
create<ast::GroupAttribute>(0),
});
WrapInFunction(function);
ASSERT_TRUE(r()->Resolve()) << r()->error();
ASSERT_TRUE(TypeOf(function)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(private_)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(workgroup)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(uniform)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(handle)->Is<sem::Reference>());
EXPECT_EQ(TypeOf(function)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(private_)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(workgroup)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(uniform)->As<sem::Reference>()->Access(), ast::Access::kRead);
EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kRead);
EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
}
TEST_F(ResolverVariableTest, ExplicitVarStorageClass) {
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
auto* buf = Structure("S", {Member("m", ty.i32())});
auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
ast::AttributeList{
create<ast::BindingAttribute>(1),
create<ast::GroupAttribute>(0),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
}
TEST_F(ResolverVariableTest, LetInheritsAccessFromOriginatingVariable) {
// struct Inner { // struct Inner {
// arr: array<i32, 4>; // arr: array<i32, 4>;
// } // }
@ -304,293 +439,248 @@ TEST_F(ResolverVariableTest, LetInheritsAccessFromOriginatingVariable) {
EXPECT_EQ(TypeOf(ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite); EXPECT_EQ(TypeOf(ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
} }
TEST_F(ResolverVariableTest, LocalShadowsAlias) { TEST_F(ResolverVariableTest, LocalLet_ShadowsAlias) {
// type a = i32; // type a = i32;
// //
// fn X() { // fn F() {
// var a = false;
// }
//
// fn Y() {
// let a = true; // let a = true;
// } // }
auto* t = Alias("a", ty.i32()); auto* t = Alias("a", ty.i32());
auto* v = Var("a", nullptr, Expr(false));
auto* l = Let("a", nullptr, Expr(false)); auto* l = Let("a", nullptr, Expr(false));
Func("X", {}, ty.void_(), {Decl(v)}); Func("F", {}, ty.void_(), {Decl(l)});
Func("Y", {}, ty.void_(), {Decl(l)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* type_t = Sem().Get(t); auto* type_t = Sem().Get(t);
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* local = Sem().Get<sem::LocalVariable>(l);
auto* local_l = Sem().Get<sem::LocalVariable>(l); ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), type_t);
ASSERT_NE(local_v, nullptr);
ASSERT_NE(local_l, nullptr);
EXPECT_EQ(local_v->Shadows(), type_t);
EXPECT_EQ(local_l->Shadows(), type_t);
} }
TEST_F(ResolverVariableTest, LocalShadowsStruct) { TEST_F(ResolverVariableTest, LocalLet_ShadowsStruct) {
// struct a { // struct a {
// m : i32; // m : i32;
// }; // };
// //
// fn X() { // fn F() {
// var a = true;
// }
//
// fn Y() {
// let a = false; // let a = false;
// } // }
auto* t = Structure("a", {Member("m", ty.i32())}); auto* t = Structure("a", {Member("m", ty.i32())});
auto* v = Var("a", nullptr, Expr(false));
auto* l = Let("a", nullptr, Expr(false)); auto* l = Let("a", nullptr, Expr(false));
Func("X", {}, ty.void_(), {Decl(v)}); Func("F", {}, ty.void_(), {Decl(l)});
Func("Y", {}, ty.void_(), {Decl(l)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* type_t = Sem().Get(t); auto* type_t = Sem().Get(t);
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* local = Sem().Get<sem::LocalVariable>(l);
auto* local_l = Sem().Get<sem::LocalVariable>(l); ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), type_t);
ASSERT_NE(local_v, nullptr);
ASSERT_NE(local_l, nullptr);
EXPECT_EQ(local_v->Shadows(), type_t);
EXPECT_EQ(local_l->Shadows(), type_t);
} }
TEST_F(ResolverVariableTest, LocalShadowsFunction) { TEST_F(ResolverVariableTest, LocalLet_ShadowsFunction) {
// fn a() { // fn a() {
// var a = true; // let a = false;
// }
//
// fn b() {
// let b = false;
// } // }
auto* v = Var("a", nullptr, Expr(false)); auto* l = Let("a", nullptr, Expr(false));
auto* l = Let("b", nullptr, Expr(false)); auto* fb = Func("a", {}, ty.void_(), {Decl(l)});
auto* fa = Func("a", {}, ty.void_(), {Decl(v)});
auto* fb = Func("b", {}, ty.void_(), {Decl(l)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* func = Sem().Get(fb);
auto* local_l = Sem().Get<sem::LocalVariable>(l); ASSERT_NE(func, nullptr);
auto* func_a = Sem().Get(fa);
auto* func_b = Sem().Get(fb);
ASSERT_NE(local_v, nullptr); auto* local = Sem().Get<sem::LocalVariable>(l);
ASSERT_NE(local_l, nullptr); ASSERT_NE(local, nullptr);
ASSERT_NE(func_a, nullptr); EXPECT_EQ(local->Shadows(), func);
ASSERT_NE(func_b, nullptr);
EXPECT_EQ(local_v->Shadows(), func_a);
EXPECT_EQ(local_l->Shadows(), func_b);
} }
TEST_F(ResolverVariableTest, LocalShadowsGlobalVar) { TEST_F(ResolverVariableTest, LocalLet_ShadowsGlobalVar) {
// var<private> a : i32; // var<private> a : i32;
// //
// fn X() { // fn F() {
// var a = a;
// }
//
// fn Y() {
// let a = a; // let a = a;
// } // }
auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate); auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
auto* v = Var("a", nullptr, Expr("a"));
auto* l = Let("a", nullptr, Expr("a")); auto* l = Let("a", nullptr, Expr("a"));
Func("X", {}, ty.void_(), {Decl(v)}); Func("F", {}, ty.void_(), {Decl(l)});
Func("Y", {}, ty.void_(), {Decl(l)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* global = Sem().Get(g); auto* global = Sem().Get(g);
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* local = Sem().Get<sem::LocalVariable>(l);
auto* local_l = Sem().Get<sem::LocalVariable>(l); ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), global);
ASSERT_NE(local_v, nullptr); auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
ASSERT_NE(local_l, nullptr); ASSERT_NE(user, nullptr);
EXPECT_EQ(user->Variable(), global);
EXPECT_EQ(local_v->Shadows(), global);
EXPECT_EQ(local_l->Shadows(), global);
auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
ASSERT_NE(user_l, nullptr);
EXPECT_EQ(user_v->Variable(), global);
EXPECT_EQ(user_l->Variable(), global);
} }
TEST_F(ResolverVariableTest, LocalShadowsGlobalLet) { TEST_F(ResolverVariableTest, LocalLet_ShadowsGlobalLet) {
// let a : i32 = 1; // let a : i32 = 1;
// //
// fn X() { // fn F() {
// var a = (a == 123);
// }
//
// fn Y() {
// let a = (a == 321); // let a = (a == 321);
// } // }
auto* g = GlobalConst("a", ty.i32(), Expr(1_i)); auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
auto* v = Var("a", nullptr, Expr("a"));
auto* l = Let("a", nullptr, Expr("a")); auto* l = Let("a", nullptr, Expr("a"));
Func("X", {}, ty.void_(), {Decl(v)}); Func("F", {}, ty.void_(), {Decl(l)});
Func("Y", {}, ty.void_(), {Decl(l)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* global = Sem().Get(g); auto* global = Sem().Get(g);
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* local = Sem().Get<sem::LocalVariable>(l);
auto* local_l = Sem().Get<sem::LocalVariable>(l); ASSERT_NE(local, nullptr);
EXPECT_EQ(local->Shadows(), global);
ASSERT_NE(local_v, nullptr); auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
ASSERT_NE(local_l, nullptr); ASSERT_NE(user, nullptr);
EXPECT_EQ(user->Variable(), global);
EXPECT_EQ(local_v->Shadows(), global);
EXPECT_EQ(local_l->Shadows(), global);
auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
ASSERT_NE(user_l, nullptr);
EXPECT_EQ(user_v->Variable(), global);
EXPECT_EQ(user_l->Variable(), global);
} }
TEST_F(ResolverVariableTest, LocalShadowsLocalVar) { TEST_F(ResolverVariableTest, LocalLet_ShadowsLocalVar) {
// fn X() { // fn F() {
// var a : i32; // var a : i32;
// { // {
// var a = a;
// }
// {
// let a = a; // let a = a;
// } // }
// } // }
auto* s = Var("a", ty.i32(), Expr(1_i)); auto* v = Var("a", ty.i32(), Expr(1_i));
auto* v = Var("a", nullptr, Expr("a"));
auto* l = Let("a", nullptr, Expr("a")); auto* l = Let("a", nullptr, Expr("a"));
Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))}); Func("F", {}, ty.void_(), {Decl(v), Block(Decl(l))});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* local_s = Sem().Get<sem::LocalVariable>(s);
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* local_v = Sem().Get<sem::LocalVariable>(v);
auto* local_l = Sem().Get<sem::LocalVariable>(l); auto* local_l = Sem().Get<sem::LocalVariable>(l);
ASSERT_NE(local_s, nullptr);
ASSERT_NE(local_v, nullptr); ASSERT_NE(local_v, nullptr);
ASSERT_NE(local_l, nullptr); ASSERT_NE(local_l, nullptr);
EXPECT_EQ(local_l->Shadows(), local_v);
EXPECT_EQ(local_v->Shadows(), local_s); auto* user = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
EXPECT_EQ(local_l->Shadows(), local_s); ASSERT_NE(user, nullptr);
EXPECT_EQ(user->Variable(), local_v);
auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
ASSERT_NE(user_l, nullptr);
EXPECT_EQ(user_v->Variable(), local_s);
EXPECT_EQ(user_l->Variable(), local_s);
} }
TEST_F(ResolverVariableTest, LocalShadowsLocalLet) { TEST_F(ResolverVariableTest, LocalLet_ShadowsLocalLet) {
// fn X() { // fn X() {
// let a = 1; // let a = 1; // x
// { // {
// var a = (a == 123); // let a = (a == 321); // y
// }
// {
// let a = (a == 321);
// } // }
// } // }
auto* s = Let("a", ty.i32(), Expr(1_i)); auto* x = Let("a", ty.i32(), Expr(1_i));
auto* v = Var("a", nullptr, Expr("a")); auto* y = Let("a", nullptr, Expr("a"));
auto* l = Let("a", nullptr, Expr("a")); Func("X", {}, ty.void_(), {Decl(x), Block(Decl(y))});
Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* local_s = Sem().Get<sem::LocalVariable>(s); auto* local_x = Sem().Get<sem::LocalVariable>(x);
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* local_y = Sem().Get<sem::LocalVariable>(y);
auto* local_l = Sem().Get<sem::LocalVariable>(l);
ASSERT_NE(local_s, nullptr); ASSERT_NE(local_x, nullptr);
ASSERT_NE(local_v, nullptr); ASSERT_NE(local_y, nullptr);
ASSERT_NE(local_l, nullptr); EXPECT_EQ(local_y->Shadows(), local_x);
EXPECT_EQ(local_v->Shadows(), local_s); auto* user = Sem().Get<sem::VariableUser>(local_y->Declaration()->constructor);
EXPECT_EQ(local_l->Shadows(), local_s); ASSERT_NE(user, nullptr);
EXPECT_EQ(user->Variable(), local_x);
auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
ASSERT_NE(user_l, nullptr);
EXPECT_EQ(user_v->Variable(), local_s);
EXPECT_EQ(user_l->Variable(), local_s);
} }
TEST_F(ResolverVariableTest, LocalShadowsParam) { TEST_F(ResolverVariableTest, LocalLet_ShadowsParam) {
// fn F(a : i32) { // fn F(a : i32) {
// { // {
// var a = a;
// }
// {
// let a = a; // let a = a;
// } // }
// } // }
auto* p = Param("a", ty.i32()); auto* p = Param("a", ty.i32());
auto* v = Var("a", nullptr, Expr("a"));
auto* l = Let("a", nullptr, Expr("a")); auto* l = Let("a", nullptr, Expr("a"));
Func("X", {p}, ty.void_(), {Block(Decl(v)), Block(Decl(l))}); Func("X", {p}, ty.void_(), {Block(Decl(l))});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* param = Sem().Get<sem::Parameter>(p); auto* param = Sem().Get<sem::Parameter>(p);
auto* local_v = Sem().Get<sem::LocalVariable>(v); auto* local = Sem().Get<sem::LocalVariable>(l);
auto* local_l = Sem().Get<sem::LocalVariable>(l);
ASSERT_NE(param, nullptr); ASSERT_NE(param, nullptr);
ASSERT_NE(local_v, nullptr); ASSERT_NE(local, nullptr);
ASSERT_NE(local_l, nullptr); EXPECT_EQ(local->Shadows(), param);
EXPECT_EQ(local_v->Shadows(), param); auto* user = Sem().Get<sem::VariableUser>(local->Declaration()->constructor);
EXPECT_EQ(local_l->Shadows(), param); ASSERT_NE(user, nullptr);
EXPECT_EQ(user->Variable(), param);
auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
ASSERT_NE(user_v, nullptr);
ASSERT_NE(user_l, nullptr);
EXPECT_EQ(user_v->Variable(), param);
EXPECT_EQ(user_l->Variable(), param);
} }
TEST_F(ResolverVariableTest, ParamShadowsFunction) { ////////////////////////////////////////////////////////////////////////////////////////////////////
// Module-scope 'var'
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_F(ResolverVariableTest, GlobalVar_StorageClass) {
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
auto* buf = Structure("S", {Member("m", ty.i32())});
auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
ast::AttributeList{
create<ast::BindingAttribute>(0),
create<ast::GroupAttribute>(0),
});
auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
ast::AttributeList{
create<ast::BindingAttribute>(1),
create<ast::GroupAttribute>(0),
});
auto* handle = Global("h", ty.depth_texture(ast::TextureDimension::k2d),
ast::AttributeList{
create<ast::BindingAttribute>(2),
create<ast::GroupAttribute>(0),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
ASSERT_TRUE(TypeOf(private_)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(workgroup)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(uniform)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
ASSERT_TRUE(TypeOf(handle)->Is<sem::Reference>());
EXPECT_EQ(TypeOf(private_)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(workgroup)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
EXPECT_EQ(TypeOf(uniform)->As<sem::Reference>()->Access(), ast::Access::kRead);
EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kRead);
EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
}
TEST_F(ResolverVariableTest, GlobalVar_ExplicitStorageClass) {
// https://gpuweb.github.io/gpuweb/wgsl/#storage-class
auto* buf = Structure("S", {Member("m", ty.i32())});
auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
ast::AttributeList{
create<ast::BindingAttribute>(1),
create<ast::GroupAttribute>(0),
});
ASSERT_TRUE(r()->Resolve()) << r()->error();
ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function parameter
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_F(ResolverVariableTest, Param_ShadowsFunction) {
// fn a(a : bool) { // fn a(a : bool) {
// } // }
@ -608,7 +698,7 @@ TEST_F(ResolverVariableTest, ParamShadowsFunction) {
EXPECT_EQ(param->Shadows(), func); EXPECT_EQ(param->Shadows(), func);
} }
TEST_F(ResolverVariableTest, ParamShadowsGlobalVar) { TEST_F(ResolverVariableTest, Param_ShadowsGlobalVar) {
// var<private> a : i32; // var<private> a : i32;
// //
// fn F(a : bool) { // fn F(a : bool) {
@ -629,7 +719,7 @@ TEST_F(ResolverVariableTest, ParamShadowsGlobalVar) {
EXPECT_EQ(param->Shadows(), global); EXPECT_EQ(param->Shadows(), global);
} }
TEST_F(ResolverVariableTest, ParamShadowsGlobalLet) { TEST_F(ResolverVariableTest, Param_ShadowsGlobalLet) {
// let a : i32 = 1; // let a : i32 = 1;
// //
// fn F(a : bool) { // fn F(a : bool) {
@ -650,7 +740,7 @@ TEST_F(ResolverVariableTest, ParamShadowsGlobalLet) {
EXPECT_EQ(param->Shadows(), global); EXPECT_EQ(param->Shadows(), global);
} }
TEST_F(ResolverVariableTest, ParamShadowsAlias) { TEST_F(ResolverVariableTest, Param_ShadowsAlias) {
// type a = i32; // type a = i32;
// //
// fn F(a : a) { // fn F(a : a) {