aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AST.cpp10
-rw-r--r--ExpressionCompiler.cpp5
-rw-r--r--Types.cpp49
-rw-r--r--Types.h47
4 files changed, 70 insertions, 41 deletions
diff --git a/AST.cpp b/AST.cpp
index 2972cb5c..9aecbded 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -462,14 +462,10 @@ void MemberAccess::checkTypeRequirements()
{
m_expression->checkTypeRequirements();
m_expression->requireLValue();
- if (m_expression->getType()->getCategory() != Type::Category::STRUCT)
- BOOST_THROW_EXCEPTION(createTypeError("Member access to a non-struct (is " +
- m_expression->getType()->toString() + ")"));
- StructType const& type = dynamic_cast<StructType const&>(*m_expression->getType());
- unsigned memberIndex = type.memberNameToIndex(*m_memberName);
- if (memberIndex >= type.getMemberCount())
+ 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()));
- m_type = type.getMemberByIndex(memberIndex);
m_isLvalue = true;
}
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index f37ce39c..89eeb31f 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -208,10 +208,7 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess)
if (asserts(m_currentLValue.isInStorage()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to a non-storage value."));
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
- unsigned memberIndex = type.memberNameToIndex(_memberAccess.getMemberName());
- if (asserts(memberIndex <= type.getMemberCount()))
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member not found in struct during compilation."));
- m_context << type.getStorageOffsetOfMember(memberIndex) << eth::Instruction::ADD;
+ m_context << type.getStorageOffsetOfMember(_memberAccess.getMemberName()) << eth::Instruction::ADD;
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
}
diff --git a/Types.cpp b/Types.cpp
index 79d4a1c1..897ca221 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -86,6 +86,8 @@ shared_ptr<Type> Type::forLiteral(Literal const& _literal)
}
}
+const MemberList Type::EmptyMemberList = MemberList();
+
shared_ptr<IntegerType> IntegerType::smallestTypeForLiteral(string const& _literal)
{
bigint value(_literal);
@@ -226,15 +228,15 @@ bool StructType::operator==(Type const& _other) const
u256 StructType::getStorageSize() const
{
u256 size = 0;
- for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
- size += variable->getType()->getStorageSize();
+ for (pair<string, shared_ptr<Type const>> const& member: getMembers())
+ size += member.second->getStorageSize();
return max<u256>(1, size);
}
bool StructType::canLiveOutsideStorage() const
{
- for (unsigned i = 0; i < getMemberCount(); ++i)
- if (!getMemberByIndex(i)->canLiveOutsideStorage())
+ for (pair<string, shared_ptr<Type const>> const& member: getMembers())
+ if (!member.second->canLiveOutsideStorage())
return false;
return true;
}
@@ -244,33 +246,30 @@ string StructType::toString() const
return string("struct ") + m_struct.getName();
}
-unsigned StructType::getMemberCount() const
-{
- return m_struct.getMembers().size();
-}
-
-unsigned StructType::memberNameToIndex(string const& _name) const
-{
- vector<ASTPointer<VariableDeclaration>> const& members = m_struct.getMembers();
- for (unsigned index = 0; index < members.size(); ++index)
- if (members[index]->getName() == _name)
- return index;
- return unsigned(-1);
-}
-
-shared_ptr<Type const> const& StructType::getMemberByIndex(unsigned _index) const
+MemberList const& StructType::getMembers() const
{
- return m_struct.getMembers()[_index].getType();
+ // We need to lazy-initialize it because of recursive references.
+ if (!m_members)
+ {
+ map<string, shared_ptr<Type const>> members;
+ for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
+ members[variable->getName()] = variable->getType();
+ m_members.reset(new MemberList(members));
+ }
+ return *m_members;
}
-u256 StructType::getStorageOffsetOfMember(unsigned _index) const
+u256 StructType::getStorageOffsetOfMember(string const& _name) const
{
//@todo cache member offset?
u256 offset;
-// vector<ASTPointer<VariableDeclaration>> const& members = m_struct.getMembers();
- for (unsigned index = 0; index < _index; ++index)
- offset += getMemberByIndex(index)->getStorageSize();
- return offset;
+ for (ASTPointer<VariableDeclaration> variable: m_struct.getMembers())
+ {
+ offset += variable->getType()->getStorageSize();
+ if (variable->getName() == _name)
+ return offset;
+ }
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested."));
}
bool FunctionType::operator==(Type const& _other) const
diff --git a/Types.h b/Types.h
index b0d95d29..2208a880 100644
--- a/Types.h
+++ b/Types.h
@@ -24,6 +24,7 @@
#include <memory>
#include <string>
+#include <map>
#include <boost/noncopyable.hpp>
#include <libdevcore/Common.h>
#include <libsolidity/Exceptions.h>
@@ -37,6 +38,33 @@ namespace solidity
// @todo realMxN, string<N>
+class Type; // forward
+
+/**
+ * List of members of a type.
+ */
+class MemberList
+{
+public:
+ using TypePointer = std::shared_ptr<Type const>;
+ using MemberMap = std::map<std::string, TypePointer>;
+
+ MemberList() {}
+ explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
+ TypePointer getMemberType(std::string const& _name) const
+ {
+ auto it = m_memberTypes.find(_name);
+ return it != m_memberTypes.end() ? it->second : std::shared_ptr<Type const>();
+ }
+
+ MemberMap::const_iterator begin() const { return m_memberTypes.begin(); }
+ MemberMap::const_iterator end() const { return m_memberTypes.end(); }
+
+private:
+ MemberMap m_memberTypes;
+};
+
+
/**
* Abstract base class that forms the root of the type hierarchy.
*/
@@ -81,12 +109,21 @@ public:
/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
virtual bool canLiveOutsideStorage() const { return true; }
+ /// Returns the list of all members of this type. Default implementation: no members.
+ virtual MemberList const& getMembers() const { return EmptyMemberList; }
+ /// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
+ std::shared_ptr<Type const> getMemberType(std::string const& _name) const { return getMembers().getMemberType(_name); }
+
virtual std::string toString() const = 0;
virtual u256 literalValue(Literal const&) const
{
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested "
"for type without literals."));
}
+
+protected:
+ /// Convenience object used when returning an empty member list.
+ static const MemberList EmptyMemberList;
};
/**
@@ -187,14 +224,14 @@ public:
virtual bool canLiveOutsideStorage() const;
virtual std::string toString() const override;
- unsigned getMemberCount() const;
- /// Returns the index of the member with name @a _name or unsigned(-1) if it does not exist.
- unsigned memberNameToIndex(std::string const& _name) const;
- std::shared_ptr<Type const> const& getMemberByIndex(unsigned _index) const;
- u256 getStorageOffsetOfMember(unsigned _index) const;
+ virtual MemberList const& getMembers() const override;
+
+ u256 getStorageOffsetOfMember(std::string const& _name) const;
private:
StructDefinition const& m_struct;
+ /// List of member types, will be lazy-initialized because of recursive references.
+ mutable std::unique_ptr<MemberList> m_members;
};
/**