diff options
-rw-r--r-- | Changelog.md | 2 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 34 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 25 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 23 |
4 files changed, 78 insertions, 6 deletions
diff --git a/Changelog.md b/Changelog.md index b1643810..a83c6ddb 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,8 @@ Features: Bugfixes: * Parser: Fix source location of VariableDeclarationStatement. + * Type Checker: Properly support overwriting members inherited from ``address`` in a contract + (such as ``balance``, ``transfer``, etc.) ### 0.4.17 (2017-09-21) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 43930125..43a77002 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1720,12 +1720,34 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ); } else if (possibleMembers.size() > 1) - m_errorReporter.fatalTypeError( - _memberAccess.location(), - "Member \"" + memberName + "\" not unique " - "after argument-dependent lookup in " + exprType->toString() + - (memberName == "value" ? " - did you forget the \"payable\" modifier?" : "") - ); + { + // Remove builtins (i.e. not having a declaration) first + for (auto it = possibleMembers.begin(); it != possibleMembers.end();) + if ( + ( + // Overloaded functions without declaration (e.g. transfer(), send(), call(), etc.) + it->type->category() == Type::Category::Function && + !dynamic_cast<FunctionType const&>(*it->type).hasDeclaration() + ) + || + ( + // Overloaded members (e.g. balance) + it->type->category() == Type::Category::Integer && + memberName == "balance" + ) + ) + it = possibleMembers.erase(it); + else + ++it; + + if (possibleMembers.size() > 1) + m_errorReporter.fatalTypeError( + _memberAccess.location(), + "Member \"" + memberName + "\" not unique " + "after argument-dependent lookup in " + exprType->toString() + + (memberName == "value" ? " - did you forget the \"payable\" modifier?" : "") + ); + } auto& annotation = _memberAccess.annotation(); annotation.referencedDeclaration = possibleMembers.front().declaration; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index df9332c4..35916ec7 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -10151,6 +10151,31 @@ BOOST_AUTO_TEST_CASE(constant_string) ABI_CHECK(callContractFunction("h()"), encodeDyn(string("hello"))); } +BOOST_AUTO_TEST_CASE(address_overload_resolution) +{ + char const* sourceCode = R"( + contract C { + function balance() returns (uint) { + return 1; + } + function transfer(uint amount) returns (uint) { + return amount; + } + } + contract D { + function f() returns (uint) { + return (new C()).balance(); + } + function g() returns (uint) { + return (new C()).transfer(5); + } + } + )"; + compileAndRun(sourceCode, 0, "D"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(5))); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 39c47f9c..959bc4ff 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -6953,6 +6953,29 @@ BOOST_AUTO_TEST_CASE(warn_about_suicide) CHECK_WARNING(text, "\"suicide\" has been deprecated in favour of \"selfdestruct\""); } +BOOST_AUTO_TEST_CASE(address_overload_resolution) +{ + char const* text = R"( + contract C { + function balance() returns (uint) { + this.balance; // to avoid pureness warning + return 1; + } + function transfer(uint amount) { + address(this).transfer(amount); // to avoid pureness warning + } + } + contract D { + function f() { + var x = (new C()).balance(); + x; + (new C()).transfer(5); + } + } + )"; + CHECK_SUCCESS(text); +} + BOOST_AUTO_TEST_SUITE_END() } |