Constructors must be implemented if declared.

This commit is contained in:
Alex Beregszaszi 2017-08-04 20:38:45 +01:00
parent a372941a44
commit bb0eb57c2f
4 changed files with 15 additions and 47 deletions

View File

@ -6,6 +6,7 @@ Features:
Bugfixes: Bugfixes:
* Code Generator: ``.delegatecall()`` should always return execution outcome. * Code Generator: ``.delegatecall()`` should always return execution outcome.
* Code Generator: Provide "new account gas" for low-level ``callcode`` and ``delegatecall``. * Code Generator: Provide "new account gas" for low-level ``callcode`` and ``delegatecall``.
* Type Checker: Constructors must be implemented if declared.
* Type Checker: Do not mark overloaded functions as shadowing other functions. * Type Checker: Do not mark overloaded functions as shadowing other functions.
* Type Checker: Disallow the ``.gas()`` modifier on ``ecrecover``, ``sha256`` and ``ripemd160``. * Type Checker: Disallow the ``.gas()`` modifier on ``ecrecover``, ``sha256`` and ``ripemd160``.

View File

@ -192,13 +192,7 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
{ {
// 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.
_contract.annotation().unimplementedFunctions.push_back(function);
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)
@ -522,6 +516,8 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
} }
if (_function.isImplemented()) if (_function.isImplemented())
_function.body().accept(*this); _function.body().accept(*this);
else if (_function.isConstructor())
m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared.");
return false; return false;
} }

View File

@ -79,8 +79,7 @@ struct TypeDeclarationAnnotation: ASTAnnotation
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnotation struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnotation
{ {
/// List of functions without a body. Can also contain functions from base classes, /// List of functions without a body. Can also contain functions from base classes.
/// especially constructors.
std::vector<FunctionDefinition const*> unimplementedFunctions; std::vector<FunctionDefinition const*> unimplementedFunctions;
/// List of all (direct and indirect) base contracts in order from derived to /// List of all (direct and indirect) base contracts in order from derived to
/// base, including the contract itself. /// base, including the contract itself.

View File

@ -677,44 +677,6 @@ BOOST_AUTO_TEST_CASE(create_abstract_contract)
CHECK_ERROR(text, TypeError, ""); CHECK_ERROR(text, TypeError, "");
} }
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional)
{
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
contract BaseBase { function BaseBase(uint j); }
contract base is BaseBase { function foo(); }
contract derived is base {
function derived(uint i) BaseBase(i){}
function foo() {}
}
)";
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().unimplementedFunctions.empty());
}
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided)
{
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
contract BaseBase { function BaseBase(uint); }
contract base is BaseBase { function foo(); }
contract derived is base {
function derived(uint) {}
function foo() {}
}
)";
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().unimplementedFunctions.empty());
}
BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract) BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract)
{ {
ASTPointer<SourceUnit> sourceUnit; ASTPointer<SourceUnit> sourceUnit;
@ -5714,7 +5676,7 @@ BOOST_AUTO_TEST_CASE(interface_constructor)
function I(); function I();
} }
)"; )";
CHECK_ERROR(text, TypeError, "Constructor cannot be defined in interfaces"); CHECK_ERROR_ALLOW_MULTI(text, TypeError, "Constructor cannot be defined in interfaces");
} }
BOOST_AUTO_TEST_CASE(interface_functions) BOOST_AUTO_TEST_CASE(interface_functions)
@ -6564,6 +6526,16 @@ BOOST_AUTO_TEST_CASE(builtin_reject_value)
CHECK_ERROR(text, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup"); CHECK_ERROR(text, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup");
} }
BOOST_AUTO_TEST_CASE(constructor_without_implementation)
{
char const* text = R"(
contract C {
function C();
}
)";
CHECK_ERROR(text, TypeError, "Constructor must be implemented if declared.");
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }