diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 3a0aed119..79b755e97 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -328,8 +328,30 @@ bool VariableDeclaration::isLValue() const void VariableDeclaration::checkTypeRequirements() { - if (m_value) + // Variables can be declared without type (with "var"), in which case the first assignment + // sets the type. + // Note that assignments before the first declaration are legal because of the special scoping + // rules inherited from JavaScript. + if (!m_value) + return; + if (m_type) + m_value->expectType(*m_type); + else + { + // no type declared and no previous assignment, infer the type m_value->checkTypeRequirements(); + TypePointer type = m_value->getType(); + if (type->getCategory() == Type::Category::IntegerConstant) + { + auto intType = dynamic_pointer_cast(type)->getIntegerType(); + if (!intType) + BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString() + ".")); + type = intType; + } + else if (type->getCategory() == Type::Category::Void) + BOOST_THROW_EXCEPTION(createTypeError("Variable cannot have void type.")); + m_type = type; + } } bool VariableDeclaration::isExternalFunctionParameter() const @@ -445,32 +467,9 @@ void Return::checkTypeRequirements() void VariableDeclarationStatement::checkTypeRequirements() { - // Variables can be declared without type (with "var"), in which case the first assignment - // sets the type. - // Note that assignments before the first declaration are legal because of the special scoping - // rules inherited from JavaScript. - if (m_variable->getValue()) - { - if (m_variable->getType()) - m_variable->getValue()->expectType(*m_variable->getType()); - else - { - // no type declared and no previous assignment, infer the type - m_variable->getValue()->checkTypeRequirements(); - TypePointer type = m_variable->getValue()->getType(); - if (type->getCategory() == Type::Category::IntegerConstant) - { - auto intType = dynamic_pointer_cast(type)->getIntegerType(); - if (!intType) - BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString())); - type = intType; - } - else if (type->getCategory() == Type::Category::Void) - BOOST_THROW_EXCEPTION(m_variable->createTypeError("var cannot be void type")); - m_variable->setType(type); - } - } + m_variable->checkTypeRequirements(); } + void Assignment::checkTypeRequirements() { m_leftHandSide->checkTypeRequirements(); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index c3c2cd8d3..eab53153f 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -460,7 +460,6 @@ public: virtual bool isLValue() const override; - /// Calls checkTypeRequirments for all state variables. void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } bool isExternalFunctionParameter() const; diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index a48b62d0d..6e6254eba 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1292,6 +1292,24 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_int) +{ + char const* text = R"( + contract c { + uint8 a = 1000; + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_string) +{ + char const* text = R"( + contract c { + uint a = "abc"; + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() }