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();
m_type = type.getMemberType(*m_memberName);
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
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);
if (contractDef)
{
m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef));
m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef), m_currentContract);
return;
}
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 checkTypeRequirements() override;
void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; }
void setFunctionReturnParameters(ParameterList const& _parameters) { m_returnParameters = &_parameters; }
ParameterList const& getFunctionReturnParameters() const
{
solAssert(m_returnParameters, "");
@ -607,7 +607,7 @@ private:
ASTPointer<Expression> m_expression; ///< value to return, optional
/// 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:
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(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
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; }
ContractDefinition const* getCurrentContract() const { return m_currentContract; }
private:
ASTPointer<ASTString> m_name;
/// 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);
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:
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"
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();
return;
}
if (dynamic_cast<VariableDeclaration const*>(declaration))
else if (dynamic_cast<VariableDeclaration const*>(declaration))
{
m_currentLValue.fromIdentifier(_identifier, *declaration);
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)

16
libsolidity/NameAndTypeResolver.cpp

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

7
libsolidity/NameAndTypeResolver.h

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

23
libsolidity/Types.cpp

@ -695,6 +695,29 @@ bool TypeType::operator==(Type const& _other) const
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):
m_kind(_kind)
{

8
libsolidity/Types.h

@ -442,7 +442,8 @@ class TypeType: public Type
{
public:
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; }
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 bool canLiveOutsideStorage() const override { return false; }
virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
virtual MemberList const& getMembers() const override;
private:
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_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()
}

Loading…
Cancel
Save