diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index 5d4575d45b..e490815175 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc @@ -413,6 +413,8 @@ sem::Variable* Resolver::Variable(const ast::Variable* var, } } + global->SetConstructor(rhs); + builder_->Sem().Add(var, global); return global; } @@ -421,6 +423,7 @@ sem::Variable* Resolver::Variable(const ast::Variable* var, var, var_ty, storage_class, access, current_statement_, (rhs && var->is_const) ? rhs->ConstantValue() : sem::Constant{}); builder_->Sem().Add(var, local); + local->SetConstructor(rhs); return local; } case VariableKind::kParameter: { diff --git a/src/resolver/var_let_test.cc b/src/resolver/var_let_test.cc index 57d7a148c5..631537b47b 100644 --- a/src/resolver/var_let_test.cc +++ b/src/resolver/var_let_test.cc @@ -26,7 +26,7 @@ namespace { struct ResolverVarLetTest : public resolver::TestHelper, public testing::Test {}; -TEST_F(ResolverVarLetTest, TypeOfVar) { +TEST_F(ResolverVarLetTest, VarDeclWithoutConstructor) { // struct S { i : i32; } // alias A = S; // fn F(){ @@ -74,9 +74,80 @@ TEST_F(ResolverVarLetTest, TypeOfVar) { EXPECT_TRUE(TypeOf(b)->As()->StoreType()->Is()); EXPECT_TRUE(TypeOf(s)->As()->StoreType()->Is()); EXPECT_TRUE(TypeOf(a)->As()->StoreType()->Is()); + + EXPECT_EQ(Sem().Get(i)->Constructor(), nullptr); + EXPECT_EQ(Sem().Get(u)->Constructor(), nullptr); + EXPECT_EQ(Sem().Get(f)->Constructor(), nullptr); + EXPECT_EQ(Sem().Get(b)->Constructor(), nullptr); + EXPECT_EQ(Sem().Get(s)->Constructor(), nullptr); + EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr); } -TEST_F(ResolverVarLetTest, TypeOfLet) { +TEST_F(ResolverVarLetTest, VarDeclWithConstructor) { + // struct S { i : i32; } + // alias A = S; + // fn F(){ + // var i : i32 = 1; + // var u : u32 = 1u; + // var f : f32 = 1.f; + // var b : bool = true; + // var s : S = S(1); + // var a : A = A(1); + // } + + auto* S = Structure("S", {Member("i", ty.i32())}); + auto* A = Alias("A", ty.Of(S)); + + auto* i_c = Expr(1); + auto* u_c = Expr(1u); + auto* f_c = Expr(1.f); + auto* b_c = Expr(true); + auto* s_c = Construct(ty.Of(S), Expr(1)); + auto* a_c = Construct(ty.Of(A), Expr(1)); + + auto* i = Var("i", ty.i32(), ast::StorageClass::kNone, i_c); + auto* u = Var("u", ty.u32(), ast::StorageClass::kNone, u_c); + auto* f = Var("f", ty.f32(), ast::StorageClass::kNone, f_c); + auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone, b_c); + auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone, s_c); + auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone, a_c); + + Func("F", {}, ty.void_(), + { + Decl(i), + Decl(u), + Decl(f), + Decl(b), + Decl(s), + Decl(a), + }); + + ASSERT_TRUE(r()->Resolve()) << r()->error(); + + // `var` declarations are always of reference type + ASSERT_TRUE(TypeOf(i)->Is()); + ASSERT_TRUE(TypeOf(u)->Is()); + ASSERT_TRUE(TypeOf(f)->Is()); + ASSERT_TRUE(TypeOf(b)->Is()); + ASSERT_TRUE(TypeOf(s)->Is()); + ASSERT_TRUE(TypeOf(a)->Is()); + + EXPECT_TRUE(TypeOf(i)->As()->StoreType()->Is()); + EXPECT_TRUE(TypeOf(u)->As()->StoreType()->Is()); + EXPECT_TRUE(TypeOf(f)->As()->StoreType()->Is()); + EXPECT_TRUE(TypeOf(b)->As()->StoreType()->Is()); + EXPECT_TRUE(TypeOf(s)->As()->StoreType()->Is()); + EXPECT_TRUE(TypeOf(a)->As()->StoreType()->Is()); + + EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c); + EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c); + EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c); + EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c); + EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c); + EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c); +} + +TEST_F(ResolverVarLetTest, LetDecl) { // struct S { i : i32; } // fn F(){ // var v : i32; @@ -86,21 +157,28 @@ TEST_F(ResolverVarLetTest, TypeOfLet) { // let b : bool = true; // let s : S = S(1); // let a : A = A(1); - // let p : pointer = &V; + // let p : pointer = &v; // } auto* S = Structure("S", {Member("i", ty.i32())}); auto* A = Alias("A", ty.Of(S)); - auto* v = Var("v", ty.i32(), ast::StorageClass::kNone); - auto* i = Const("i", ty.i32(), Expr(1)); - auto* u = Const("u", ty.u32(), Expr(1u)); - auto* f = Const("f", ty.f32(), Expr(1.f)); - auto* b = Const("b", ty.bool_(), Expr(true)); - auto* s = Const("s", ty.Of(S), Construct(ty.Of(S), Expr(1))); - auto* a = Const("a", ty.Of(A), Construct(ty.Of(A), Expr(1))); - auto* p = - Const("p", ty.pointer(ast::StorageClass::kFunction), AddressOf(v)); + + auto* i_c = Expr(1); + auto* u_c = Expr(1u); + auto* f_c = Expr(1.f); + auto* b_c = Expr(true); + auto* s_c = Construct(ty.Of(S), Expr(1)); + auto* a_c = Construct(ty.Of(A), Expr(1)); + auto* p_c = AddressOf(v); + + auto* i = Const("i", ty.i32(), i_c); + auto* u = Const("u", ty.u32(), u_c); + auto* f = Const("f", ty.f32(), f_c); + auto* b = Const("b", ty.bool_(), b_c); + auto* s = Const("s", ty.Of(S), s_c); + auto* a = Const("a", ty.Of(A), a_c); + auto* p = Const("p", ty.pointer(ast::StorageClass::kFunction), p_c); Func("F", {}, ty.void_(), { @@ -117,14 +195,22 @@ TEST_F(ResolverVarLetTest, TypeOfLet) { ASSERT_TRUE(r()->Resolve()) << r()->error(); // `let` declarations are always of the storage type - EXPECT_TRUE(TypeOf(i)->Is()); - EXPECT_TRUE(TypeOf(u)->Is()); - EXPECT_TRUE(TypeOf(f)->Is()); - EXPECT_TRUE(TypeOf(b)->Is()); - EXPECT_TRUE(TypeOf(s)->Is()); - EXPECT_TRUE(TypeOf(a)->Is()); + ASSERT_TRUE(TypeOf(i)->Is()); + ASSERT_TRUE(TypeOf(u)->Is()); + ASSERT_TRUE(TypeOf(f)->Is()); + ASSERT_TRUE(TypeOf(b)->Is()); + ASSERT_TRUE(TypeOf(s)->Is()); + ASSERT_TRUE(TypeOf(a)->Is()); ASSERT_TRUE(TypeOf(p)->Is()); - EXPECT_TRUE(TypeOf(p)->As()->StoreType()->Is()); + ASSERT_TRUE(TypeOf(p)->As()->StoreType()->Is()); + + EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c); + EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c); + EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c); + EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c); + EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c); + EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c); + EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c); } TEST_F(ResolverVarLetTest, DefaultVarStorageClass) { diff --git a/src/sem/variable.h b/src/sem/variable.h index ac7dac151d..1f66ac7f23 100644 --- a/src/sem/variable.h +++ b/src/sem/variable.h @@ -72,6 +72,16 @@ class Variable : public Castable { /// @return the constant value of this expression const Constant& ConstantValue() const { return constant_value_; } + /// @returns the variable constructor expression, or nullptr if the variable + /// does not have one. + const Expression* Constructor() const { return constructor_; } + + /// Sets the variable constructor expression. + /// @param constructor the constructor expression to assign to this variable. + void SetConstructor(const Expression* constructor) { + constructor_ = constructor; + } + /// @returns the expressions that use the variable const std::vector& Users() const { return users_; } @@ -81,9 +91,10 @@ class Variable : public Castable { private: const ast::Variable* const declaration_; const sem::Type* const type_; - ast::StorageClass const storage_class_; - ast::Access const access_; + const ast::StorageClass storage_class_; + const ast::Access access_; const Constant constant_value_; + const Expression* constructor_ = nullptr; std::vector users_; };