mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10307 from ethereum/fixQualifiedModifierLookup
Fix qualified modifier lookup.
This commit is contained in:
commit
6e3f817aac
@ -100,6 +100,11 @@ if they are marked ``virtual``. For details, please see
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
If you want to access a modifier ``m`` defined in a contract ``C``, you can use ``C.m`` to
|
||||||
|
reference it without virtual lookup. It is only possible to use modifiers defined in the current
|
||||||
|
contract or its base contracts. Modifiers can also be defined in libraries but their use is
|
||||||
|
limited to functions of the same library.
|
||||||
|
|
||||||
Multiple modifiers are applied to a function by specifying them in a
|
Multiple modifiers are applied to a function by specifying them in a
|
||||||
whitespace-separated list and are evaluated in the order presented.
|
whitespace-separated list and are evaluated in the order presented.
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ inheritanceSpecifierList:
|
|||||||
* Inheritance specifier for contracts and interfaces.
|
* Inheritance specifier for contracts and interfaces.
|
||||||
* Can optionally supply base constructor arguments.
|
* Can optionally supply base constructor arguments.
|
||||||
*/
|
*/
|
||||||
inheritanceSpecifier: name=userDefinedTypeName arguments=callArgumentList?;
|
inheritanceSpecifier: name=identifierPath arguments=callArgumentList?;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declarations that can be used in contracts, interfaces and libraries.
|
* Declarations that can be used in contracts, interfaces and libraries.
|
||||||
@ -98,15 +98,15 @@ namedArgument: name=identifier Colon value=expression;
|
|||||||
*/
|
*/
|
||||||
callArgumentList: LParen ((expression (Comma expression)*)? | LBrace (namedArgument (Comma namedArgument)*)? RBrace) RParen;
|
callArgumentList: LParen ((expression (Comma expression)*)? | LBrace (namedArgument (Comma namedArgument)*)? RBrace) RParen;
|
||||||
/**
|
/**
|
||||||
* Qualified name of a user defined type.
|
* Qualified name.
|
||||||
*/
|
*/
|
||||||
userDefinedTypeName: identifier (Period identifier)*;
|
identifierPath: identifier (Period identifier)*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call to a modifier. If the modifier takes no arguments, the argument list can be skipped entirely
|
* Call to a modifier. If the modifier takes no arguments, the argument list can be skipped entirely
|
||||||
* (including opening and closing parentheses).
|
* (including opening and closing parentheses).
|
||||||
*/
|
*/
|
||||||
modifierInvocation: identifier callArgumentList?;
|
modifierInvocation: identifierPath callArgumentList?;
|
||||||
/**
|
/**
|
||||||
* Visibility for functions and function types.
|
* Visibility for functions and function types.
|
||||||
*/
|
*/
|
||||||
@ -144,7 +144,7 @@ stateMutability: Pure | View | Payable;
|
|||||||
* In cases where there are ambiguous declarations in several base contracts being overridden,
|
* In cases where there are ambiguous declarations in several base contracts being overridden,
|
||||||
* a complete list of base contracts has to be given.
|
* a complete list of base contracts has to be given.
|
||||||
*/
|
*/
|
||||||
overrideSpecifier: Override (LParen overrides+=userDefinedTypeName (Comma overrides+=userDefinedTypeName)* RParen)?;
|
overrideSpecifier: Override (LParen overrides+=identifierPath (Comma overrides+=identifierPath)* RParen)?;
|
||||||
/**
|
/**
|
||||||
* The definition of contract, library and interface functions.
|
* The definition of contract, library and interface functions.
|
||||||
* Depending on the context in which the function is defined, further restrictions may apply,
|
* Depending on the context in which the function is defined, further restrictions may apply,
|
||||||
@ -269,12 +269,12 @@ eventDefinition:
|
|||||||
* Using directive to bind library functions to types.
|
* Using directive to bind library functions to types.
|
||||||
* Can occur within contracts and libraries.
|
* Can occur within contracts and libraries.
|
||||||
*/
|
*/
|
||||||
usingDirective: Using userDefinedTypeName For (Mul | typeName) Semicolon;
|
usingDirective: Using identifierPath For (Mul | typeName) Semicolon;
|
||||||
/**
|
/**
|
||||||
* A type name can be an elementary type, a function type, a mapping type, a user-defined type
|
* A type name can be an elementary type, a function type, a mapping type, a user-defined type
|
||||||
* (e.g. a contract or struct) or an array type.
|
* (e.g. a contract or struct) or an array type.
|
||||||
*/
|
*/
|
||||||
typeName: elementaryTypeName[true] | functionTypeName | mappingType | userDefinedTypeName | typeName LBrack expression? RBrack;
|
typeName: elementaryTypeName[true] | functionTypeName | mappingType | identifierPath | typeName LBrack expression? RBrack;
|
||||||
elementaryTypeName[boolean allowAddressPayable]: Address | {$allowAddressPayable}? Address Payable | Bool | String | Bytes | SignedIntegerType | UnsignedIntegerType | FixedBytes | Fixed | Ufixed;
|
elementaryTypeName[boolean allowAddressPayable]: Address | {$allowAddressPayable}? Address Payable | Bool | String | Bytes | SignedIntegerType | UnsignedIntegerType | FixedBytes | Fixed | Ufixed;
|
||||||
functionTypeName
|
functionTypeName
|
||||||
locals [boolean visibilitySet = false, boolean mutabilitySet = false]
|
locals [boolean visibilitySet = false, boolean mutabilitySet = false]
|
||||||
@ -329,7 +329,6 @@ expression:
|
|||||||
identifier
|
identifier
|
||||||
| literal
|
| literal
|
||||||
| elementaryTypeName[false]
|
| elementaryTypeName[false]
|
||||||
| userDefinedTypeName
|
|
||||||
) # PrimaryExpression
|
) # PrimaryExpression
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -452,7 +451,7 @@ mappingType: Mapping LParen key=mappingKeyType DoubleArrow value=typeName RParen
|
|||||||
/**
|
/**
|
||||||
* Only elementary types or user defined types are viable as mapping keys.
|
* Only elementary types or user defined types are viable as mapping keys.
|
||||||
*/
|
*/
|
||||||
mappingKeyType: elementaryTypeName[false] | userDefinedTypeName;
|
mappingKeyType: elementaryTypeName[false] | identifierPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Yul statement within an inline assembly block.
|
* A Yul statement within an inline assembly block.
|
||||||
|
@ -630,7 +630,19 @@ void TypeChecker::visitManually(
|
|||||||
vector<ASTPointer<VariableDeclaration>> emptyParameterList;
|
vector<ASTPointer<VariableDeclaration>> emptyParameterList;
|
||||||
vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
|
vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
|
||||||
if (auto modifierDecl = dynamic_cast<ModifierDefinition const*>(declaration))
|
if (auto modifierDecl = dynamic_cast<ModifierDefinition const*>(declaration))
|
||||||
|
{
|
||||||
parameters = &modifierDecl->parameters();
|
parameters = &modifierDecl->parameters();
|
||||||
|
if (auto const* modifierContract = dynamic_cast<ContractDefinition const*>(modifierDecl->scope()))
|
||||||
|
if (m_currentContract)
|
||||||
|
{
|
||||||
|
if (!contains(m_currentContract->annotation().linearizedBaseContracts, modifierContract))
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
9428_error,
|
||||||
|
_modifier.location(),
|
||||||
|
"Can only use modifiers defined in the current contract or in base contracts."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// check parameters for Base constructors
|
// check parameters for Base constructors
|
||||||
for (ContractDefinition const* base: _bases)
|
for (ContractDefinition const* base: _bases)
|
||||||
|
@ -1301,11 +1301,16 @@ void ContractCompiler::appendModifierOrFunctionCode()
|
|||||||
appendModifierOrFunctionCode();
|
appendModifierOrFunctionCode();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(*modifierInvocation->name().annotation().requiredLookup == VirtualLookup::Virtual, "");
|
ModifierDefinition const& referencedModifier = dynamic_cast<ModifierDefinition const&>(
|
||||||
|
|
||||||
ModifierDefinition const& modifier = dynamic_cast<ModifierDefinition const&>(
|
|
||||||
*modifierInvocation->name().annotation().referencedDeclaration
|
*modifierInvocation->name().annotation().referencedDeclaration
|
||||||
).resolveVirtual(m_context.mostDerivedContract());
|
);
|
||||||
|
VirtualLookup lookup = *modifierInvocation->name().annotation().requiredLookup;
|
||||||
|
solAssert(lookup == VirtualLookup::Virtual || lookup == VirtualLookup::Static, "");
|
||||||
|
ModifierDefinition const& modifier =
|
||||||
|
lookup == VirtualLookup::Virtual ?
|
||||||
|
referencedModifier.resolveVirtual(m_context.mostDerivedContract()) :
|
||||||
|
referencedModifier;
|
||||||
|
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, modifier);
|
CompilerContext::LocationSetter locationSetter(m_context, modifier);
|
||||||
std::vector<ASTPointer<Expression>> const& modifierArguments =
|
std::vector<ASTPointer<Expression>> const& modifierArguments =
|
||||||
modifierInvocation->arguments() ? *modifierInvocation->arguments() : std::vector<ASTPointer<Expression>>();
|
modifierInvocation->arguments() ? *modifierInvocation->arguments() : std::vector<ASTPointer<Expression>>();
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
contract A {
|
||||||
|
uint public x = 7;
|
||||||
|
modifier m virtual { x = 2; _; }
|
||||||
|
}
|
||||||
|
contract C is A {
|
||||||
|
modifier m override { x = 1; _; }
|
||||||
|
|
||||||
|
function f() public A.m returns (uint) {
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
function g() public m returns (uint) {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// x() -> 7
|
||||||
|
// f() -> 9
|
||||||
|
// x() -> 2
|
||||||
|
// g() -> 0x0a
|
||||||
|
// x() -> 1
|
||||||
|
// f() -> 9
|
||||||
|
// x() -> 2
|
@ -0,0 +1,25 @@
|
|||||||
|
==== Source: a ====
|
||||||
|
import "a" as M;
|
||||||
|
contract C {
|
||||||
|
uint public x;
|
||||||
|
modifier m { x = 1; _; }
|
||||||
|
|
||||||
|
function f() public M.M.C.m returns (uint t, uint r) {
|
||||||
|
t = x;
|
||||||
|
x = 3;
|
||||||
|
r = 9;
|
||||||
|
}
|
||||||
|
function g() public m returns (uint t, uint r) {
|
||||||
|
t = x;
|
||||||
|
x = 4;
|
||||||
|
r = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// x() -> 0x00
|
||||||
|
// f() -> 1, 9
|
||||||
|
// x() -> 3
|
||||||
|
// g() -> 1, 0x0a
|
||||||
|
// x() -> 4
|
||||||
|
// f() -> 1, 9
|
||||||
|
// x() -> 3
|
@ -0,0 +1,9 @@
|
|||||||
|
library L {
|
||||||
|
modifier m() { _; }
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
function f() L.m public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9428: (68-71): Can only use modifiers defined in the current contract or in base contracts.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
modifier m() { _; }
|
||||||
|
}
|
||||||
|
contract D {
|
||||||
|
function f() C.m public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9428: (69-72): Can only use modifiers defined in the current contract or in base contracts.
|
@ -0,0 +1,8 @@
|
|||||||
|
contract C {
|
||||||
|
modifier m() { _; }
|
||||||
|
}
|
||||||
|
contract D is C {
|
||||||
|
function f() C.m public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
@ -0,0 +1,11 @@
|
|||||||
|
contract A {}
|
||||||
|
contract C is A {
|
||||||
|
modifier m() { _; }
|
||||||
|
}
|
||||||
|
contract D is A {
|
||||||
|
function f() C.m public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract T is D, C {}
|
||||||
|
// ----
|
||||||
|
// TypeError 9428: (93-96): Can only use modifiers defined in the current contract or in base contracts.
|
10
test/libsolidity/syntaxTests/modifiers/library_via_using.sol
Normal file
10
test/libsolidity/syntaxTests/modifiers/library_via_using.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
library L {
|
||||||
|
modifier m() { _; }
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
using L for *;
|
||||||
|
function f() L.m public {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9428: (87-90): Can only use modifiers defined in the current contract or in base contracts.
|
Loading…
Reference in New Issue
Block a user