diff --git a/src/validator_impl.cc b/src/validator_impl.cc index ae7bbef031..da7908c436 100644 --- a/src/validator_impl.cc +++ b/src/validator_impl.cc @@ -96,6 +96,9 @@ bool ValidatorImpl::ValidateAssign(const ast::AssignmentStatement* a) { if (!a) { return false; } + if (!(ValidateConstant(a))) { + return false; + } if (!(ValidateExpression(a->lhs()) && ValidateExpression(a->rhs()))) { return false; } @@ -106,6 +109,25 @@ bool ValidatorImpl::ValidateAssign(const ast::AssignmentStatement* a) { return true; } +bool ValidatorImpl::ValidateConstant(const ast::AssignmentStatement* assign) { + if (!assign) { + return false; + } + + if (assign->lhs()->IsIdentifier()) { + ast::Variable* var; + auto* ident = assign->lhs()->AsIdentifier(); + if (variable_stack_.get(ident->name(), &var)) { + if (var->is_const()) { + set_error(assign->source(), "v-0021: cannot re-assign a constant: '" + + ident->name() + "'"); + return false; + } + } + } + return true; +} + bool ValidatorImpl::ValidateResultTypes(const ast::AssignmentStatement* a) { if (!a->lhs()->result_type() || !a->rhs()->result_type()) { set_error(a->source(), "result_type() is nullptr"); diff --git a/src/validator_impl.h b/src/validator_impl.h index 1fa0205f2f..d7a7fc3227 100644 --- a/src/validator_impl.h +++ b/src/validator_impl.h @@ -66,9 +66,9 @@ class ValidatorImpl { /// @returns true if the validation was successful bool ValidateStatement(const ast::Statement* stmt); /// Validates an assignment - /// @param a the assignment to check + /// @param assign the assignment to check /// @returns true if the validation was successful - bool ValidateAssign(const ast::AssignmentStatement* a); + bool ValidateAssign(const ast::AssignmentStatement* assign); /// Validates v-0001: Only allowed import is "GLSL.std.450" /// @param module the modele to check imports /// @returns ture if input complies with v-0001 rule @@ -82,9 +82,13 @@ class ValidatorImpl { /// @return true if idnet was defined bool ValidateIdentifier(const ast::IdentifierExpression* ident); /// Validates if the input follows type checking rules - /// @param 'a' the assignment to check + /// @param assign the assignment to check /// @returns ture if successful - bool ValidateResultTypes(const ast::AssignmentStatement* a); + bool ValidateResultTypes(const ast::AssignmentStatement* assign); + /// Validate v-0021: Cannot re-assign a constant + /// @param assign is the assigment to check if its lhs is a const + /// @returns false if lhs of assign is a constant identifier + bool ValidateConstant(const ast::AssignmentStatement* assign); private: std::string error_; diff --git a/src/validator_test.cc b/src/validator_test.cc index fe485fc529..cb5d6dbd63 100644 --- a/src/validator_test.cc +++ b/src/validator_test.cc @@ -413,27 +413,36 @@ TEST_F(ValidatorTest, UnsingUndefinedVariableOuterScope_Pass) { EXPECT_TRUE(v.ValidateStatements(outer_body.get())) << v.error(); } -TEST_F(ValidatorTest, DISABLED_AssignToConstant_Fail) { - // v-0021: Cannot re-assign a constant. - // const a :i32 = 1; - // a = 2; +TEST_F(ValidatorTest, AssignToConstant_Fail) { + // { + // const a :i32 = 2; + // a = 2 + // } ast::type::I32Type i32; + auto var = + std::make_unique("a", ast::StorageClass::kNone, &i32); + var->set_constructor(std::make_unique( + std::make_unique(&i32, 2))); + var->set_is_const(true); - ast::Variable var("a", ast::StorageClass::kPrivate, &i32); - var.set_constructor(std::make_unique( - std::make_unique(&i32, 1))); - var.set_is_const(true); auto lhs = std::make_unique("a"); - + auto* lhs_ptr = lhs.get(); auto rhs = std::make_unique( std::make_unique(&i32, 2)); + auto* rhs_ptr = rhs.get(); - ast::AssignmentStatement assign(std::move(lhs), std::move(rhs)); + auto body = std::make_unique(); + body->append(std::make_unique(std::move(var))); + body->append(std::make_unique( + Source{12, 34}, std::move(lhs), std::move(rhs))); + + EXPECT_TRUE(td()->DetermineStatements(body.get())) << td()->error(); + ASSERT_NE(lhs_ptr->result_type(), nullptr); + ASSERT_NE(rhs_ptr->result_type(), nullptr); tint::ValidatorImpl v; - // TODO(SarahM0): Invalidate assignments to a constant. - ASSERT_TRUE(v.has_error()); - EXPECT_EQ(v.error(), "2:1: v-0021: cannot re-assign a constant"); + EXPECT_FALSE(v.ValidateStatements(body.get())); + EXPECT_EQ(v.error(), "12:34: v-0021: cannot re-assign a constant: 'a'"); } } // namespace