From 9c483859d1bf346a0af2ca026e3c767565d1594a Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 23 Jun 2015 16:56:59 +0200 Subject: [PATCH] Fixed checking of abstract functions. Fixes #2264 --- libsolidity/AST.cpp | 36 +++++++++++++------ .../SolidityNameAndTypeResolution.cpp | 17 +++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index cb935183f..fac4360f1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -175,24 +175,40 @@ void ContractDefinition::checkDuplicateFunctions() const void ContractDefinition::checkAbstractFunctions() { - map functions; + // Mapping from name to function definition (exactly one per argument type equality class) and + // flag to indicate whether it is fully implemented. + using FunTypeAndFlag = std::pair; + map> functions; // Search from base to derived for (ContractDefinition const* contract: boost::adaptors::reverse(getLinearizedBaseContracts())) for (ASTPointer const& function: contract->getDefinedFunctions()) { - string const& name = function->getName(); - if (!function->isFullyImplemented() && functions.count(name) && functions[name]) - BOOST_THROW_EXCEPTION(function->createTypeError("Redeclaring an already implemented function as abstract")); - functions[name] = function->isFullyImplemented(); + auto& overloads = functions[function->getName()]; + FunctionTypePointer funType = make_shared(*function); + auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag) + { + return funType->hasEqualArgumentTypes(*_funAndFlag.first); + }); + if (it == overloads.end()) + overloads.push_back(make_pair(funType, function->isFullyImplemented())); + else if (it->second) + { + if (!function->isFullyImplemented()) + BOOST_THROW_EXCEPTION(function->createTypeError("Redeclaring an already implemented function as abstract")); + } + else if (function->isFullyImplemented()) + it->second = true; } + // Set to not fully implemented if at least one flag is false. for (auto const& it: functions) - if (!it.second) - { - setFullyImplemented(false); - break; - } + for (auto const& funAndFlag: it.second) + if (!funAndFlag.second) + { + setFullyImplemented(false); + return; + } } void ContractDefinition::checkAbstractConstructors() diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index df976eaea..4914ef975 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -403,6 +403,23 @@ BOOST_AUTO_TEST_CASE(abstract_contract) BOOST_CHECK(derived->getDefinedFunctions()[0]->isFullyImplemented()); } +BOOST_AUTO_TEST_CASE(abstract_contract_with_overload) +{ + ASTPointer sourceUnit; + char const* text = R"( + contract base { function foo(bool); } + contract derived is base { function foo(uint) {} } + )"; + ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed"); + std::vector> nodes = sourceUnit->getNodes(); + ContractDefinition* base = dynamic_cast(nodes[0].get()); + ContractDefinition* derived = dynamic_cast(nodes[1].get()); + BOOST_REQUIRE(base); + BOOST_CHECK(!base->isFullyImplemented()); + BOOST_REQUIRE(derived); + BOOST_CHECK(!derived->isFullyImplemented()); +} + BOOST_AUTO_TEST_CASE(create_abstract_contract) { ASTPointer sourceUnit;