From 0668a9ecfb60ab0e00bfb2c4a4a97ce523860832 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 1 Dec 2018 00:08:42 +0100 Subject: Public state variables are implementing external functions. --- Changelog.md | 1 + libsolidity/analysis/ContractLevelChecker.cpp | 53 +++++++++++++--------- .../implement_interface_by_public_variable.sol | 7 +++ ...lement_internal_function_by_public_variable.sol | 9 ++++ ...plement_private_function_by_public_variable.sol | 7 +++ ...mplement_public_function_by_public_variable.sol | 9 ++++ .../override/state_variable_function.sol | 1 + 7 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/implement_internal_function_by_public_variable.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/implement_private_function_by_public_variable.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/implement_public_function_by_public_variable.sol diff --git a/Changelog.md b/Changelog.md index 630801e4..7aa5a6be 100644 --- a/Changelog.md +++ b/Changelog.md @@ -27,6 +27,7 @@ Bugfixes: * Type Checker: Fixed internal error when trying to create abstract contract in some cases. * Type Checker: Fixed internal error related to double declaration of events. * Type Checker: Disallow inline arrays of mapping type. + * Type Checker: Consider abstract function to be implemented by public state variable. Build System: * Emscripten: Upgrade to Emscripten SDK 1.37.21 and boost 1.67. diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 58dcfe4d..6dc564de 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -219,29 +219,40 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con using FunTypeAndFlag = std::pair; map> functions; - // Search from base to derived - for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts)) - for (FunctionDefinition const* function: contract->definedFunctions()) + auto registerFunction = [&](Declaration const& _declaration, FunctionTypePointer const& _type, bool _implemented) + { + auto& overloads = functions[_declaration.name()]; + auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag) { - // Take constructors out of overload hierarchy - if (function->isConstructor()) - continue; - auto& overloads = functions[function->name()]; - FunctionTypePointer funType = make_shared(*function)->asCallableFunction(false); - auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag) - { - return funType->hasEqualParameterTypes(*_funAndFlag.first); - }); - if (it == overloads.end()) - overloads.push_back(make_pair(funType, function->isImplemented())); - else if (it->second) - { - if (!function->isImplemented()) - m_errorReporter.typeError(function->location(), "Redeclaring an already implemented function as abstract"); - } - else if (function->isImplemented()) - it->second = true; + return _type->hasEqualParameterTypes(*_funAndFlag.first); + }); + if (it == overloads.end()) + overloads.push_back(make_pair(_type, _implemented)); + else if (it->second) + { + if (!_implemented) + m_errorReporter.typeError(_declaration.location(), "Redeclaring an already implemented function as abstract"); } + else if (_implemented) + it->second = true; + }; + + // Search from base to derived, collect all functions and update + // the 'implemented' flag. + for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts)) + { + for (VariableDeclaration const* v: contract->stateVariables()) + if (v->isPartOfExternalInterface()) + registerFunction(*v, make_shared(*v), true); + + for (FunctionDefinition const* function: contract->definedFunctions()) + if (!function->isConstructor()) + registerFunction( + *function, + make_shared(*function)->asCallableFunction(false), + function->isImplemented() + ); + } // Set to not fully implemented if at least one flag is false. for (auto const& it: functions) diff --git a/test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol b/test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol new file mode 100644 index 00000000..49f7c33b --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol @@ -0,0 +1,7 @@ +interface X { function test() external returns (uint256); } +contract Y is X { + uint256 public test = 42; +} +contract T { + constructor() public { new Y(); } +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/implement_internal_function_by_public_variable.sol b/test/libsolidity/syntaxTests/inheritance/override/implement_internal_function_by_public_variable.sol new file mode 100644 index 00000000..32fac25c --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/implement_internal_function_by_public_variable.sol @@ -0,0 +1,9 @@ +contract X { function test() internal returns (uint256); } +contract Y is X { + uint256 public test = 42; +} +contract T { + constructor() public { new Y(); } +} +// ---- +// DeclarationError: (81-105): Identifier already declared. diff --git a/test/libsolidity/syntaxTests/inheritance/override/implement_private_function_by_public_variable.sol b/test/libsolidity/syntaxTests/inheritance/override/implement_private_function_by_public_variable.sol new file mode 100644 index 00000000..c58e24b6 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/implement_private_function_by_public_variable.sol @@ -0,0 +1,7 @@ +contract X { function test() private returns (uint256); } +contract Y is X { + uint256 public test = 42; +} +contract T { + constructor() public { new Y(); } +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/implement_public_function_by_public_variable.sol b/test/libsolidity/syntaxTests/inheritance/override/implement_public_function_by_public_variable.sol new file mode 100644 index 00000000..7a59c137 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/implement_public_function_by_public_variable.sol @@ -0,0 +1,9 @@ +contract X { function test() public returns (uint256); } +contract Y is X { + uint256 public test = 42; +} +contract T { + constructor() public { new Y(); } +} +// ---- +// DeclarationError: (79-103): Identifier already declared. diff --git a/test/libsolidity/syntaxTests/inheritance/override/state_variable_function.sol b/test/libsolidity/syntaxTests/inheritance/override/state_variable_function.sol index 0f05cc8e..fb7f3fbd 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/state_variable_function.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/state_variable_function.sol @@ -6,3 +6,4 @@ contract C is A { } // ---- // DeclarationError: (50-85): Identifier already declared. +// TypeError: (50-85): Redeclaring an already implemented function as abstract -- cgit v1.2.3