mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Initial introduction of array slices with partial implementation for dynamic calldata arrays.
This commit is contained in:
@@ -1642,6 +1642,32 @@ private:
|
||||
ASTPointer<Expression> m_index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Index range access to an array. Example: a[2:3]
|
||||
*/
|
||||
class IndexRangeAccess: public Expression
|
||||
{
|
||||
public:
|
||||
IndexRangeAccess(
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<Expression> const& _base,
|
||||
ASTPointer<Expression> const& _start,
|
||||
ASTPointer<Expression> const& _end
|
||||
):
|
||||
Expression(_location), m_base(_base), m_start(_start), m_end(_end) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
Expression const& baseExpression() const { return *m_base; }
|
||||
Expression const* startExpression() const { return m_start.get(); }
|
||||
Expression const* endExpression() const { return m_end.get(); }
|
||||
|
||||
private:
|
||||
ASTPointer<Expression> m_base;
|
||||
ASTPointer<Expression> m_start;
|
||||
ASTPointer<Expression> m_end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Primary expression, i.e. an expression that cannot be divided any further. Examples are literals
|
||||
* or variable references.
|
||||
|
||||
@@ -694,6 +694,18 @@ bool ASTJsonConverter::visit(IndexAccess const& _node)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTJsonConverter::visit(IndexRangeAccess const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("baseExpression", toJson(_node.baseExpression())),
|
||||
make_pair("startExpression", toJsonOrNull(_node.startExpression())),
|
||||
make_pair("endExpression", toJsonOrNull(_node.endExpression())),
|
||||
};
|
||||
appendExpressionAttributes(attributes, _node.annotation());
|
||||
setJsonNode(_node, "IndexRangeAccess", std::move(attributes));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTJsonConverter::visit(Identifier const& _node)
|
||||
{
|
||||
Json::Value overloads(Json::arrayValue);
|
||||
|
||||
@@ -111,6 +111,7 @@ public:
|
||||
bool visit(NewExpression const& _node) override;
|
||||
bool visit(MemberAccess const& _node) override;
|
||||
bool visit(IndexAccess const& _node) override;
|
||||
bool visit(IndexRangeAccess const& _node) override;
|
||||
bool visit(Identifier const& _node) override;
|
||||
bool visit(ElementaryTypeNameExpression const& _node) override;
|
||||
bool visit(Literal const& _node) override;
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
virtual bool visit(NewExpression& _node) { return visitNode(_node); }
|
||||
virtual bool visit(MemberAccess& _node) { return visitNode(_node); }
|
||||
virtual bool visit(IndexAccess& _node) { return visitNode(_node); }
|
||||
virtual bool visit(IndexRangeAccess& _node) { return visitNode(_node); }
|
||||
virtual bool visit(Identifier& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ElementaryTypeNameExpression& _node) { return visitNode(_node); }
|
||||
virtual bool visit(Literal& _node) { return visitNode(_node); }
|
||||
@@ -134,6 +135,7 @@ public:
|
||||
virtual void endVisit(NewExpression& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(MemberAccess& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(IndexAccess& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(IndexRangeAccess& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(Identifier& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ElementaryTypeNameExpression& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(Literal& _node) { endVisitNode(_node); }
|
||||
@@ -194,6 +196,7 @@ public:
|
||||
virtual bool visit(NewExpression const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(MemberAccess const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(IndexAccess const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(IndexRangeAccess const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(Identifier const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ElementaryTypeNameExpression const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(Literal const& _node) { return visitNode(_node); }
|
||||
@@ -241,6 +244,7 @@ public:
|
||||
virtual void endVisit(NewExpression const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(MemberAccess const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(IndexAccess const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(IndexRangeAccess const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(Identifier const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ElementaryTypeNameExpression const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(Literal const& _node) { endVisitNode(_node); }
|
||||
|
||||
@@ -783,6 +783,32 @@ void IndexAccess::accept(ASTConstVisitor& _visitor) const
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
void IndexRangeAccess::accept(ASTVisitor& _visitor)
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
m_base->accept(_visitor);
|
||||
if (m_start)
|
||||
m_start->accept(_visitor);
|
||||
if (m_end)
|
||||
m_end->accept(_visitor);
|
||||
}
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
void IndexRangeAccess::accept(ASTConstVisitor& _visitor) const
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
m_base->accept(_visitor);
|
||||
if (m_start)
|
||||
m_start->accept(_visitor);
|
||||
if (m_end)
|
||||
m_end->accept(_visitor);
|
||||
}
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
void Identifier::accept(ASTVisitor& _visitor)
|
||||
{
|
||||
_visitor.visit(*this);
|
||||
|
||||
@@ -31,6 +31,7 @@ InaccessibleDynamicType const TypeProvider::m_inaccessibleDynamic{};
|
||||
/// they rely on `byte` being available which we cannot guarantee in the static init context.
|
||||
unique_ptr<ArrayType> TypeProvider::m_bytesStorage;
|
||||
unique_ptr<ArrayType> TypeProvider::m_bytesMemory;
|
||||
unique_ptr<ArrayType> TypeProvider::m_bytesCalldata;
|
||||
unique_ptr<ArrayType> TypeProvider::m_stringStorage;
|
||||
unique_ptr<ArrayType> TypeProvider::m_stringMemory;
|
||||
|
||||
@@ -177,6 +178,7 @@ void TypeProvider::reset()
|
||||
clearCache(m_inaccessibleDynamic);
|
||||
clearCache(m_bytesStorage);
|
||||
clearCache(m_bytesMemory);
|
||||
clearCache(m_bytesCalldata);
|
||||
clearCache(m_stringStorage);
|
||||
clearCache(m_stringMemory);
|
||||
clearCache(m_emptyTuple);
|
||||
@@ -314,6 +316,13 @@ ArrayType const* TypeProvider::bytesMemory()
|
||||
return m_bytesMemory.get();
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::bytesCalldata()
|
||||
{
|
||||
if (!m_bytesCalldata)
|
||||
m_bytesCalldata = make_unique<ArrayType>(DataLocation::CallData, false);
|
||||
return m_bytesCalldata.get();
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::stringStorage()
|
||||
{
|
||||
if (!m_stringStorage)
|
||||
@@ -500,6 +509,11 @@ ArrayType const* TypeProvider::array(DataLocation _location, Type const* _baseTy
|
||||
return createAndGet<ArrayType>(_location, _baseType, _length);
|
||||
}
|
||||
|
||||
ArraySliceType const* TypeProvider::arraySlice(ArrayType const& _arrayType)
|
||||
{
|
||||
return createAndGet<ArraySliceType>(_arrayType);
|
||||
}
|
||||
|
||||
ContractType const* TypeProvider::contract(ContractDefinition const& _contractDef, bool _isSuper)
|
||||
{
|
||||
return createAndGet<ContractType>(_contractDef, _isSuper);
|
||||
|
||||
@@ -68,6 +68,7 @@ public:
|
||||
|
||||
static ArrayType const* bytesStorage();
|
||||
static ArrayType const* bytesMemory();
|
||||
static ArrayType const* bytesCalldata();
|
||||
static ArrayType const* stringStorage();
|
||||
static ArrayType const* stringMemory();
|
||||
|
||||
@@ -80,6 +81,8 @@ public:
|
||||
/// Constructor for a fixed-size array type ("type[20]")
|
||||
static ArrayType const* array(DataLocation _location, Type const* _baseType, u256 const& _length);
|
||||
|
||||
static ArraySliceType const* arraySlice(ArrayType const& _arrayType);
|
||||
|
||||
static AddressType const* payableAddress() noexcept { return &m_payableAddress; }
|
||||
static AddressType const* address() noexcept { return &m_address; }
|
||||
|
||||
@@ -203,6 +206,7 @@ private:
|
||||
/// These are lazy-initialized because they depend on `byte` being available.
|
||||
static std::unique_ptr<ArrayType> m_bytesStorage;
|
||||
static std::unique_ptr<ArrayType> m_bytesMemory;
|
||||
static std::unique_ptr<ArrayType> m_bytesCalldata;
|
||||
static std::unique_ptr<ArrayType> m_stringStorage;
|
||||
static std::unique_ptr<ArrayType> m_stringMemory;
|
||||
|
||||
|
||||
@@ -1869,6 +1869,30 @@ std::unique_ptr<ReferenceType> ArrayType::copyForLocation(DataLocation _location
|
||||
return copy;
|
||||
}
|
||||
|
||||
BoolResult ArraySliceType::isImplicitlyConvertibleTo(Type const& _other) const
|
||||
{
|
||||
if (m_arrayType.location() == DataLocation::CallData && m_arrayType.isDynamicallySized() && m_arrayType == _other)
|
||||
return true;
|
||||
return (*this) == _other;
|
||||
}
|
||||
|
||||
string ArraySliceType::richIdentifier() const
|
||||
{
|
||||
return m_arrayType.richIdentifier() + "_slice";
|
||||
}
|
||||
|
||||
bool ArraySliceType::operator==(Type const& _other) const
|
||||
{
|
||||
if (auto const* other = dynamic_cast<ArraySliceType const*>(&_other))
|
||||
return m_arrayType == other->m_arrayType;
|
||||
return false;
|
||||
}
|
||||
|
||||
string ArraySliceType::toString(bool _short) const
|
||||
{
|
||||
return m_arrayType.toString(_short) + " slice";
|
||||
}
|
||||
|
||||
string ContractType::richIdentifier() const
|
||||
{
|
||||
return (m_super ? "t_super" : "t_contract") + parenthesizeUserIdentifier(m_contract.name()) + to_string(m_contract.id());
|
||||
|
||||
+30
-1
@@ -161,7 +161,7 @@ public:
|
||||
|
||||
enum class Category
|
||||
{
|
||||
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
|
||||
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array, ArraySlice,
|
||||
FixedBytes, Contract, Struct, Function, Enum, Tuple,
|
||||
Mapping, TypeType, Modifier, Magic, Module,
|
||||
InaccessibleDynamic
|
||||
@@ -773,6 +773,35 @@ private:
|
||||
mutable boost::optional<TypeResult> m_interfaceType_library;
|
||||
};
|
||||
|
||||
class ArraySliceType: public ReferenceType
|
||||
{
|
||||
public:
|
||||
explicit ArraySliceType(ArrayType const& _arrayType): ReferenceType(_arrayType.location()), m_arrayType(_arrayType) {}
|
||||
Category category() const override { return Category::ArraySlice; }
|
||||
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
unsigned calldataEncodedSize(bool) const override { solAssert(false, ""); }
|
||||
unsigned calldataEncodedTailSize() const override { return 32; }
|
||||
bool isDynamicallySized() const override { return true; }
|
||||
bool isDynamicallyEncoded() const override { return true; }
|
||||
bool canLiveOutsideStorage() const override { return m_arrayType.canLiveOutsideStorage(); }
|
||||
unsigned sizeOnStack() const override { return 2; }
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
/// @returns true if this is valid to be stored in calldata
|
||||
bool validForCalldata() const { return m_arrayType.validForCalldata(); }
|
||||
|
||||
ArrayType const& arrayType() const { return m_arrayType; }
|
||||
u256 memoryDataSize() const override { solAssert(false, ""); }
|
||||
|
||||
std::unique_ptr<ReferenceType> copyForLocation(DataLocation, bool) const override { solAssert(false, ""); }
|
||||
|
||||
private:
|
||||
ArrayType const& m_arrayType;
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of a contract instance or library, there is one distinct type for each contract definition.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user