Browse Source

Explicit calls to base class function.

cl-refactor
Christian 10 years ago
parent
commit
4fe47c5014
  1. 5
      libsolidity/AST.cpp
  2. 19
      libsolidity/AST.h
  3. 34
      libsolidity/ExpressionCompiler.cpp
  4. 16
      libsolidity/NameAndTypeResolver.cpp
  5. 7
      libsolidity/NameAndTypeResolver.h
  6. 23
      libsolidity/Types.cpp
  7. 8
      libsolidity/Types.h
  8. 15
      test/SolidityEndToEndTest.cpp

5
libsolidity/AST.cpp

@ -373,7 +373,8 @@ void MemberAccess::checkTypeRequirements()
Type const& type = *m_expression->getType(); Type const& type = *m_expression->getType();
m_type = type.getMemberType(*m_memberName); m_type = type.getMemberType(*m_memberName);
if (!m_type) if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found in " + type.toString())); BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
"visible in " + type.toString()));
//@todo later, this will not always be STORAGE //@todo later, this will not always be STORAGE
m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE; m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE;
} }
@ -423,7 +424,7 @@ void Identifier::checkTypeRequirements()
ContractDefinition const* contractDef = dynamic_cast<ContractDefinition const*>(m_referencedDeclaration); ContractDefinition const* contractDef = dynamic_cast<ContractDefinition const*>(m_referencedDeclaration);
if (contractDef) if (contractDef)
{ {
m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef)); m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef), m_currentContract);
return; return;
} }
MagicVariableDeclaration const* magicVariable = dynamic_cast<MagicVariableDeclaration const*>(m_referencedDeclaration); MagicVariableDeclaration const* magicVariable = dynamic_cast<MagicVariableDeclaration const*>(m_referencedDeclaration);

19
libsolidity/AST.h

@ -595,7 +595,7 @@ public:
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; } void setFunctionReturnParameters(ParameterList const& _parameters) { m_returnParameters = &_parameters; }
ParameterList const& getFunctionReturnParameters() const ParameterList const& getFunctionReturnParameters() const
{ {
solAssert(m_returnParameters, ""); solAssert(m_returnParameters, "");
@ -607,7 +607,7 @@ private:
ASTPointer<Expression> m_expression; ///< value to return, optional ASTPointer<Expression> m_expression; ///< value to return, optional
/// Pointer to the parameter list of the function, filled by the @ref NameAndTypeResolver. /// Pointer to the parameter list of the function, filled by the @ref NameAndTypeResolver.
ParameterList* m_returnParameters; ParameterList const* m_returnParameters;
}; };
/** /**
@ -884,21 +884,30 @@ class Identifier: public PrimaryExpression
{ {
public: public:
Identifier(Location const& _location, ASTPointer<ASTString> const& _name): Identifier(Location const& _location, ASTPointer<ASTString> const& _name):
PrimaryExpression(_location), m_name(_name), m_referencedDeclaration(nullptr) {} PrimaryExpression(_location), m_name(_name) {}
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 void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
ASTString const& getName() const { return *m_name; } ASTString const& getName() const { return *m_name; }
void setReferencedDeclaration(Declaration const& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } void setReferencedDeclaration(Declaration const& _referencedDeclaration,
ContractDefinition const* _currentContract = nullptr)
{
m_referencedDeclaration = &_referencedDeclaration;
m_currentContract = _currentContract;
}
Declaration const* getReferencedDeclaration() const { return m_referencedDeclaration; } Declaration const* getReferencedDeclaration() const { return m_referencedDeclaration; }
ContractDefinition const* getCurrentContract() const { return m_currentContract; }
private: private:
ASTPointer<ASTString> m_name; ASTPointer<ASTString> m_name;
/// Declaration the name refers to. /// Declaration the name refers to.
Declaration const* m_referencedDeclaration; Declaration const* m_referencedDeclaration = nullptr;
/// Stores a reference to the current contract. This is needed because types of base contracts
/// change depending on the context.
ContractDefinition const* m_currentContract = nullptr;
}; };
/** /**

34
libsolidity/ExpressionCompiler.cpp

@ -419,6 +419,22 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
break; break;
} }
case Type::Category::TYPE:
{
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.getExpression().getType());
if (type.getMembers().getMemberType(member))
{
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*type.getActualType())
.getContractDefinition();
for (ASTPointer<FunctionDefinition> const& function: contract.getDefinedFunctions())
if (function->getName() == member)
{
m_context << m_context.getFunctionEntryLabel(*function).pushTag();
return;
}
}
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to " + type.toString()));
}
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type."));
} }
@ -449,20 +465,22 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
{ {
if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) // must be "this" if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) // must be "this"
m_context << eth::Instruction::ADDRESS; m_context << eth::Instruction::ADDRESS;
return;
} }
if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration)) else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
{
m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag(); m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag();
return; else if (dynamic_cast<VariableDeclaration const*>(declaration))
}
if (dynamic_cast<VariableDeclaration const*>(declaration))
{ {
m_currentLValue.fromIdentifier(_identifier, *declaration); m_currentLValue.fromIdentifier(_identifier, *declaration);
m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier);
return;
} }
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context.")); else if (dynamic_cast<ContractDefinition const*>(declaration))
{
// no-op
}
else
{
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context."));
}
} }
void ExpressionCompiler::endVisit(Literal const& _literal) void ExpressionCompiler::endVisit(Literal const& _literal)

16
libsolidity/NameAndTypeResolver.cpp

@ -49,7 +49,7 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
m_currentScope = &m_scopes[nullptr]; m_currentScope = &m_scopes[nullptr];
for (ASTPointer<Identifier> const& baseContract: _contract.getBaseContracts()) for (ASTPointer<Identifier> const& baseContract: _contract.getBaseContracts())
ReferencesResolver resolver(*baseContract, *this, nullptr); ReferencesResolver resolver(*baseContract, *this, &_contract, nullptr);
m_currentScope = &m_scopes[&_contract]; m_currentScope = &m_scopes[&_contract];
@ -58,13 +58,13 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
importInheritedScope(*base); importInheritedScope(*base);
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs()) for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
ReferencesResolver resolver(*structDef, *this, nullptr); ReferencesResolver resolver(*structDef, *this, &_contract, nullptr);
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables()) for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
ReferencesResolver resolver(*variable, *this, nullptr); ReferencesResolver resolver(*variable, *this, &_contract, nullptr);
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
{ {
m_currentScope = &m_scopes[function.get()]; m_currentScope = &m_scopes[function.get()];
ReferencesResolver referencesResolver(*function, *this, ReferencesResolver referencesResolver(*function, *this, &_contract,
function->getReturnParameterList().get()); function->getReturnParameterList().get());
} }
} }
@ -267,8 +267,10 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
} }
ReferencesResolver::ReferencesResolver(ASTNode& _root, NameAndTypeResolver& _resolver, ReferencesResolver::ReferencesResolver(ASTNode& _root, NameAndTypeResolver& _resolver,
ParameterList* _returnParameters, bool _allowLazyTypes): ContractDefinition const* _currentContract,
m_resolver(_resolver), m_returnParameters(_returnParameters), m_allowLazyTypes(_allowLazyTypes) ParameterList const* _returnParameters, bool _allowLazyTypes):
m_resolver(_resolver), m_currentContract(_currentContract),
m_returnParameters(_returnParameters), m_allowLazyTypes(_allowLazyTypes)
{ {
_root.accept(*this); _root.accept(*this);
} }
@ -316,7 +318,7 @@ bool ReferencesResolver::visit(Identifier& _identifier)
if (!declaration) if (!declaration)
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation())
<< errinfo_comment("Undeclared identifier.")); << errinfo_comment("Undeclared identifier."));
_identifier.setReferencedDeclaration(*declaration); _identifier.setReferencedDeclaration(*declaration, m_currentContract);
return false; return false;
} }

7
libsolidity/NameAndTypeResolver.h

@ -120,7 +120,9 @@ class ReferencesResolver: private ASTVisitor
{ {
public: public:
ReferencesResolver(ASTNode& _root, NameAndTypeResolver& _resolver, ReferencesResolver(ASTNode& _root, NameAndTypeResolver& _resolver,
ParameterList* _returnParameters, bool _allowLazyTypes = true); ContractDefinition const* _currentContract,
ParameterList const* _returnParameters,
bool _allowLazyTypes = true);
private: private:
virtual void endVisit(VariableDeclaration& _variable) override; virtual void endVisit(VariableDeclaration& _variable) override;
@ -130,7 +132,8 @@ private:
virtual bool visit(Return& _return) override; virtual bool visit(Return& _return) override;
NameAndTypeResolver& m_resolver; NameAndTypeResolver& m_resolver;
ParameterList* m_returnParameters; ContractDefinition const* m_currentContract;
ParameterList const* m_returnParameters;
bool m_allowLazyTypes; bool m_allowLazyTypes;
}; };

23
libsolidity/Types.cpp

@ -695,6 +695,29 @@ bool TypeType::operator==(Type const& _other) const
return *getActualType() == *other.getActualType(); return *getActualType() == *other.getActualType();
} }
MemberList const& TypeType::getMembers() const
{
// We need to lazy-initialize it because of recursive references.
if (!m_members)
{
map<string, TypePointer> members;
if (m_actualType->getCategory() == Category::CONTRACT && m_currentContract != nullptr)
{
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).getContractDefinition();
vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts();
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
// We are accessing the type of a base contract, so add all public and private
// functions. Note that this does not add inherited functions on purpose.
for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions())
if (f->getName() != contract.getName())
members[f->getName()] = make_shared<FunctionType>(*f);
}
m_members.reset(new MemberList(members));
}
return *m_members;
}
MagicType::MagicType(MagicType::Kind _kind): MagicType::MagicType(MagicType::Kind _kind):
m_kind(_kind) m_kind(_kind)
{ {

8
libsolidity/Types.h

@ -442,7 +442,8 @@ class TypeType: public Type
{ {
public: public:
virtual Category getCategory() const override { return Category::TYPE; } virtual Category getCategory() const override { return Category::TYPE; }
TypeType(TypePointer const& _actualType): m_actualType(_actualType) {} TypeType(TypePointer const& _actualType, ContractDefinition const* _currentContract = nullptr):
m_actualType(_actualType), m_currentContract(_currentContract) {}
TypePointer const& getActualType() const { return m_actualType; } TypePointer const& getActualType() 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(); }
@ -451,9 +452,14 @@ public:
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); }
virtual bool canLiveOutsideStorage() const override { return false; } virtual bool canLiveOutsideStorage() const override { return false; }
virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
virtual MemberList const& getMembers() 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.
mutable std::unique_ptr<MemberList> m_members;
}; };

15
test/SolidityEndToEndTest.cpp

@ -1553,6 +1553,21 @@ BOOST_AUTO_TEST_CASE(single_copy_with_multiple_inheritance)
BOOST_CHECK(callContractFunction("getViaB()") == encodeArgs(23)); BOOST_CHECK(callContractFunction("getViaB()") == encodeArgs(23));
} }
BOOST_AUTO_TEST_CASE(explicit_base_cass)
{
char const* sourceCode = R"(
contract BaseBase { function g() returns (uint r) { return 1; } }
contract Base is BaseBase { function g() returns (uint r) { return 2; } }
contract Derived is Base {
function f() returns (uint r) { return BaseBase.g(); }
function g() returns (uint r) { return 3; }
}
)";
compileAndRun(sourceCode, 0, "Derived");
BOOST_CHECK(callContractFunction("g()") == encodeArgs(3));
BOOST_CHECK(callContractFunction("f()") == encodeArgs(1));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save