mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Make members context-sensitive.
This commit is contained in:
parent
c498dcce22
commit
86495dfc57
@ -64,7 +64,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
{
|
{
|
||||||
m_currentScope = &m_scopes[nullptr];
|
m_currentScope = &m_scopes[nullptr];
|
||||||
|
|
||||||
ReferencesResolver resolver(m_errors, *this, &_contract, nullptr);
|
ReferencesResolver resolver(m_errors, *this, nullptr);
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts())
|
for (ASTPointer<InheritanceSpecifier> const& baseContract: _contract.baseContracts())
|
||||||
if (!resolver.resolve(*baseContract))
|
if (!resolver.resolve(*baseContract))
|
||||||
@ -100,7 +100,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
||||||
{
|
{
|
||||||
m_currentScope = &m_scopes[modifier.get()];
|
m_currentScope = &m_scopes[modifier.get()];
|
||||||
ReferencesResolver resolver(m_errors, *this, &_contract, nullptr);
|
ReferencesResolver resolver(m_errors, *this, nullptr);
|
||||||
if (!resolver.resolve(*modifier))
|
if (!resolver.resolve(*modifier))
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@ -111,7 +111,6 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
if (!ReferencesResolver(
|
if (!ReferencesResolver(
|
||||||
m_errors,
|
m_errors,
|
||||||
*this,
|
*this,
|
||||||
&_contract,
|
|
||||||
function->returnParameterList().get()
|
function->returnParameterList().get()
|
||||||
).resolve(*function))
|
).resolve(*function))
|
||||||
success = false;
|
success = false;
|
||||||
@ -126,7 +125,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
for (ASTPointer<ModifierDefinition> const& modifier: _contract.functionModifiers())
|
||||||
{
|
{
|
||||||
m_currentScope = &m_scopes[modifier.get()];
|
m_currentScope = &m_scopes[modifier.get()];
|
||||||
ReferencesResolver resolver(m_errors, *this, &_contract, nullptr, true);
|
ReferencesResolver resolver(m_errors, *this, nullptr, true);
|
||||||
if (!resolver.resolve(*modifier))
|
if (!resolver.resolve(*modifier))
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@ -137,7 +136,6 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
if (!ReferencesResolver(
|
if (!ReferencesResolver(
|
||||||
m_errors,
|
m_errors,
|
||||||
*this,
|
*this,
|
||||||
&_contract,
|
|
||||||
function->returnParameterList().get(),
|
function->returnParameterList().get(),
|
||||||
true
|
true
|
||||||
).resolve(*function))
|
).resolve(*function))
|
||||||
|
@ -50,7 +50,6 @@ bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
|
|||||||
|
|
||||||
_typeName.annotation().referencedDeclaration = declaration;
|
_typeName.annotation().referencedDeclaration = declaration;
|
||||||
|
|
||||||
_typeName.annotation().contractScope = m_currentContract;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,10 +72,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
|||||||
if (declarations.empty())
|
if (declarations.empty())
|
||||||
fatalDeclarationError(_identifier.location(), "Undeclared identifier.");
|
fatalDeclarationError(_identifier.location(), "Undeclared identifier.");
|
||||||
else if (declarations.size() == 1)
|
else if (declarations.size() == 1)
|
||||||
{
|
|
||||||
_identifier.annotation().referencedDeclaration = declarations.front();
|
_identifier.annotation().referencedDeclaration = declarations.front();
|
||||||
_identifier.annotation().contractScope = m_currentContract;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
_identifier.annotation().overloadedDeclarations =
|
_identifier.annotation().overloadedDeclarations =
|
||||||
m_resolver.cleanedDeclarations(_identifier, declarations);
|
m_resolver.cleanedDeclarations(_identifier, declarations);
|
||||||
|
@ -45,13 +45,11 @@ public:
|
|||||||
ReferencesResolver(
|
ReferencesResolver(
|
||||||
ErrorList& _errors,
|
ErrorList& _errors,
|
||||||
NameAndTypeResolver& _resolver,
|
NameAndTypeResolver& _resolver,
|
||||||
ContractDefinition const* _currentContract,
|
|
||||||
ParameterList const* _returnParameters,
|
ParameterList const* _returnParameters,
|
||||||
bool _resolveInsideCode = false
|
bool _resolveInsideCode = false
|
||||||
):
|
):
|
||||||
m_errors(_errors),
|
m_errors(_errors),
|
||||||
m_resolver(_resolver),
|
m_resolver(_resolver),
|
||||||
m_currentContract(_currentContract),
|
|
||||||
m_returnParameters(_returnParameters),
|
m_returnParameters(_returnParameters),
|
||||||
m_resolveInsideCode(_resolveInsideCode)
|
m_resolveInsideCode(_resolveInsideCode)
|
||||||
{}
|
{}
|
||||||
@ -83,7 +81,6 @@ private:
|
|||||||
|
|
||||||
ErrorList& m_errors;
|
ErrorList& m_errors;
|
||||||
NameAndTypeResolver& m_resolver;
|
NameAndTypeResolver& m_resolver;
|
||||||
ContractDefinition const* m_currentContract;
|
|
||||||
ParameterList const* m_returnParameters;
|
ParameterList const* m_returnParameters;
|
||||||
bool const m_resolveInsideCode;
|
bool const m_resolveInsideCode;
|
||||||
bool m_errorOccurred = false;
|
bool m_errorOccurred = false;
|
||||||
|
@ -60,6 +60,8 @@ TypePointer const& TypeChecker::type(VariableDeclaration const& _variable) const
|
|||||||
|
|
||||||
bool TypeChecker::visit(ContractDefinition const& _contract)
|
bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
|
m_scope = &_contract;
|
||||||
|
|
||||||
// We force our own visiting order here.
|
// We force our own visiting order here.
|
||||||
ASTNode::listAccept(_contract.definedStructs(), *this);
|
ASTNode::listAccept(_contract.definedStructs(), *this);
|
||||||
ASTNode::listAccept(_contract.baseContracts(), *this);
|
ASTNode::listAccept(_contract.baseContracts(), *this);
|
||||||
@ -1057,13 +1059,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
|||||||
if (!contract->annotation().isFullyImplemented)
|
if (!contract->annotation().isFullyImplemented)
|
||||||
typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
|
typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
|
||||||
|
|
||||||
auto scopeContract = contractName->annotation().contractScope;
|
solAssert(!!m_scope, "");
|
||||||
scopeContract->annotation().contractDependencies.insert(contract);
|
m_scope->annotation().contractDependencies.insert(contract);
|
||||||
solAssert(
|
solAssert(
|
||||||
!contract->annotation().linearizedBaseContracts.empty(),
|
!contract->annotation().linearizedBaseContracts.empty(),
|
||||||
"Linearized base contracts not yet available."
|
"Linearized base contracts not yet available."
|
||||||
);
|
);
|
||||||
if (contractDependenciesAreCyclic(*scopeContract))
|
if (contractDependenciesAreCyclic(*m_scope))
|
||||||
typeError(
|
typeError(
|
||||||
_newExpression.location(),
|
_newExpression.location(),
|
||||||
"Circular reference for contract creation (cannot create instance of derived or same contract)."
|
"Circular reference for contract creation (cannot create instance of derived or same contract)."
|
||||||
@ -1112,7 +1114,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
|
|
||||||
// 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& argumentTypes = _memberAccess.annotation().argumentTypes;
|
auto const& argumentTypes = _memberAccess.annotation().argumentTypes;
|
||||||
MemberList::MemberMap possibleMembers = exprType->members().membersByName(memberName);
|
MemberList::MemberMap possibleMembers = exprType->members(m_scope).membersByName(memberName);
|
||||||
if (possibleMembers.size() > 1 && argumentTypes)
|
if (possibleMembers.size() > 1 && argumentTypes)
|
||||||
{
|
{
|
||||||
// do overload resolution
|
// do overload resolution
|
||||||
@ -1131,7 +1133,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
DataLocation::Storage,
|
DataLocation::Storage,
|
||||||
exprType
|
exprType
|
||||||
);
|
);
|
||||||
if (!storageType->members().membersByName(memberName).empty())
|
if (!storageType->members(m_scope).membersByName(memberName).empty())
|
||||||
fatalTypeError(
|
fatalTypeError(
|
||||||
_memberAccess.location(),
|
_memberAccess.location(),
|
||||||
"Member \"" + memberName + "\" is not available in " +
|
"Member \"" + memberName + "\" is not available in " +
|
||||||
@ -1258,7 +1260,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
|||||||
|
|
||||||
for (Declaration const* declaration: annotation.overloadedDeclarations)
|
for (Declaration const* declaration: annotation.overloadedDeclarations)
|
||||||
{
|
{
|
||||||
TypePointer function = declaration->type(_identifier.annotation().contractScope);
|
TypePointer function = declaration->type();
|
||||||
solAssert(!!function, "Requested type not present.");
|
solAssert(!!function, "Requested type not present.");
|
||||||
auto const* functionType = dynamic_cast<FunctionType const*>(function.get());
|
auto const* functionType = dynamic_cast<FunctionType const*>(function.get());
|
||||||
if (functionType && functionType->canTakeArguments(*annotation.argumentTypes))
|
if (functionType && functionType->canTakeArguments(*annotation.argumentTypes))
|
||||||
@ -1277,7 +1279,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
|||||||
"Referenced declaration is null after overload resolution."
|
"Referenced declaration is null after overload resolution."
|
||||||
);
|
);
|
||||||
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
||||||
annotation.type = annotation.referencedDeclaration->type(_identifier.annotation().contractScope);
|
annotation.type = annotation.referencedDeclaration->type();
|
||||||
if (!annotation.type)
|
if (!annotation.type)
|
||||||
fatalTypeError(_identifier.location(), "Declaration referenced before type could be determined.");
|
fatalTypeError(_identifier.location(), "Declaration referenced before type could be determined.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -117,6 +117,8 @@ private:
|
|||||||
/// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
|
/// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
|
||||||
void requireLValue(Expression const& _expression);
|
void requireLValue(Expression const& _expression);
|
||||||
|
|
||||||
|
ContractDefinition const* m_scope = nullptr;
|
||||||
|
|
||||||
ErrorList& m_errors;
|
ErrorList& m_errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -188,9 +188,9 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
|
|||||||
return *m_inheritableMembers;
|
return *m_inheritableMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract) const
|
TypePointer ContractDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<TypeType>(make_shared<ContractType>(*this), m_currentContract);
|
return make_shared<TypeType>(make_shared<ContractType>(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
ContractDefinitionAnnotation& ContractDefinition::annotation() const
|
ContractDefinitionAnnotation& ContractDefinition::annotation() const
|
||||||
@ -207,7 +207,7 @@ TypeNameAnnotation& TypeName::annotation() const
|
|||||||
return static_cast<TypeNameAnnotation&>(*m_annotation);
|
return static_cast<TypeNameAnnotation&>(*m_annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer StructDefinition::type(ContractDefinition const*) const
|
TypePointer StructDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<TypeType>(make_shared<StructType>(*this));
|
return make_shared<TypeType>(make_shared<StructType>(*this));
|
||||||
}
|
}
|
||||||
@ -219,14 +219,14 @@ TypeDeclarationAnnotation& StructDefinition::annotation() const
|
|||||||
return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
|
return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer EnumValue::type(ContractDefinition const*) const
|
TypePointer EnumValue::type() const
|
||||||
{
|
{
|
||||||
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
|
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
|
||||||
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
|
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
|
||||||
return make_shared<EnumType>(*parentDef);
|
return make_shared<EnumType>(*parentDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer EnumDefinition::type(ContractDefinition const*) const
|
TypePointer EnumDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<TypeType>(make_shared<EnumType>(*this));
|
return make_shared<TypeType>(make_shared<EnumType>(*this));
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const
|
|||||||
return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
|
return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer FunctionDefinition::type(ContractDefinition const*) const
|
TypePointer FunctionDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<FunctionType>(*this);
|
return make_shared<FunctionType>(*this);
|
||||||
}
|
}
|
||||||
@ -255,7 +255,7 @@ FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
|
|||||||
return static_cast<FunctionDefinitionAnnotation&>(*m_annotation);
|
return static_cast<FunctionDefinitionAnnotation&>(*m_annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer ModifierDefinition::type(ContractDefinition const*) const
|
TypePointer ModifierDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<ModifierType>(*this);
|
return make_shared<ModifierType>(*this);
|
||||||
}
|
}
|
||||||
@ -267,7 +267,7 @@ ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
|
|||||||
return static_cast<ModifierDefinitionAnnotation&>(*m_annotation);
|
return static_cast<ModifierDefinitionAnnotation&>(*m_annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer EventDefinition::type(ContractDefinition const*) const
|
TypePointer EventDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<FunctionType>(*this);
|
return make_shared<FunctionType>(*this);
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ bool VariableDeclaration::canHaveAutoType() const
|
|||||||
return (!!callable && !isCallableParameter());
|
return (!!callable && !isCallableParameter());
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer VariableDeclaration::type(ContractDefinition const*) const
|
TypePointer VariableDeclaration::type() const
|
||||||
{
|
{
|
||||||
return annotation().type;
|
return annotation().type;
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ public:
|
|||||||
/// The current contract has to be given since this context can change the type, especially of
|
/// The current contract has to be given since this context can change the type, especially of
|
||||||
/// contract types.
|
/// contract types.
|
||||||
/// This can only be called once types of variable declarations have already been resolved.
|
/// This can only be called once types of variable declarations have already been resolved.
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract = nullptr) const = 0;
|
virtual TypePointer type() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Visibility defaultVisibility() const { return Visibility::Public; }
|
virtual Visibility defaultVisibility() const { return Visibility::Public; }
|
||||||
@ -290,7 +290,7 @@ public:
|
|||||||
std::string const& devDocumentation() const;
|
std::string const& devDocumentation() const;
|
||||||
void setDevDocumentation(std::string const& _devDocumentation);
|
void setDevDocumentation(std::string const& _devDocumentation);
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual ContractDefinitionAnnotation& annotation() const override;
|
virtual ContractDefinitionAnnotation& annotation() const override;
|
||||||
|
|
||||||
@ -350,7 +350,7 @@ public:
|
|||||||
|
|
||||||
std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
|
std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual TypeDeclarationAnnotation& annotation() const override;
|
virtual TypeDeclarationAnnotation& annotation() const override;
|
||||||
|
|
||||||
@ -372,7 +372,7 @@ public:
|
|||||||
|
|
||||||
std::vector<ASTPointer<EnumValue>> const& members() const { return m_members; }
|
std::vector<ASTPointer<EnumValue>> const& members() const { return m_members; }
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual TypeDeclarationAnnotation& annotation() const override;
|
virtual TypeDeclarationAnnotation& annotation() const override;
|
||||||
|
|
||||||
@ -392,7 +392,7 @@ public:
|
|||||||
virtual void accept(ASTVisitor& _visitor) override;
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
virtual void accept(ASTConstVisitor& _visitor) const override;
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -490,7 +490,7 @@ public:
|
|||||||
/// arguments separated by commas all enclosed in parentheses without any spaces.
|
/// arguments separated by commas all enclosed in parentheses without any spaces.
|
||||||
std::string externalSignature() const;
|
std::string externalSignature() const;
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual FunctionDefinitionAnnotation& annotation() const override;
|
virtual FunctionDefinitionAnnotation& annotation() const override;
|
||||||
|
|
||||||
@ -551,7 +551,7 @@ public:
|
|||||||
bool isConstant() const { return m_isConstant; }
|
bool isConstant() const { return m_isConstant; }
|
||||||
Location referenceLocation() const { return m_location; }
|
Location referenceLocation() const { return m_location; }
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual VariableDeclarationAnnotation& annotation() const override;
|
virtual VariableDeclarationAnnotation& annotation() const override;
|
||||||
|
|
||||||
@ -593,7 +593,7 @@ public:
|
|||||||
|
|
||||||
Block const& body() const { return *m_body; }
|
Block const& body() const { return *m_body; }
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual ModifierDefinitionAnnotation& annotation() const override;
|
virtual ModifierDefinitionAnnotation& annotation() const override;
|
||||||
|
|
||||||
@ -649,7 +649,7 @@ public:
|
|||||||
|
|
||||||
bool isAnonymous() const { return m_anonymous; }
|
bool isAnonymous() const { return m_anonymous; }
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
virtual TypePointer type() const override;
|
||||||
|
|
||||||
virtual EventDefinitionAnnotation& annotation() const override;
|
virtual EventDefinitionAnnotation& annotation() const override;
|
||||||
|
|
||||||
@ -675,7 +675,7 @@ public:
|
|||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST."));
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST."));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual TypePointer type(ContractDefinition const*) const override { return m_type; }
|
virtual TypePointer type() const override { return m_type; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Type const> m_type;
|
std::shared_ptr<Type const> m_type;
|
||||||
|
@ -138,9 +138,6 @@ struct ExpressionAnnotation: ASTAnnotation
|
|||||||
|
|
||||||
struct IdentifierAnnotation: ExpressionAnnotation
|
struct IdentifierAnnotation: ExpressionAnnotation
|
||||||
{
|
{
|
||||||
/// Stores a reference to the current contract.
|
|
||||||
/// This is needed because types of base contracts change depending on the context.
|
|
||||||
ContractDefinition const* contractScope = nullptr;
|
|
||||||
/// 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;
|
||||||
/// List of possible declarations it could refer to.
|
/// List of possible declarations it could refer to.
|
||||||
|
@ -858,7 +858,7 @@ string ArrayType::canonicalName(bool _addDataLocation) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList const& ArrayType::members() const
|
MemberList const& ArrayType::members(ContractDefinition const*) const
|
||||||
{
|
{
|
||||||
if (!m_members)
|
if (!m_members)
|
||||||
{
|
{
|
||||||
@ -956,7 +956,7 @@ string ContractType::canonicalName(bool) const
|
|||||||
return m_contract.annotation().canonicalName;
|
return m_contract.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList const& ContractType::members() const
|
MemberList const& ContractType::members(ContractDefinition const*) const
|
||||||
{
|
{
|
||||||
// We need to lazy-initialize it because of recursive references.
|
// We need to lazy-initialize it because of recursive references.
|
||||||
if (!m_members)
|
if (!m_members)
|
||||||
@ -1064,7 +1064,7 @@ bool StructType::operator==(Type const& _other) const
|
|||||||
unsigned StructType::calldataEncodedSize(bool _padded) const
|
unsigned StructType::calldataEncodedSize(bool _padded) const
|
||||||
{
|
{
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
for (auto const& member: members())
|
for (auto const& member: members(nullptr))
|
||||||
if (!member.type->canLiveOutsideStorage())
|
if (!member.type->canLiveOutsideStorage())
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
@ -1080,7 +1080,7 @@ unsigned StructType::calldataEncodedSize(bool _padded) const
|
|||||||
u256 StructType::memorySize() const
|
u256 StructType::memorySize() const
|
||||||
{
|
{
|
||||||
u256 size;
|
u256 size;
|
||||||
for (auto const& member: members())
|
for (auto const& member: members(nullptr))
|
||||||
if (member.type->canLiveOutsideStorage())
|
if (member.type->canLiveOutsideStorage())
|
||||||
size += member.type->memoryHeadSize();
|
size += member.type->memoryHeadSize();
|
||||||
return size;
|
return size;
|
||||||
@ -1088,7 +1088,7 @@ u256 StructType::memorySize() const
|
|||||||
|
|
||||||
u256 StructType::storageSize() const
|
u256 StructType::storageSize() const
|
||||||
{
|
{
|
||||||
return max<u256>(1, members().storageSize());
|
return max<u256>(1, members(nullptr).storageSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
string StructType::toString(bool _short) const
|
string StructType::toString(bool _short) const
|
||||||
@ -1099,7 +1099,7 @@ string StructType::toString(bool _short) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList const& StructType::members() const
|
MemberList const& StructType::members(ContractDefinition const*) const
|
||||||
{
|
{
|
||||||
// We need to lazy-initialize it because of recursive references.
|
// We need to lazy-initialize it because of recursive references.
|
||||||
if (!m_members)
|
if (!m_members)
|
||||||
@ -1149,7 +1149,7 @@ FunctionTypePointer StructType::constructorType() const
|
|||||||
{
|
{
|
||||||
TypePointers paramTypes;
|
TypePointers paramTypes;
|
||||||
strings paramNames;
|
strings paramNames;
|
||||||
for (auto const& member: members())
|
for (auto const& member: members(nullptr))
|
||||||
{
|
{
|
||||||
if (!member.type->canLiveOutsideStorage())
|
if (!member.type->canLiveOutsideStorage())
|
||||||
continue;
|
continue;
|
||||||
@ -1167,7 +1167,7 @@ FunctionTypePointer StructType::constructorType() const
|
|||||||
|
|
||||||
pair<u256, unsigned> const& StructType::storageOffsetsOfMember(string const& _name) const
|
pair<u256, unsigned> const& StructType::storageOffsetsOfMember(string const& _name) const
|
||||||
{
|
{
|
||||||
auto const* offsets = members().memberStorageOffset(_name);
|
auto const* offsets = members(nullptr).memberStorageOffset(_name);
|
||||||
solAssert(offsets, "Storage offset of non-existing member requested.");
|
solAssert(offsets, "Storage offset of non-existing member requested.");
|
||||||
return *offsets;
|
return *offsets;
|
||||||
}
|
}
|
||||||
@ -1175,7 +1175,7 @@ pair<u256, unsigned> const& StructType::storageOffsetsOfMember(string const& _na
|
|||||||
u256 StructType::memoryOffsetOfMember(string const& _name) const
|
u256 StructType::memoryOffsetOfMember(string const& _name) const
|
||||||
{
|
{
|
||||||
u256 offset;
|
u256 offset;
|
||||||
for (auto const& member: members())
|
for (auto const& member: members(nullptr))
|
||||||
if (member.name == _name)
|
if (member.name == _name)
|
||||||
return offset;
|
return offset;
|
||||||
else
|
else
|
||||||
@ -1395,7 +1395,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
|||||||
vector<string> retParamNames;
|
vector<string> retParamNames;
|
||||||
if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
|
if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
|
||||||
{
|
{
|
||||||
for (auto const& member: structType->members())
|
for (auto const& member: structType->members(nullptr))
|
||||||
if (member.type->category() != Category::Mapping)
|
if (member.type->category() != Category::Mapping)
|
||||||
{
|
{
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(member.type.get()))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(member.type.get()))
|
||||||
@ -1533,7 +1533,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
|||||||
return make_shared<FunctionType>(paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_location, m_arbitraryParameters);
|
return make_shared<FunctionType>(paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_location, m_arbitraryParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList const& FunctionType::members() const
|
MemberList const& FunctionType::members(ContractDefinition const*) const
|
||||||
{
|
{
|
||||||
switch (m_location)
|
switch (m_location)
|
||||||
{
|
{
|
||||||
@ -1784,7 +1784,7 @@ unsigned TypeType::sizeOnStack() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList const& TypeType::members() const
|
MemberList const& TypeType::members(ContractDefinition const* _currentScope) const
|
||||||
{
|
{
|
||||||
// We need to lazy-initialize it because of recursive references.
|
// We need to lazy-initialize it because of recursive references.
|
||||||
if (!m_members)
|
if (!m_members)
|
||||||
@ -1800,9 +1800,9 @@ MemberList const& TypeType::members() const
|
|||||||
it.second->asMemberFunction(true), // use callcode
|
it.second->asMemberFunction(true), // use callcode
|
||||||
&it.second->declaration()
|
&it.second->declaration()
|
||||||
));
|
));
|
||||||
else if (m_currentContract != nullptr)
|
else if (_currentScope != nullptr)
|
||||||
{
|
{
|
||||||
auto const& currentBases = m_currentContract->annotation().linearizedBaseContracts;
|
auto const& currentBases = _currentScope->annotation().linearizedBaseContracts;
|
||||||
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
|
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
|
||||||
// We are accessing the type of a base contract, so add all public and protected
|
// We are accessing the type of a base contract, so add all public and protected
|
||||||
// members. Note that this does not add inherited functions on purpose.
|
// members. Note that this does not add inherited functions on purpose.
|
||||||
|
@ -217,9 +217,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of all members of this type. Default implementation: no members.
|
/// Returns the list of all members of this type. Default implementation: no members.
|
||||||
virtual MemberList const& members() const { return EmptyMemberList; }
|
/// @param _currentScope scope in which the members are accessed.
|
||||||
|
virtual MemberList const& members(ContractDefinition const* /*_currentScope*/) const { return EmptyMemberList; }
|
||||||
/// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
|
/// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
|
||||||
TypePointer memberType(std::string const& _name) const { return members().memberType(_name); }
|
TypePointer memberType(std::string const& _name, ContractDefinition const* _currentScope = nullptr) const
|
||||||
|
{
|
||||||
|
return members(_currentScope).memberType(_name);
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::string toString(bool _short) const = 0;
|
virtual std::string toString(bool _short) const = 0;
|
||||||
std::string toString() const { return toString(false); }
|
std::string toString() const { return toString(false); }
|
||||||
@ -277,7 +281,10 @@ public:
|
|||||||
virtual unsigned storageBytes() const override { return m_bits / 8; }
|
virtual unsigned storageBytes() const override { return m_bits / 8; }
|
||||||
virtual bool isValueType() const override { return true; }
|
virtual bool isValueType() const override { return true; }
|
||||||
|
|
||||||
virtual MemberList const& members() const override { return isAddress() ? AddressMemberList : EmptyMemberList; }
|
virtual MemberList const& members(ContractDefinition const* /*_currentScope*/) const override
|
||||||
|
{
|
||||||
|
return isAddress() ? AddressMemberList : EmptyMemberList;
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
|
|
||||||
@ -510,7 +517,7 @@ public:
|
|||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||||
virtual MemberList const& members() const override;
|
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||||
virtual TypePointer encodingType() const override;
|
virtual TypePointer encodingType() const override;
|
||||||
virtual TypePointer decodingType() const override;
|
virtual TypePointer decodingType() const override;
|
||||||
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
||||||
@ -563,7 +570,7 @@ public:
|
|||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||||
|
|
||||||
virtual MemberList const& members() const override;
|
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||||
virtual TypePointer encodingType() const override
|
virtual TypePointer encodingType() const override
|
||||||
{
|
{
|
||||||
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
||||||
@ -616,7 +623,7 @@ public:
|
|||||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
|
|
||||||
virtual MemberList const& members() const override;
|
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||||
virtual TypePointer encodingType() const override
|
virtual TypePointer encodingType() const override
|
||||||
{
|
{
|
||||||
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : TypePointer();
|
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : TypePointer();
|
||||||
@ -810,7 +817,7 @@ public:
|
|||||||
virtual u256 storageSize() const override;
|
virtual u256 storageSize() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual MemberList const& members() const override;
|
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||||
|
|
||||||
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
|
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
|
||||||
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
|
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
|
||||||
@ -918,8 +925,7 @@ class TypeType: public Type
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Category category() const override { return Category::TypeType; }
|
virtual Category category() const override { return Category::TypeType; }
|
||||||
explicit TypeType(TypePointer const& _actualType, ContractDefinition const* _currentContract = nullptr):
|
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
|
||||||
m_actualType(_actualType), m_currentContract(_currentContract) {}
|
|
||||||
TypePointer const& actualType() const { return m_actualType; }
|
TypePointer const& actualType() const { return m_actualType; }
|
||||||
|
|
||||||
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
|
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
|
||||||
@ -929,12 +935,10 @@ public:
|
|||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
virtual std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
||||||
virtual MemberList const& members() const override;
|
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypePointer m_actualType;
|
TypePointer m_actualType;
|
||||||
/// Context in which this type is used (influences visibility etc.), can be nullptr.
|
|
||||||
ContractDefinition const* m_currentContract;
|
|
||||||
/// List of member types, will be lazy-initialized because of recursive references.
|
/// List of member types, will be lazy-initialized because of recursive references.
|
||||||
mutable std::unique_ptr<MemberList> m_members;
|
mutable std::unique_ptr<MemberList> m_members;
|
||||||
};
|
};
|
||||||
@ -983,7 +987,7 @@ public:
|
|||||||
virtual bool canBeStored() const override { return false; }
|
virtual bool canBeStored() const override { return false; }
|
||||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||||
virtual unsigned sizeOnStack() const override { return 0; }
|
virtual unsigned sizeOnStack() const override { return 0; }
|
||||||
virtual MemberList const& members() const override { return m_members; }
|
virtual MemberList const& members(ContractDefinition const*) const override { return m_members; }
|
||||||
|
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
|
|||||||
allocateMemory();
|
allocateMemory();
|
||||||
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
|
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
|
||||||
// stack: <memory ptr> <source ref> <memory ptr>
|
// stack: <memory ptr> <source ref> <memory ptr>
|
||||||
for (auto const& member: typeOnStack.members())
|
for (auto const& member: typeOnStack.members(nullptr))
|
||||||
{
|
{
|
||||||
if (!member.type->canLiveOutsideStorage())
|
if (!member.type->canLiveOutsideStorage())
|
||||||
continue;
|
continue;
|
||||||
@ -642,7 +642,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
|||||||
m_context << eth::Instruction::DUP1;
|
m_context << eth::Instruction::DUP1;
|
||||||
|
|
||||||
if (auto structType = dynamic_cast<StructType const*>(&_type))
|
if (auto structType = dynamic_cast<StructType const*>(&_type))
|
||||||
for (auto const& member: structType->members())
|
for (auto const& member: structType->members(nullptr))
|
||||||
{
|
{
|
||||||
pushZeroValue(*member.type);
|
pushZeroValue(*member.type);
|
||||||
storeInMemoryDynamic(*member.type);
|
storeInMemoryDynamic(*member.type);
|
||||||
|
@ -888,10 +888,6 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
|||||||
case Type::Category::TypeType:
|
case Type::Category::TypeType:
|
||||||
{
|
{
|
||||||
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.expression().annotation().type);
|
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.expression().annotation().type);
|
||||||
solAssert(
|
|
||||||
!type.members().membersByName(_memberAccess.memberName()).empty(),
|
|
||||||
"Invalid member access to " + type.toString(false)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (dynamic_cast<ContractType const*>(type.actualType().get()))
|
if (dynamic_cast<ContractType const*>(type.actualType().get()))
|
||||||
{
|
{
|
||||||
@ -1043,11 +1039,11 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
|
|||||||
Declaration const* declaration = _identifier.annotation().referencedDeclaration;
|
Declaration const* declaration = _identifier.annotation().referencedDeclaration;
|
||||||
if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
switch (magicVar->type(_identifier.annotation().contractScope)->category())
|
switch (magicVar->type()->category())
|
||||||
{
|
{
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
// "this" or "super"
|
// "this" or "super"
|
||||||
if (!dynamic_cast<ContractType const&>(*magicVar->type(_identifier.annotation().contractScope)).isSuper())
|
if (!dynamic_cast<ContractType const&>(*magicVar->type()).isSuper())
|
||||||
m_context << eth::Instruction::ADDRESS;
|
m_context << eth::Instruction::ADDRESS;
|
||||||
break;
|
break;
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
|
@ -273,7 +273,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
|||||||
"Struct assignment with conversion."
|
"Struct assignment with conversion."
|
||||||
);
|
);
|
||||||
solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
|
solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
|
||||||
for (auto const& member: structType.members())
|
for (auto const& member: structType.members(nullptr))
|
||||||
{
|
{
|
||||||
// assign each member that is not a mapping
|
// assign each member that is not a mapping
|
||||||
TypePointer const& memberType = member.type;
|
TypePointer const& memberType = member.type;
|
||||||
@ -336,7 +336,7 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
|
|||||||
// @todo this can be improved: use StorageItem for non-value types, and just store 0 in
|
// @todo this can be improved: use StorageItem for non-value types, and just store 0 in
|
||||||
// all slots that contain value types later.
|
// all slots that contain value types later.
|
||||||
auto const& structType = dynamic_cast<StructType const&>(*m_dataType);
|
auto const& structType = dynamic_cast<StructType const&>(*m_dataType);
|
||||||
for (auto const& member: structType.members())
|
for (auto const& member: structType.members(nullptr))
|
||||||
{
|
{
|
||||||
// zero each member that is not a mapping
|
// zero each member that is not a mapping
|
||||||
TypePointer const& memberType = member.type;
|
TypePointer const& memberType = member.type;
|
||||||
|
@ -120,7 +120,7 @@ string InterfaceHandler::ABISolidityInterface(ContractDefinition const& _contrac
|
|||||||
{
|
{
|
||||||
ret += "struct " + stru->name() + "{";
|
ret += "struct " + stru->name() + "{";
|
||||||
for (ASTPointer<VariableDeclaration> const& _member: stru->members())
|
for (ASTPointer<VariableDeclaration> const& _member: stru->members())
|
||||||
ret += _member->type(nullptr)->canonicalName(false) + " " + _member->name() + ";";
|
ret += _member->type()->canonicalName(false) + " " + _member->name() + ";";
|
||||||
ret += "}";
|
ret += "}";
|
||||||
}
|
}
|
||||||
for (auto const& enu: _contractDef.definedEnums())
|
for (auto const& enu: _contractDef.definedEnums())
|
||||||
|
Loading…
Reference in New Issue
Block a user