More flexible array literals.

This commit is contained in:
chriseth 2021-09-14 17:47:30 +02:00
parent 8735d3fb6c
commit 83e7f5e83e
4 changed files with 66 additions and 8 deletions

View File

@ -2565,8 +2565,26 @@ vector<tuple<string, Type const*>> UserDefinedValueType::makeStackItems() const
BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const
{ {
if (auto tupleType = dynamic_cast<TupleType const*>(&_other)) if (auto arrayType = dynamic_cast<ArrayType const*>(&_other))
{ {
if (!m_isArrayLiteral)
return false;
if (!(
arrayType->isDynamicallySized() ||
arrayType->length() == m_components.size()
))
return false;
for (Type const* t: m_components)
if (!t->isImplicitlyConvertibleTo(arrayType->baseType()))
return false;
return true;
}
else if (auto tupleType = dynamic_cast<TupleType const*>(&_other))
{
if (m_isArrayLiteral != tupleType->m_isArrayLiteral)
return false;
TypePointers const& targets = tupleType->components(); TypePointers const& targets = tupleType->components();
if (targets.empty()) if (targets.empty())
return components().empty(); return components().empty();
@ -2585,19 +2603,20 @@ BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const
string TupleType::richIdentifier() const string TupleType::richIdentifier() const
{ {
return "t_tuple" + identifierList(components()); return (m_isArrayLiteral ? "t_arrayLiteral" : "t_tuple") + identifierList(components());
} }
bool TupleType::operator==(Type const& _other) const bool TupleType::operator==(Type const& _other) const
{ {
if (auto tupleType = dynamic_cast<TupleType const*>(&_other)) if (auto tupleType = dynamic_cast<TupleType const*>(&_other))
return components() == tupleType->components(); return components() == tupleType->components() && m_isArrayLiteral == tupleType->m_isArrayLiteral;
else else
return false; return false;
} }
string TupleType::toString(bool _short) const string TupleType::toString(bool _short) const
{ {
// TODO
if (components().empty()) if (components().empty())
return "tuple()"; return "tuple()";
string str = "tuple("; string str = "tuple(";
@ -2640,7 +2659,8 @@ Type const* TupleType::mobileType() const
else else
mobiles.push_back(nullptr); mobiles.push_back(nullptr);
} }
return TypeProvider::tuple(move(mobiles)); // TODO correct?
return TypeProvider::tuple(move(mobiles), m_isArrayLiteral);
} }
FunctionType::FunctionType(FunctionDefinition const& _function, Kind _kind): FunctionType::FunctionType(FunctionDefinition const& _function, Kind _kind):

View File

@ -1136,7 +1136,10 @@ private:
class TupleType: public CompositeType class TupleType: public CompositeType
{ {
public: public:
explicit TupleType(std::vector<Type const*> _types = {}): m_components(std::move(_types)) {} explicit TupleType(std::vector<Type const*> _types = {}, bool _arrayLiteral = false):
m_components(std::move(_types)),
m_isArrayLiteral(_arrayLiteral)
{}
Category category() const override { return Category::Tuple; } Category category() const override { return Category::Tuple; }
@ -1150,6 +1153,7 @@ public:
bool hasSimpleZeroValueInMemory() const override { return false; } bool hasSimpleZeroValueInMemory() const override { return false; }
Type const* mobileType() const override; Type const* mobileType() const override;
bool isArrayLiteral() const { return m_isArrayLiteral; }
std::vector<Type const*> const& components() const { return m_components; } std::vector<Type const*> const& components() const { return m_components; }
protected: protected:
@ -1166,6 +1170,7 @@ protected:
private: private:
std::vector<Type const*> const m_components; std::vector<Type const*> const m_components;
bool const m_isArrayLiteral;
}; };
/** /**

View File

@ -3256,6 +3256,11 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
solAssert(_to.category() == Type::Category::Array, ""); solAssert(_to.category() == Type::Category::Array, "");
return arrayConversionFunction(fromArrayType, dynamic_cast<ArrayType const&>(_to)); return arrayConversionFunction(fromArrayType, dynamic_cast<ArrayType const&>(_to));
} }
else if (auto tupleType = dynamic_cast<TupleType const*>(&_from))
{
if (tupleType->isArrayLiteral())
return arrayLiteralConversionFunction(*tupleType, dynamic_cast<ArrayType const&>(_to));
}
if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1) if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
return conversionFunctionSpecial(_from, _to); return conversionFunctionSpecial(_from, _to);
@ -3418,10 +3423,8 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
break; break;
} }
case Type::Category::Tuple: case Type::Category::Tuple:
{ solAssert(false, "");
solUnimplementedAssert(false, "Tuple conversion not implemented.");
break; break;
}
case Type::Category::TypeType: case Type::Category::TypeType:
{ {
TypeType const& typeType = dynamic_cast<decltype(typeType)>(_from); TypeType const& typeType = dynamic_cast<decltype(typeType)>(_from);
@ -3704,6 +3707,34 @@ string YulUtilFunctions::arrayConversionFunction(ArrayType const& _from, ArrayTy
}); });
} }
string YulUtilFunctions::arrayLiteralConversionFunction(TupleType const& _from, ArrayType const& _to)
{
solUnimplementedAssert(_to.dataStoredIn(DataLocation::Memory, "");
string functionName =
"convert_arrayliteral_" +
_from.identifier() +
"_to_" +
_to.identifier();
return m_functionCollector.createFunction(functionName, [&](vector<string>& _args, vector<string>& _ret) {
_args = _from.stackItems();
_ret = "converted";
Whiskers templ(R"(
// Copy the array to a free position in memory
converted := <allocate>(<length>)
<?dynamic>
mstore(converted, <length>)
</dynamic>
<#items>
mstore(<pos>, <var>)
</items>
)");
return templ.render();
});
}
string YulUtilFunctions::cleanupFunction(Type const& _type) string YulUtilFunctions::cleanupFunction(Type const& _type)
{ {
if (auto userDefinedValueType = dynamic_cast<UserDefinedValueType const*>(&_type)) if (auto userDefinedValueType = dynamic_cast<UserDefinedValueType const*>(&_type))

View File

@ -530,6 +530,8 @@ private:
/// Special case of conversion functions - handles all array conversions. /// Special case of conversion functions - handles all array conversions.
std::string arrayConversionFunction(ArrayType const& _from, ArrayType const& _to); std::string arrayConversionFunction(ArrayType const& _from, ArrayType const& _to);
std::string arrayLiteralConversionFunction(TupleType const& _from, ArrayType const& _to);
/// Special case of conversionFunction - handles everything that does not /// Special case of conversionFunction - handles everything that does not
/// use exactly one variable to hold the value. /// use exactly one variable to hold the value.
std::string conversionFunctionSpecial(Type const& _from, Type const& _to); std::string conversionFunctionSpecial(Type const& _from, Type const& _to);