diff options
-rw-r--r-- | AST.cpp | 10 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 5 | ||||
-rw-r--r-- | Types.cpp | 49 | ||||
-rw-r--r-- | Types.h | 47 |
4 files changed, 70 insertions, 41 deletions
@@ -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); } @@ -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 @@ -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; }; /** |