mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add InlineArrayType to support literals conversion to statically and dynamically allocated arrays.
This commit is contained in:
@@ -407,6 +407,11 @@ TupleType const* TypeProvider::tuple(vector<Type const*> members)
|
||||
return createAndGet<TupleType>(move(members));
|
||||
}
|
||||
|
||||
InlineArrayType const* TypeProvider::inlineArray(vector<Type const*> _members)
|
||||
{
|
||||
return createAndGet<InlineArrayType>(move(_members));
|
||||
}
|
||||
|
||||
ReferenceType const* TypeProvider::withLocation(ReferenceType const* _type, DataLocation _location, bool _isPointer)
|
||||
{
|
||||
if (_type->location() == _location && _type->isPointer() == _isPointer)
|
||||
|
||||
@@ -109,6 +109,8 @@ public:
|
||||
|
||||
static TupleType const* emptyTuple() noexcept { return &m_emptyTuple; }
|
||||
|
||||
static InlineArrayType const* inlineArray(std::vector<Type const*> members);
|
||||
|
||||
static ReferenceType const* withLocation(ReferenceType const* _type, DataLocation _location, bool _isPointer);
|
||||
|
||||
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
||||
|
||||
@@ -323,6 +323,7 @@ Type const* Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
|
||||
if (_inLibraryCall && encodingType && encodingType->dataStoredIn(DataLocation::Storage))
|
||||
return encodingType;
|
||||
Type const* baseType = encodingType;
|
||||
|
||||
while (auto const* arrayType = dynamic_cast<ArrayType const*>(baseType))
|
||||
{
|
||||
baseType = arrayType->baseType();
|
||||
@@ -2740,6 +2741,101 @@ Type const* TupleType::mobileType() const
|
||||
return TypeProvider::tuple(move(mobiles));
|
||||
}
|
||||
|
||||
BoolResult InlineArrayType::isImplicitlyConvertibleTo(Type const& _other) const
|
||||
{
|
||||
auto arrayType = dynamic_cast<ArrayType const*>(&_other);
|
||||
|
||||
if (!arrayType || arrayType->isByteArrayOrString())
|
||||
return BoolResult::err("Array literal can not be converted to byte array or string.");
|
||||
|
||||
if (!arrayType->isDynamicallySized() && arrayType->length() != components().size())
|
||||
return BoolResult::err(
|
||||
"Number of components in array literal (" + to_string(components().size()) + ") " +
|
||||
"does not match array size (" + to_string(arrayType->length().convert_to<unsigned>()) + ")."
|
||||
);
|
||||
|
||||
for (Type const* c: components())
|
||||
{
|
||||
BoolResult result = c->isImplicitlyConvertibleTo(*arrayType->baseType());
|
||||
if (!result)
|
||||
return BoolResult::err(
|
||||
"Invalid conversion from " + c->toString(false) +
|
||||
" to " + arrayType->baseType()->toString(false) + "." +
|
||||
(result.message().empty() ? "" : " ") + result.message()
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string InlineArrayType::richIdentifier() const
|
||||
{
|
||||
return "t_inline_array" + identifierList(components());
|
||||
}
|
||||
|
||||
bool InlineArrayType::operator==(Type const& _other) const
|
||||
{
|
||||
if (auto inlineArrayType = dynamic_cast<InlineArrayType const*>(&_other))
|
||||
{
|
||||
std::vector<Type const*> const& otherComponents = inlineArrayType->components();
|
||||
if (m_components.size() != otherComponents.size())
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < m_components.size(); ++i)
|
||||
if (!(*m_components[i] == *otherComponents[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
string InlineArrayType::toString(bool _short) const
|
||||
{
|
||||
vector<string> result;
|
||||
for (auto const& t: components())
|
||||
result.push_back(t->toString(_short));
|
||||
return "inline_array(" + util::joinHumanReadable(result) + ")";
|
||||
}
|
||||
|
||||
u256 InlineArrayType::storageSize() const
|
||||
{
|
||||
solAssert(false, "Storage size of non-storable InlineArrayType type requested.");
|
||||
}
|
||||
|
||||
Type const* InlineArrayType::mobileType() const
|
||||
{
|
||||
Type const* baseType = componentsCommonMobileType();
|
||||
return
|
||||
baseType ?
|
||||
TypeProvider::array(DataLocation::Memory, baseType, components().size()) :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
Type const* InlineArrayType::componentsCommonMobileType() const
|
||||
{
|
||||
solAssert(!m_components.empty(), "Empty array literal");
|
||||
Type const* commonType = nullptr;
|
||||
|
||||
for (Type const* type: m_components)
|
||||
commonType =
|
||||
commonType ?
|
||||
Type::commonType(commonType, type->mobileType()) :
|
||||
type->mobileType();
|
||||
|
||||
return TypeProvider::withLocationIfReference(DataLocation::Memory, commonType);
|
||||
}
|
||||
|
||||
vector<tuple<string, Type const*>> InlineArrayType::makeStackItems() const
|
||||
{
|
||||
vector<tuple<string, Type const*>> slots;
|
||||
for (auto && [index, type]: components() | ranges::views::enumerate)
|
||||
slots.emplace_back("component_" + std::to_string(index + 1), type);
|
||||
return slots;
|
||||
}
|
||||
|
||||
|
||||
FunctionType::FunctionType(FunctionDefinition const& _function, Kind _kind):
|
||||
m_kind(_kind),
|
||||
m_stateMutability(_function.stateMutability()),
|
||||
|
||||
+36
-1
@@ -175,7 +175,7 @@ public:
|
||||
enum class Category
|
||||
{
|
||||
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array, ArraySlice,
|
||||
FixedBytes, Contract, Struct, Function, Enum, UserDefinedValueType, Tuple,
|
||||
FixedBytes, Contract, Struct, Function, Enum, UserDefinedValueType, Tuple, InlineArray,
|
||||
Mapping, TypeType, Modifier, Magic, Module,
|
||||
InaccessibleDynamic
|
||||
};
|
||||
@@ -1204,6 +1204,41 @@ private:
|
||||
std::vector<Type const*> const m_components;
|
||||
};
|
||||
|
||||
class InlineArrayType: public CompositeType
|
||||
{
|
||||
public:
|
||||
explicit InlineArrayType(std::vector<Type const*> _types): m_components(std::move(_types)) {}
|
||||
|
||||
Category category() const override { return Category::InlineArray; }
|
||||
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
std::string toString(bool) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
Type const* mobileType() const override;
|
||||
Type const* componentsCommonMobileType() const;
|
||||
std::vector<Type const*> const& components() const { return m_components; }
|
||||
|
||||
protected:
|
||||
std::vector<std::tuple<std::string, Type const*>> makeStackItems() const override;
|
||||
std::vector<Type const*> decomposition() const override
|
||||
{
|
||||
// Currently calling InlineArrayType::decomposition() is not expected, because we cannot declare a variable of a InlineArrayType type.
|
||||
// If that changes, before removing the solAssert, make sure the function does the right thing and is used properly.
|
||||
// Note that different InlineArrayType members can have different data locations, so using decomposition() to check
|
||||
// the tuple validity for a data location might require special care.
|
||||
solUnimplemented("InlineArray decomposition is not expected.");
|
||||
return m_components;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Type const*> const m_components;
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of a function, identified by its (return) parameter types.
|
||||
* @todo the return parameters should also have names, i.e. return parameters should be a struct
|
||||
|
||||
Reference in New Issue
Block a user