From 83e7f5e83eb3a3e95173d8e2ea1b5589e6334fac Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 14 Sep 2021 17:47:30 +0200 Subject: [PATCH] More flexible array literals. --- libsolidity/ast/Types.cpp | 28 +++++++++++++++--- libsolidity/ast/Types.h | 7 ++++- libsolidity/codegen/YulUtilFunctions.cpp | 37 ++++++++++++++++++++++-- libsolidity/codegen/YulUtilFunctions.h | 2 ++ 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index da6f7d196..851de5df7 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2565,8 +2565,26 @@ vector> UserDefinedValueType::makeStackItems() const BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const { - if (auto tupleType = dynamic_cast(&_other)) + if (auto arrayType = dynamic_cast(&_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(&_other)) + { + if (m_isArrayLiteral != tupleType->m_isArrayLiteral) + return false; TypePointers const& targets = tupleType->components(); if (targets.empty()) return components().empty(); @@ -2585,19 +2603,20 @@ BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) 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 { if (auto tupleType = dynamic_cast(&_other)) - return components() == tupleType->components(); + return components() == tupleType->components() && m_isArrayLiteral == tupleType->m_isArrayLiteral; else return false; } string TupleType::toString(bool _short) const { + // TODO if (components().empty()) return "tuple()"; string str = "tuple("; @@ -2640,7 +2659,8 @@ Type const* TupleType::mobileType() const else 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): diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index b092628fb..f08ba9d97 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1136,7 +1136,10 @@ private: class TupleType: public CompositeType { public: - explicit TupleType(std::vector _types = {}): m_components(std::move(_types)) {} + explicit TupleType(std::vector _types = {}, bool _arrayLiteral = false): + m_components(std::move(_types)), + m_isArrayLiteral(_arrayLiteral) + {} Category category() const override { return Category::Tuple; } @@ -1150,6 +1153,7 @@ public: bool hasSimpleZeroValueInMemory() const override { return false; } Type const* mobileType() const override; + bool isArrayLiteral() const { return m_isArrayLiteral; } std::vector const& components() const { return m_components; } protected: @@ -1166,6 +1170,7 @@ protected: private: std::vector const m_components; + bool const m_isArrayLiteral; }; /** diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index bb56c43df..9f0248a04 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -3256,6 +3256,11 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) solAssert(_to.category() == Type::Category::Array, ""); return arrayConversionFunction(fromArrayType, dynamic_cast(_to)); } + else if (auto tupleType = dynamic_cast(&_from)) + { + if (tupleType->isArrayLiteral()) + return arrayLiteralConversionFunction(*tupleType, dynamic_cast(_to)); + } if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1) return conversionFunctionSpecial(_from, _to); @@ -3418,10 +3423,8 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) break; } case Type::Category::Tuple: - { - solUnimplementedAssert(false, "Tuple conversion not implemented."); + solAssert(false, ""); break; - } case Type::Category::TypeType: { TypeType const& typeType = dynamic_cast(_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& _args, vector& _ret) { + _args = _from.stackItems(); + _ret = "converted"; + Whiskers templ(R"( + // Copy the array to a free position in memory + converted := () + + mstore(converted, ) + + <#items> + mstore(, ) + + )"); + return templ.render(); + }); +} + + string YulUtilFunctions::cleanupFunction(Type const& _type) { if (auto userDefinedValueType = dynamic_cast(&_type)) diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index a03ee75c2..0e696c03b 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -530,6 +530,8 @@ private: /// Special case of conversion functions - handles all array conversions. 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 /// use exactly one variable to hold the value. std::string conversionFunctionSpecial(Type const& _from, Type const& _to);