diff options
-rw-r--r-- | AST.cpp | 2 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 3 | ||||
-rw-r--r-- | Token.h | 2 | ||||
-rw-r--r-- | Types.cpp | 20 | ||||
-rw-r--r-- | Types.h | 22 |
5 files changed, 36 insertions, 13 deletions
@@ -890,6 +890,8 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) ArrayType const& type = dynamic_cast<ArrayType const&>(*m_base->getType()); if (!m_index) BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); + if (type.isString()) + BOOST_THROW_EXCEPTION(createTypeError("Index access for string is not possible.")); m_index->expectType(IntegerType(256)); if (type.isByteArray()) m_type = make_shared<FixedBytesType>(1); diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 2e513b7f..5a978285 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -824,7 +824,10 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) if (arrayType.getLocation() == ArrayType::Location::Storage) { if (arrayType.isByteArray()) + { + solAssert(!arrayType.isString(), "Index access to string is not allowed."); setLValue<StorageByteArrayElement>(_indexAccess); + } else setLValueToStorageItem(_indexAccess); } @@ -286,6 +286,7 @@ namespace solidity K(Bytes32, "bytes32", 0) \ K(Bytes, "bytes", 0) \ K(Byte, "byte", 0) \ + K(String, "string", 0) \ K(Address, "address", 0) \ K(Bool, "bool", 0) \ K(Real, "real", 0) \ @@ -312,7 +313,6 @@ namespace solidity K(Match, "match", 0) \ K(Of, "of", 0) \ K(Relocatable, "relocatable", 0) \ - T(String, "string", 0) \ K(Switch, "switch", 0) \ K(Throw, "throw", 0) \ K(Try, "try", 0) \ @@ -145,6 +145,8 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) return make_shared<BoolType>(); else if (_typeToken == Token::Bytes) return make_shared<ArrayType>(ArrayType::Location::Storage); + else if (_typeToken == Token::String) + return make_shared<ArrayType>(ArrayType::Location::Storage, true); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -663,7 +665,7 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const // let us not allow assignment to memory arrays for now if (convertTo.getLocation() != Location::Storage) return false; - if (convertTo.isByteArray() != isByteArray()) + if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString()) return false; if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType())) return false; @@ -684,8 +686,12 @@ bool ArrayType::operator==(Type const& _other) const if (_other.getCategory() != getCategory()) return false; ArrayType const& other = dynamic_cast<ArrayType const&>(_other); - if (other.m_location != m_location || other.isByteArray() != isByteArray() || - other.isDynamicallySized() != isDynamicallySized()) + if ( + other.m_location != m_location || + other.isByteArray() != isByteArray() || + other.isString() != isString() || + other.isDynamicallySized() != isDynamicallySized() + ) return false; return isDynamicallySized() || getLength() == other.getLength(); } @@ -736,7 +742,9 @@ unsigned ArrayType::getSizeOnStack() const string ArrayType::toString() const { - if (isByteArray()) + if (isString()) + return "string"; + else if (isByteArray()) return "bytes"; string ret = getBaseType()->toString() + "["; if (!isDynamicallySized()) @@ -746,7 +754,7 @@ string ArrayType::toString() const TypePointer ArrayType::externalType() const { - if (m_isByteArray) + if (m_arrayKind != ArrayKind::Ordinary) return shared_from_this(); if (!m_baseType->externalType()) return TypePointer(); @@ -762,7 +770,7 @@ TypePointer ArrayType::externalType() const shared_ptr<ArrayType> ArrayType::copyForLocation(ArrayType::Location _location) const { auto copy = make_shared<ArrayType>(_location); - copy->m_isByteArray = m_isByteArray; + copy->m_arrayKind = m_arrayKind; if (m_baseType->getCategory() == Type::Category::Array) copy->m_baseType = dynamic_cast<ArrayType const&>(*m_baseType).copyForLocation(_location); else @@ -367,10 +367,10 @@ public: virtual Category getCategory() const override { return Category::Array; } - /// Constructor for a byte array ("bytes") - explicit ArrayType(Location _location): + /// Constructor for a byte array ("bytes") and string. + explicit ArrayType(Location _location, bool _isString = false): m_location(_location), - m_isByteArray(true), + m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes), m_baseType(std::make_shared<FixedBytesType>(1)) {} /// Constructor for a dynamically sized array type ("type[]") @@ -394,11 +394,17 @@ public: virtual u256 getStorageSize() const override; virtual unsigned getSizeOnStack() const override; virtual std::string toString() const override; - virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; } + virtual MemberList const& getMembers() const override + { + return isString() ? EmptyMemberList : s_arrayTypeMemberList; + } virtual TypePointer externalType() const override; Location getLocation() const { return m_location; } - bool isByteArray() const { return m_isByteArray; } + /// @returns true if this is a byte array or a string + bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; } + /// @returns true if this is a string + bool isString() const { return m_arrayKind == ArrayKind::String; } TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;} u256 const& getLength() const { return m_length; } @@ -407,8 +413,12 @@ public: std::shared_ptr<ArrayType> copyForLocation(Location _location) const; private: + /// String is interpreted as a subtype of Bytes. + enum class ArrayKind { Ordinary, Bytes, String }; + Location m_location; - bool m_isByteArray = false; ///< Byte arrays ("bytes") have different semantics from ordinary arrays. + ///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays. + ArrayKind m_arrayKind = ArrayKind::Ordinary; TypePointer m_baseType; bool m_hasDynamicLength = true; u256 m_length; |