mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add annotation field `requiresVirtualLookup
`
This commit is contained in:
parent
858b4507e2
commit
8584c98b6a
@ -125,7 +125,7 @@ bool ImmutableValidator::visit(WhileStatement const& _whileStatement)
|
|||||||
void ImmutableValidator::endVisit(Identifier const& _identifier)
|
void ImmutableValidator::endVisit(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
if (auto const callableDef = dynamic_cast<CallableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
if (auto const callableDef = dynamic_cast<CallableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||||
visitCallableIfNew(callableDef->resolveVirtual(m_currentContract));
|
visitCallableIfNew(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual ? callableDef->resolveVirtual(m_currentContract) : *callableDef);
|
||||||
if (auto const varDecl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
if (auto const varDecl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||||
analyseVariableReference(*varDecl, _identifier);
|
analyseVariableReference(*varDecl, _identifier);
|
||||||
}
|
}
|
||||||
|
@ -2544,8 +2544,10 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
TypePointer exprType = type(_memberAccess.expression());
|
TypePointer exprType = type(_memberAccess.expression());
|
||||||
ASTString const& memberName = _memberAccess.memberName();
|
ASTString const& memberName = _memberAccess.memberName();
|
||||||
|
|
||||||
|
auto& annotation = _memberAccess.annotation();
|
||||||
|
|
||||||
// Retrieve the types of the arguments if this is used to call a function.
|
// Retrieve the types of the arguments if this is used to call a function.
|
||||||
auto const& arguments = _memberAccess.annotation().arguments;
|
auto const& arguments = annotation.arguments;
|
||||||
MemberList::MemberMap possibleMembers = exprType->members(currentDefinitionScope()).membersByName(memberName);
|
MemberList::MemberMap possibleMembers = exprType->members(currentDefinitionScope()).membersByName(memberName);
|
||||||
size_t const initialMemberCount = possibleMembers.size();
|
size_t const initialMemberCount = possibleMembers.size();
|
||||||
if (initialMemberCount > 1 && arguments)
|
if (initialMemberCount > 1 && arguments)
|
||||||
@ -2561,8 +2563,6 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& annotation = _memberAccess.annotation();
|
|
||||||
|
|
||||||
annotation.isConstant = false;
|
annotation.isConstant = false;
|
||||||
|
|
||||||
if (possibleMembers.empty())
|
if (possibleMembers.empty())
|
||||||
@ -2661,6 +2661,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
annotation.referencedDeclaration = possibleMembers.front().declaration;
|
annotation.referencedDeclaration = possibleMembers.front().declaration;
|
||||||
annotation.type = possibleMembers.front().type;
|
annotation.type = possibleMembers.front().type;
|
||||||
|
|
||||||
|
VirtualLookup requiredLookup = VirtualLookup::Static;
|
||||||
|
|
||||||
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type))
|
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type))
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
@ -2679,8 +2681,15 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
_memberAccess.location(),
|
_memberAccess.location(),
|
||||||
"Using \"." + memberName + "(...)\" is deprecated. Use \"{" + memberName + ": ...}\" instead."
|
"Using \"." + memberName + "(...)\" is deprecated. Use \"{" + memberName + ": ...}\" instead."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!funType->bound())
|
||||||
|
if (auto contractType = dynamic_cast<ContractType const*>(exprType))
|
||||||
|
requiredLookup = contractType->isSuper() ? VirtualLookup::Super : VirtualLookup::Virtual;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
annotation.requiredLookup = requiredLookup;
|
||||||
|
|
||||||
if (auto const* structType = dynamic_cast<StructType const*>(exprType))
|
if (auto const* structType = dynamic_cast<StructType const*>(exprType))
|
||||||
annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData);
|
annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData);
|
||||||
else if (exprType->category() == Type::Category::Array)
|
else if (exprType->category() == Type::Category::Array)
|
||||||
@ -3076,6 +3085,10 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
|||||||
|
|
||||||
annotation.isConstant = isConstant;
|
annotation.isConstant = isConstant;
|
||||||
|
|
||||||
|
annotation.requiredLookup =
|
||||||
|
dynamic_cast<CallableDeclaration const*>(annotation.referencedDeclaration) ?
|
||||||
|
VirtualLookup::Virtual : VirtualLookup::Static;
|
||||||
|
|
||||||
// Check for deprecated function names.
|
// Check for deprecated function names.
|
||||||
// The check is done here for the case without an actual function call.
|
// The check is done here for the case without an actual function call.
|
||||||
if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type))
|
if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type))
|
||||||
|
@ -560,7 +560,10 @@ public:
|
|||||||
ASTPointer<UserDefinedTypeName> _baseName,
|
ASTPointer<UserDefinedTypeName> _baseName,
|
||||||
std::unique_ptr<std::vector<ASTPointer<Expression>>> _arguments
|
std::unique_ptr<std::vector<ASTPointer<Expression>>> _arguments
|
||||||
):
|
):
|
||||||
ASTNode(_id, _location), m_baseName(std::move(_baseName)), m_arguments(std::move(_arguments)) {}
|
ASTNode(_id, _location), m_baseName(std::move(_baseName)), m_arguments(std::move(_arguments))
|
||||||
|
{
|
||||||
|
solAssert(m_baseName != nullptr, "Name cannot be null.");
|
||||||
|
}
|
||||||
|
|
||||||
void accept(ASTVisitor& _visitor) override;
|
void accept(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const override;
|
void accept(ASTConstVisitor& _visitor) const override;
|
||||||
@ -590,7 +593,10 @@ public:
|
|||||||
ASTPointer<UserDefinedTypeName> _libraryName,
|
ASTPointer<UserDefinedTypeName> _libraryName,
|
||||||
ASTPointer<TypeName> _typeName
|
ASTPointer<TypeName> _typeName
|
||||||
):
|
):
|
||||||
ASTNode(_id, _location), m_libraryName(std::move(_libraryName)), m_typeName(std::move(_typeName)) {}
|
ASTNode(_id, _location), m_libraryName(std::move(_libraryName)), m_typeName(std::move(_typeName))
|
||||||
|
{
|
||||||
|
solAssert(m_libraryName != nullptr, "Name cannot be null.");
|
||||||
|
}
|
||||||
|
|
||||||
void accept(ASTVisitor& _visitor) override;
|
void accept(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const override;
|
void accept(ASTConstVisitor& _visitor) const override;
|
||||||
@ -1053,7 +1059,10 @@ public:
|
|||||||
ASTPointer<Identifier> _name,
|
ASTPointer<Identifier> _name,
|
||||||
std::unique_ptr<std::vector<ASTPointer<Expression>>> _arguments
|
std::unique_ptr<std::vector<ASTPointer<Expression>>> _arguments
|
||||||
):
|
):
|
||||||
ASTNode(_id, _location), m_modifierName(std::move(_name)), m_arguments(std::move(_arguments)) {}
|
ASTNode(_id, _location), m_modifierName(std::move(_name)), m_arguments(std::move(_arguments))
|
||||||
|
{
|
||||||
|
solAssert(m_modifierName != nullptr, "Name cannot be null.");
|
||||||
|
}
|
||||||
|
|
||||||
void accept(ASTVisitor& _visitor) override;
|
void accept(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const override;
|
void accept(ASTConstVisitor& _visitor) const override;
|
||||||
@ -1196,6 +1205,7 @@ class UserDefinedTypeName: public TypeName
|
|||||||
public:
|
public:
|
||||||
UserDefinedTypeName(int64_t _id, SourceLocation const& _location, std::vector<ASTString> _namePath):
|
UserDefinedTypeName(int64_t _id, SourceLocation const& _location, std::vector<ASTString> _namePath):
|
||||||
TypeName(_id, _location), m_namePath(std::move(_namePath)) {}
|
TypeName(_id, _location), m_namePath(std::move(_namePath)) {}
|
||||||
|
|
||||||
void accept(ASTVisitor& _visitor) override;
|
void accept(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const override;
|
void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
|
@ -264,6 +264,8 @@ struct IdentifierAnnotation: ExpressionAnnotation
|
|||||||
{
|
{
|
||||||
/// Referenced declaration, set at latest during overload resolution stage.
|
/// Referenced declaration, set at latest during overload resolution stage.
|
||||||
Declaration const* referencedDeclaration = nullptr;
|
Declaration const* referencedDeclaration = nullptr;
|
||||||
|
/// What kind of lookup needs to be done (static, virtual, super) find the declaration.
|
||||||
|
SetOnce<VirtualLookup> requiredLookup;
|
||||||
/// List of possible declarations it could refer to (can contain duplicates).
|
/// List of possible declarations it could refer to (can contain duplicates).
|
||||||
std::vector<Declaration const*> candidateDeclarations;
|
std::vector<Declaration const*> candidateDeclarations;
|
||||||
/// List of possible declarations it could refer to.
|
/// List of possible declarations it could refer to.
|
||||||
@ -274,6 +276,8 @@ struct MemberAccessAnnotation: ExpressionAnnotation
|
|||||||
{
|
{
|
||||||
/// Referenced declaration, set at latest during overload resolution stage.
|
/// Referenced declaration, set at latest during overload resolution stage.
|
||||||
Declaration const* referencedDeclaration = nullptr;
|
Declaration const* referencedDeclaration = nullptr;
|
||||||
|
/// What kind of lookup needs to be done (static, virtual, super) find the declaration.
|
||||||
|
SetOnce<VirtualLookup> requiredLookup;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BinaryOperationAnnotation: ExpressionAnnotation
|
struct BinaryOperationAnnotation: ExpressionAnnotation
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// Possible lookups for function resolving
|
||||||
|
enum class VirtualLookup { Static, Virtual, Super };
|
||||||
|
|
||||||
// How a function can mutate the EVM state.
|
// How a function can mutate the EVM state.
|
||||||
enum class StateMutability { Pure, View, NonPayable, Payable };
|
enum class StateMutability { Pure, View, NonPayable, Payable };
|
||||||
|
|
||||||
|
@ -1380,7 +1380,9 @@ private:
|
|||||||
bool const m_arbitraryParameters = false;
|
bool const m_arbitraryParameters = false;
|
||||||
bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
|
bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
|
||||||
bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
|
bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
|
||||||
bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn)
|
/// true iff the function is called as arg1.fun(arg2, ..., argn).
|
||||||
|
/// This is achieved through the "using for" directive.
|
||||||
|
bool const m_bound = false;
|
||||||
Declaration const* m_declaration = nullptr;
|
Declaration const* m_declaration = nullptr;
|
||||||
bool m_saltSet = false; ///< true iff the salt value to be used is on the stack
|
bool m_saltSet = false; ///< true iff the salt value to be used is on the stack
|
||||||
};
|
};
|
||||||
|
@ -1299,6 +1299,8 @@ void ContractCompiler::appendModifierOrFunctionCode()
|
|||||||
appendModifierOrFunctionCode();
|
appendModifierOrFunctionCode();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
solAssert(*modifierInvocation->name()->annotation().requiredLookup == VirtualLookup::Virtual, "");
|
||||||
|
|
||||||
ModifierDefinition const& modifier = dynamic_cast<ModifierDefinition const&>(
|
ModifierDefinition const& modifier = dynamic_cast<ModifierDefinition const&>(
|
||||||
*modifierInvocation->name()->annotation().referencedDeclaration
|
*modifierInvocation->name()->annotation().referencedDeclaration
|
||||||
).resolveVirtual(m_context.mostDerivedContract());
|
).resolveVirtual(m_context.mostDerivedContract());
|
||||||
|
@ -595,6 +595,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
// Do not directly visit the identifier, because this way, we can avoid
|
// Do not directly visit the identifier, because this way, we can avoid
|
||||||
// the runtime entry label to be created at the creation time context.
|
// the runtime entry label to be created at the creation time context.
|
||||||
CompilerContext::LocationSetter locationSetter2(m_context, *identifier);
|
CompilerContext::LocationSetter locationSetter2(m_context, *identifier);
|
||||||
|
solAssert(*identifier->annotation().requiredLookup == VirtualLookup::Virtual, "");
|
||||||
utils().pushCombinedFunctionEntryLabel(
|
utils().pushCombinedFunctionEntryLabel(
|
||||||
functionDef->resolveVirtual(m_context.mostDerivedContract()),
|
functionDef->resolveVirtual(m_context.mostDerivedContract()),
|
||||||
false
|
false
|
||||||
@ -1311,6 +1312,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
if (funType->kind() == FunctionType::Kind::Internal)
|
if (funType->kind() == FunctionType::Kind::Internal)
|
||||||
{
|
{
|
||||||
FunctionDefinition const& funDef = dynamic_cast<decltype(funDef)>(funType->declaration());
|
FunctionDefinition const& funDef = dynamic_cast<decltype(funDef)>(funType->declaration());
|
||||||
|
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
|
||||||
utils().pushCombinedFunctionEntryLabel(funDef);
|
utils().pushCombinedFunctionEntryLabel(funDef);
|
||||||
utils().moveIntoStack(funType->selfType()->sizeOnStack(), 1);
|
utils().moveIntoStack(funType->selfType()->sizeOnStack(), 1);
|
||||||
}
|
}
|
||||||
@ -1346,7 +1348,10 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
// internal library function call, this would push the library address forcing
|
// internal library function call, this would push the library address forcing
|
||||||
// us to link against it although we actually do not need it.
|
// us to link against it although we actually do not need it.
|
||||||
if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
|
if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
|
||||||
|
{
|
||||||
|
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
|
||||||
utils().pushCombinedFunctionEntryLabel(*function);
|
utils().pushCombinedFunctionEntryLabel(*function);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
solAssert(false, "Function not found in member access");
|
solAssert(false, "Function not found in member access");
|
||||||
break;
|
break;
|
||||||
@ -1460,6 +1465,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
if (type.isSuper())
|
if (type.isSuper())
|
||||||
{
|
{
|
||||||
solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
|
solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
|
||||||
|
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Super, "");
|
||||||
utils().pushCombinedFunctionEntryLabel(m_context.superFunction(
|
utils().pushCombinedFunctionEntryLabel(m_context.superFunction(
|
||||||
dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
|
dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
|
||||||
type.contractDefinition()
|
type.contractDefinition()
|
||||||
@ -1742,6 +1748,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
auto const* funDef = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration);
|
auto const* funDef = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration);
|
||||||
solAssert(funDef && funDef->isFree(), "");
|
solAssert(funDef && funDef->isFree(), "");
|
||||||
solAssert(funType->kind() == FunctionType::Kind::Internal, "");
|
solAssert(funType->kind() == FunctionType::Kind::Internal, "");
|
||||||
|
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
|
||||||
utils().pushCombinedFunctionEntryLabel(*funDef);
|
utils().pushCombinedFunctionEntryLabel(*funDef);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1933,11 +1940,14 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
||||||
|
{
|
||||||
// If the identifier is called right away, this code is executed in visit(FunctionCall...), because
|
// If the identifier is called right away, this code is executed in visit(FunctionCall...), because
|
||||||
// we want to avoid having a reference to the runtime function entry point in the
|
// we want to avoid having a reference to the runtime function entry point in the
|
||||||
// constructor context, since this would force the compiler to include unreferenced
|
// constructor context, since this would force the compiler to include unreferenced
|
||||||
// internal functions in the runtime context.
|
// internal functions in the runtime context.
|
||||||
|
solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, "");
|
||||||
utils().pushCombinedFunctionEntryLabel(functionDef->resolveVirtual(m_context.mostDerivedContract()));
|
utils().pushCombinedFunctionEntryLabel(functionDef->resolveVirtual(m_context.mostDerivedContract()));
|
||||||
|
}
|
||||||
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
appendVariable(*variable, static_cast<Expression const&>(_identifier));
|
appendVariable(*variable, static_cast<Expression const&>(_identifier));
|
||||||
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
|
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
|
@ -839,7 +839,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
solAssert(functionType->declaration() == *functionDef, "");
|
solAssert(functionType->declaration() == *functionDef, "");
|
||||||
|
|
||||||
if (identifier)
|
if (identifier)
|
||||||
|
{
|
||||||
|
solAssert(*identifier->annotation().requiredLookup == VirtualLookup::Virtual, "");
|
||||||
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract());
|
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ContractType const* type = dynamic_cast<ContractType const*>(memberAccess->expression().annotation().type);
|
ContractType const* type = dynamic_cast<ContractType const*>(memberAccess->expression().annotation().type);
|
||||||
@ -847,6 +850,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
ContractDefinition const* super = type->contractDefinition().superContract(m_context.mostDerivedContract());
|
ContractDefinition const* super = type->contractDefinition().superContract(m_context.mostDerivedContract());
|
||||||
solAssert(super, "Super contract not available.");
|
solAssert(super, "Super contract not available.");
|
||||||
|
solAssert(*memberAccess->annotation().requiredLookup == VirtualLookup::Super, "");
|
||||||
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract(), super);
|
functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract(), super);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2082,6 +2086,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
|||||||
}
|
}
|
||||||
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
|
solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, "");
|
||||||
FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract());
|
FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract());
|
||||||
define(_identifier) << to_string(resolvedFunctionDef.id()) << "\n";
|
define(_identifier) << to_string(resolvedFunctionDef.id()) << "\n";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user