Merge pull request #5557 from ethereum/fixInterfaceImplementedByPublicStateVariable

Public state variables are implementing external functions.
This commit is contained in:
chriseth 2018-12-03 10:46:44 +01:00 committed by GitHub
commit 3f613a44ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 21 deletions

View File

@ -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.

View File

@ -219,29 +219,40 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con
using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
map<string, vector<FunTypeAndFlag>> 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<FunctionType>(*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<FunctionType>(*v), true);
for (FunctionDefinition const* function: contract->definedFunctions())
if (!function->isConstructor())
registerFunction(
*function,
make_shared<FunctionType>(*function)->asCallableFunction(false),
function->isImplemented()
);
}
// Set to not fully implemented if at least one flag is false.
for (auto const& it: functions)

View File

@ -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(); }
}

View File

@ -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.

View File

@ -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(); }
}

View File

@ -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.

View File

@ -6,3 +6,4 @@ contract C is A {
}
// ----
// DeclarationError: (50-85): Identifier already declared.
// TypeError: (50-85): Redeclaring an already implemented function as abstract