Merge pull request #1811 from ethereum/unimplementedConstructors

Contract inheriting from base with unimplemented constructor is abstract.
This commit is contained in:
chriseth 2017-03-21 18:41:53 +01:00 committed by GitHub
commit d626876310
3 changed files with 19 additions and 1 deletions

View File

@ -3,6 +3,9 @@
Features: Features:
* Support ``interface`` contracts. * Support ``interface`` contracts.
Bugfixes:
* Type system: Contract inheriting from base with unimplemented constructor should be abstract.
### 0.4.10 (2017-03-15) ### 0.4.10 (2017-03-15)
Features: Features:

View File

@ -187,13 +187,20 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>; using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
map<string, vector<FunTypeAndFlag>> functions; map<string, vector<FunTypeAndFlag>> functions;
bool allBaseConstructorsImplemented = true;
// Search from base to derived // Search from base to derived
for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts)) for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
for (FunctionDefinition const* function: contract->definedFunctions()) for (FunctionDefinition const* function: contract->definedFunctions())
{ {
// Take constructors out of overload hierarchy // Take constructors out of overload hierarchy
if (function->isConstructor()) if (function->isConstructor())
{
if (!function->isImplemented())
// Base contract's constructor is not fully implemented, no way to get
// out of this.
allBaseConstructorsImplemented = false;
continue; continue;
}
auto& overloads = functions[function->name()]; auto& overloads = functions[function->name()];
FunctionTypePointer funType = make_shared<FunctionType>(*function); FunctionTypePointer funType = make_shared<FunctionType>(*function);
auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag) auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
@ -211,6 +218,9 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
it->second = true; it->second = true;
} }
if (!allBaseConstructorsImplemented)
_contract.annotation().isFullyImplemented = false;
// Set to not fully implemented if at least one flag is false. // Set to not fully implemented if at least one flag is false.
for (auto const& it: functions) for (auto const& it: functions)
for (auto const& funAndFlag: it.second) for (auto const& funAndFlag: it.second)

View File

@ -624,7 +624,12 @@ BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional)
function foo() {} function foo() {}
} }
)"; )";
ETH_TEST_REQUIRE_NO_THROW(parseAndAnalyse(text), "Parsing and name resolving failed"); ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name resolving failed");
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
BOOST_CHECK_EQUAL(nodes.size(), 4);
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[3].get());
BOOST_REQUIRE(derived);
BOOST_CHECK(!derived->annotation().isFullyImplemented);
} }
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided) BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided)