diff options
-rw-r--r-- | Changelog.md | 4 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 5 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 23 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.h | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 114 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 13 |
6 files changed, 151 insertions, 10 deletions
diff --git a/Changelog.md b/Changelog.md index 81d753d9..71c7a0fe 100644 --- a/Changelog.md +++ b/Changelog.md @@ -14,8 +14,10 @@ Bugfixes: * Type checker: Proper type checking for bound functions. * Type checker: fixed crash related to invalid fixed point constants * Type checker: fixed crash related to invalid literal numbers. + * Type Checker: ``super.x`` does not look up ``x`` in the current contract. * Code generator: expect zero stack increase after ``super`` as an expression. - * Code Generator: fixed an internal compiler error for ``L.Foo`` for ``enum Foo`` defined in library ``L``. + * Code Generator: fix an internal compiler error for ``L.Foo`` for ``enum Foo`` defined in library ``L``. + * Code generator: allow inheritance of ``enum`` definitions. * Inline assembly: support the ``address`` opcode. * Inline assembly: fix parsing of assignment after a label. * Inline assembly: external variables of unsupported type (such as ``this``, ``super``, etc.) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 10d24e5a..46f4f7f6 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1386,6 +1386,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) } else if (exprType->category() == Type::Category::FixedBytes) annotation.isLValue = false; + else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType.get())) + { + if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType().get())) + annotation.isLValue = annotation.referencedDeclaration->isLValue(); + } return false; } diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 6d54b48b..9a096e2d 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -890,6 +890,8 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) { // no-op } + else if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration)) + appendVariable(*variable, static_cast<Expression const&>(_memberAccess)); else _memberAccess.expression().accept(*this); } @@ -1203,15 +1205,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration)) m_context << m_context.virtualFunctionEntryLabel(*functionDef).pushTag(); else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration)) - { - if (!variable->isConstant()) - setLValueFromDeclaration(*declaration, _identifier); - else - { - variable->value()->accept(*this); - utils().convertType(*variable->value()->annotation().type, *variable->annotation().type); - } - } + appendVariable(*variable, static_cast<Expression const&>(_identifier)); else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration)) { if (contract->isLibrary()) @@ -1646,6 +1640,17 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, utils().storeInMemoryDynamic(_expectedType); } +void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression) +{ + if (!_variable.isConstant()) + setLValueFromDeclaration(_variable, _expression); + else + { + _variable.value()->accept(*this); + utils().convertType(*_variable.value()->annotation().type, *_variable.annotation().type); + } +} + void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) { if (m_context.isLocalVariable(&_declaration)) diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index 43a92a10..f4ce1fec 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -103,6 +103,8 @@ private: /// expected to be on the stack and is updated by this call. void appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression); + /// Appends code for a variable that might be a constant or not + void appendVariable(VariableDeclaration const& _variable, Expression const& _expression); /// Sets the current LValue to a new one (of the appropriate type) from the given declaration. /// Also retrieves the value if it was not requested by @a _expression. void setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression); diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index bb197cca..8ef9a45b 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -5666,6 +5666,120 @@ BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable) BOOST_CHECK(callContractFunction("ticketPrice()") == encodeArgs(u256(555))); } +BOOST_AUTO_TEST_CASE(state_variable_under_contract_name) +{ + char const* text = R"( + contract Scope { + uint stateVar = 42; + + function getStateVar() constant returns (uint stateVar) { + stateVar = Scope.stateVar; + } + } + )"; + compileAndRun(text); + BOOST_CHECK(callContractFunction("getStateVar()") == encodeArgs(u256(42))); +} + +BOOST_AUTO_TEST_CASE(state_variable_local_variable_mixture) +{ + char const* sourceCode = R"( + contract A { + uint x = 1; + uint y = 2; + function a() returns (uint x) { + x = A.y; + } + } + )"; + + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(2))); +} + +BOOST_AUTO_TEST_CASE(inherited_function) { + char const* sourceCode = R"( + contract A { function f() internal returns (uint) { return 1; } } + contract B is A { + function f() internal returns (uint) { return 2; } + function g() returns (uint) { + return A.f(); + } + } + )"; + + compileAndRun(sourceCode, 0, "B"); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1))); +} + +BOOST_AUTO_TEST_CASE(inherited_function_from_a_library) { + char const* sourceCode = R"( + library A { function f() internal returns (uint) { return 1; } } + contract B { + function f() internal returns (uint) { return 2; } + function g() returns (uint) { + return A.f(); + } + } + )"; + + compileAndRun(sourceCode, 0, "B"); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(1))); +} + +BOOST_AUTO_TEST_CASE(inherited_constant_state_var) +{ + char const* sourceCode = R"( + contract A { + uint constant x = 7; + } + contract B is A { + function f() returns (uint) { + return A.x; + } + } + )"; + + compileAndRun(sourceCode, 0, "B"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7))); +} + +BOOST_AUTO_TEST_CASE(multiple_inherited_state_vars) +{ + char const* sourceCode = R"( + contract A { + uint x = 7; + } + contract B { + uint x = 9; + } + contract C is A, B { + function a() returns (uint) { + return A.x; + } + function b() returns (uint) { + return B.x; + } + function a_set(uint _x) returns (uint) { + A.x = _x; + return 1; + } + function b_set(uint _x) returns (uint) { + B.x = _x; + return 1; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(9))); + BOOST_CHECK(callContractFunction("a_set(uint256)", u256(1)) == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("b_set(uint256)", u256(3)) == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("b()") == encodeArgs(u256(3))); +} + BOOST_AUTO_TEST_CASE(constant_string_literal) { char const* sourceCode = R"( diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index f7ac73ae..9fe91cca 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1036,6 +1036,19 @@ BOOST_AUTO_TEST_CASE(private_state_variable) BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist"); } +BOOST_AUTO_TEST_CASE(missing_state_variable) +{ + char const* text = R"( + contract Scope { + function getStateVar() constant returns (uint stateVar) { + stateVar = Scope.stateVar; // should fail. + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + + BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor) { // test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126 |