Ambigous overrides for modifiers.

This commit is contained in:
chriseth 2019-12-09 17:42:12 +01:00
parent 152f42c6b2
commit a5f7661075
5 changed files with 64 additions and 23 deletions

View File

@ -730,26 +730,40 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _
void ContractLevelChecker::checkAmbiguousOverrides(ContractDefinition const& _contract) const void ContractLevelChecker::checkAmbiguousOverrides(ContractDefinition const& _contract) const
{ {
// TODO same for modifiers. std::function<bool(CallableDeclaration const*, CallableDeclaration const*)> compareById =
[](auto const* _a, auto const* _b) { return _a->id() < _b->id(); };
// Fetch inherited functions and sort them by signature.
// We get at least one function per signature and direct base contract, which is
// enough because we re-construct the inheritance graph later.
FunctionMultiSet nonOverriddenFunctions = inheritedFunctions(_contract);
// Remove all functions that match the signature of a function in the current contract.
nonOverriddenFunctions -= _contract.definedFunctions();
// Walk through the set of functions signature by signature.
for (auto it = nonOverriddenFunctions.cbegin(); it != nonOverriddenFunctions.cend();)
{ {
std::function<bool(CallableDeclaration const*, CallableDeclaration const*)> compareById = [](auto const* a, auto const* b) { return a->id() < b->id(); }; // Fetch inherited functions and sort them by signature.
std::set<CallableDeclaration const*, std::function<bool(CallableDeclaration const*, CallableDeclaration const*)>> baseFunctions(compareById); // We get at least one function per signature and direct base contract, which is
for (auto nextSignature = nonOverriddenFunctions.upper_bound(*it); it != nextSignature; ++it) // enough because we re-construct the inheritance graph later.
baseFunctions.insert(*it); FunctionMultiSet nonOverriddenFunctions = inheritedFunctions(_contract);
// Remove all functions that match the signature of a function in the current contract.
nonOverriddenFunctions -= _contract.definedFunctions();
// Walk through the set of functions signature by signature.
for (auto it = nonOverriddenFunctions.cbegin(); it != nonOverriddenFunctions.cend();)
{
std::set<CallableDeclaration const*, decltype(compareById)> baseFunctions(compareById);
for (auto nextSignature = nonOverriddenFunctions.upper_bound(*it); it != nextSignature; ++it)
baseFunctions.insert(*it);
checkAmbiguousOverridesInternal(std::move(baseFunctions), _contract.location());
}
}
{
ModifierMultiSet modifiers = inheritedModifiers(_contract);
modifiers -= _contract.functionModifiers();
for (auto it = modifiers.cbegin(); it != modifiers.cend();)
{
std::set<CallableDeclaration const*, decltype(compareById)> baseModifiers(compareById);
for (auto next = modifiers.upper_bound(*it); it != next; ++it)
baseModifiers.insert(*it);
checkAmbiguousOverridesInternal(std::move(baseModifiers), _contract.location());
}
checkAmbiguousOverridesInternal(std::move(baseFunctions), _contract.location());
} }
} }
@ -869,10 +883,17 @@ void ContractLevelChecker::checkAmbiguousOverridesInternal(set<
} }
string callableName; string callableName;
string distinguishigProperty;
if (dynamic_cast<FunctionDefinition const*>(*_baseCallables.begin())) if (dynamic_cast<FunctionDefinition const*>(*_baseCallables.begin()))
{
callableName = "function"; callableName = "function";
distinguishigProperty = "name and parameter types";
}
else if (dynamic_cast<ModifierDefinition const*>(*_baseCallables.begin())) else if (dynamic_cast<ModifierDefinition const*>(*_baseCallables.begin()))
{
callableName = "modifier"; callableName = "modifier";
distinguishigProperty = "name";
}
else else
solAssert(false, "Invalid type for ambiguous override."); solAssert(false, "Invalid type for ambiguous override.");
@ -881,7 +902,7 @@ void ContractLevelChecker::checkAmbiguousOverridesInternal(set<
ssl, ssl,
"Derived contract must override " + callableName + " \"" + "Derived contract must override " + callableName + " \"" +
(*_baseCallables.begin())->name() + (*_baseCallables.begin())->name() +
"\". Two or more base classes define " + callableName + " with same name and parameter types." "\". Two or more base classes define " + callableName + " with same " + distinguishigProperty + "."
); );
} }

View File

@ -7,4 +7,4 @@ contract B {
contract C is A, B { contract C is A, B {
} }
// ---- // ----
// THIS NEEDS TO BE AN ERROR // TypeError: (94-116): Derived contract must override modifier "f". Two or more base classes define modifier with same name.

View File

@ -0,0 +1,10 @@
contract A {
modifier f(uint a) virtual { _; }
}
contract B {
modifier f() virtual { _; }
}
contract C is A, B {
}
// ----
// TypeError: (100-122): Derived contract must override modifier "f". Two or more base classes define modifier with same name.

View File

@ -0,0 +1,11 @@
contract A {
modifier f(uint a) virtual { _; }
}
contract B {
modifier f() virtual { _; }
}
contract C is A, B {
modifier f() virtual override(A, B) { _; }
}
// ----
// TypeError: (125-167): Override changes modifier signature.

View File

@ -1,8 +1,8 @@
contract I { contract I {
modifier f() { _; } modifier f() virtual { _; }
} }
contract J { contract J {
modifier f() { _; } modifier f() virtual { _; }
} }
contract IJ is I, J { contract IJ is I, J {
modifier f() virtual override (I, J) { _; } modifier f() virtual override (I, J) { _; }
@ -16,5 +16,4 @@ contract B is IJ
} }
contract C is A, B {} contract C is A, B {}
// ---- // ----
// TypeError: (14-33): Trying to override non-virtual modifier. Did you forget to add "virtual"? // TypeError: (229-250): Derived contract must override modifier "f". Two or more base classes define modifier with same name.
// TypeError: (50-69): Trying to override non-virtual modifier. Did you forget to add "virtual"?