aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AST.cpp2
-rw-r--r--ExpressionCompiler.cpp3
-rw-r--r--Token.h2
-rw-r--r--Types.cpp20
-rw-r--r--Types.h22
5 files changed, 36 insertions, 13 deletions
diff --git a/AST.cpp b/AST.cpp
index 14884254..248abfdb 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -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);
}
diff --git a/Token.h b/Token.h
index 8a373da3..bce16ed1 100644
--- a/Token.h
+++ b/Token.h
@@ -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) \
diff --git a/Types.cpp b/Types.cpp
index 7577b83a..0e9ea987 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -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
diff --git a/Types.h b/Types.h
index a69df964..65f6e447 100644
--- a/Types.h
+++ b/Types.h
@@ -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;