diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index eb7479f12..b9a8533f8 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -918,7 +918,7 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) string functionName = "array_length_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { Whiskers w(R"( - function (value) -> length { + function (value, len) -> length { length := mload(value) @@ -929,6 +929,9 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) length := (length) + + length := len + length := @@ -940,17 +943,14 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) w("length", toCompactHexWithPrefix(_type.length())); w("memory", _type.location() == DataLocation::Memory); w("storage", _type.location() == DataLocation::Storage); + w("calldata", _type.location() == DataLocation::CallData); if (_type.location() == DataLocation::Storage) { w("byteArray", _type.isByteArray()); if (_type.isByteArray()) w("extractByteArrayLength", extractByteArrayLengthFunction()); } - if (_type.isDynamicallySized()) - solAssert( - _type.location() != DataLocation::CallData, - "called regular array length function on calldata array" - ); + return w.render(); }); } @@ -1295,6 +1295,105 @@ string YulUtilFunctions::clearStorageStructFunction(StructType const& _type) }); } +string YulUtilFunctions::copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType) +{ + solAssert( + *_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast(_toType), + "" + ); + solUnimplementedAssert(!_fromType.isByteArray(), ""); + solUnimplementedAssert(!_fromType.dataStoredIn(DataLocation::Storage), ""); + + string functionName = "copy_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); + return m_functionCollector.createFunction(functionName, [&](){ + Whiskers templ(R"( + function (slot, value, len) { + let length := (value, len) + + (slot, length) + + + let srcPtr := + + add(value, 0x20) + + value + + + let elementSlot := (slot) + let elementOffset := 0 + + for { let i := 0 } lt(i, length) {i := add(i, 1)} { + + let := + + (value, srcPtr) + + srcPtr + + + + := () + + + + + let := (srcPtr) + + + (elementSlot, elementOffset, ) + + srcPtr := add(srcPtr, ) + + + elementOffset := add(elementOffset, ) + if gt(elementOffset, sub(32, )) { + elementOffset := 0 + elementSlot := add(elementSlot, 1) + } + + elementSlot := add(elementSlot, ) + elementOffset := 0 + + } + } + )"); + templ("functionName", functionName); + bool fromCalldata = _fromType.dataStoredIn(DataLocation::CallData); + templ("isFromDynamicCalldata", _fromType.isDynamicallySized() && fromCalldata); + templ("fromMemory", _fromType.dataStoredIn(DataLocation::Memory)); + templ("fromCalldata", fromCalldata); + templ("isToDynamic", _toType.isDynamicallySized()); + templ("isFromMemoryDynamic", _fromType.isDynamicallySized() && _fromType.dataStoredIn(DataLocation::Memory)); + if (fromCalldata) + { + templ("dynamicallySizedBase", _fromType.baseType()->isDynamicallySized()); + templ("dynamicallyEncodedBase", _fromType.baseType()->isDynamicallyEncoded()); + if (_fromType.baseType()->isDynamicallyEncoded()) + templ("accessCalldataTail", accessCalldataTailFunction(*_fromType.baseType())); + } + if (_toType.isDynamicallySized()) + templ("resizeArray", resizeDynamicArrayFunction(_toType)); + templ("arrayLength",arrayLengthFunction(_fromType)); + templ("isValueType", _fromType.baseType()->isValueType()); + templ("dstDataLocation", arrayDataAreaFunction(_toType)); + if (!fromCalldata || _fromType.baseType()->isValueType()) + templ("readFromCalldataOrMemory", readFromMemoryOrCalldata(*_fromType.baseType(), fromCalldata)); + templ("elementValues", suffixedVariableNameList( + "elementValue_", + 0, + _fromType.baseType()->stackItems().size() + )); + templ("updateStorageValue", updateStorageValueFunction(*_fromType.baseType(), *_toType.baseType())); + templ("stride", to_string(fromCalldata ? _fromType.calldataStride() : _fromType.memoryStride())); + templ("multipleItemsPerSlot", _toType.storageStride() <= 16); + templ("storageStride", to_string(_toType.storageStride())); + templ("storageSize", _toType.baseType()->storageSize().str()); + + return templ.render(); + }); +} + string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type) { string functionName = "array_convert_length_to_size_" + _type.identifier(); @@ -1865,23 +1964,39 @@ string YulUtilFunctions::updateStorageValueFunction( else { auto const* toReferenceType = dynamic_cast(&_toType); - auto const* fromReferenceType = dynamic_cast(&_toType); + auto const* fromReferenceType = dynamic_cast(&_fromType); solAssert(fromReferenceType && toReferenceType, ""); solAssert(*toReferenceType->copyForLocation( fromReferenceType->location(), fromReferenceType->isPointer() ).get() == *fromReferenceType, ""); + solUnimplementedAssert(fromReferenceType->location() != DataLocation::Storage, ""); + solAssert(toReferenceType->category() == fromReferenceType->category(), ""); if (_toType.category() == Type::Category::Array) - solUnimplementedAssert(false, ""); + { + solAssert(_offset.value_or(0) == 0, ""); + + Whiskers templ(R"( + function (slot, ) { + (slot, ) + } + )"); + templ("functionName", functionName); + templ("value", suffixedVariableNameList("value_", 0, _fromType.sizeOnStack())); + templ("copyArrayToStorage", copyArrayToStorage( + dynamic_cast(_fromType), + dynamic_cast(_toType) + )); + + return templ.render(); + } else if (_toType.category() == Type::Category::Struct) { - solAssert(_fromType.category() == Type::Category::Struct, ""); auto const& fromStructType = dynamic_cast(_fromType); auto const& toStructType = dynamic_cast(_toType); solAssert(fromStructType.structDefinition() == toStructType.structDefinition(), ""); - solAssert(fromStructType.location() != DataLocation::Storage, ""); - solUnimplementedAssert(_offset.has_value() && _offset.value() == 0, ""); + solAssert(_offset.value_or(0) == 0, ""); Whiskers templ(R"( function (slot, value) { @@ -1895,6 +2010,7 @@ string YulUtilFunctions::updateStorageValueFunction( templ("functionName", functionName); MemberList::MemberMap structMembers = fromStructType.nativeMembers(nullptr); + MemberList::MemberMap toStructMembers = toStructType.nativeMembers(nullptr); vector> memberParams(structMembers.size()); for (size_t i = 0; i < structMembers.size(); ++i) @@ -1902,31 +2018,65 @@ string YulUtilFunctions::updateStorageValueFunction( solAssert(structMembers[i].type->memoryHeadSize() == 32, ""); bool fromCalldata = fromStructType.location() == DataLocation::CallData; auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(structMembers[i].name); - memberParams[i]["updateMemberCall"] = Whiskers(R"( - let := (add(value, )) - (add(slot, ), , ) - )") - ("memberValues", suffixedVariableNameList( + + Whiskers t(R"( + let memberSlot := add(slot, ) + + + + let := (value, add(value, )) + + let := add(value, ) + + + + let := () + (memberSlot, , ) + + (memberSlot, ) + + + let memberMemoryOffset := add(value, ) + let := (memberMemoryOffset) + (memberSlot, , ) + + )"); + t("fromCalldata", fromCalldata); + if (fromCalldata) + { + t("memberCalldataOffset", suffixedVariableNameList( + "memberCalldataOffset_", + 0, + structMembers[i].type->stackItems().size() + )); + t("dynamicallyEncodedMember", structMembers[i].type->isDynamicallyEncoded()); + if (structMembers[i].type->isDynamicallySized()) + t("accessCalldataTail", accessCalldataTailFunction(*structMembers[i].type)); + } + t("isValueType", structMembers[i].type->isValueType()); + t("memberValues", suffixedVariableNameList( "memberValue_", 0, structMembers[i].type->stackItems().size() - )) - ("hasOffset", structMembers[i].type->isValueType()) - ( + )); + t("hasOffset", structMembers[i].type->isValueType()); + t( "updateMember", structMembers[i].type->isValueType() ? - updateStorageValueFunction(*structMembers[i].type, *structMembers[i].type) : - updateStorageValueFunction(*structMembers[i].type, *structMembers[i].type, offset) - ) - ("memberStorageSlotDiff", slotDiff.str()) - ("memberStorageOffset", to_string(offset)) - ("memberOffset", + updateStorageValueFunction(*structMembers[i].type, *toStructMembers[i].type) : + updateStorageValueFunction(*structMembers[i].type, *toStructMembers[i].type, offset) + ); + t("memberStorageSlotDiff", slotDiff.str()); + t("memberStorageOffset", to_string(offset)); + t( + "memberOffset", fromCalldata ? to_string(fromStructType.calldataOffsetOfMember(structMembers[i].name)) : fromStructType.memoryOffsetOfMember(structMembers[i].name).str() - ) - ("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*structMembers[i].type, fromCalldata)) - .render(); + ); + if (!fromCalldata || structMembers[i].type->isValueType()) + t("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*structMembers[i].type, fromCalldata)); + memberParams[i]["updateMemberCall"] = t.render(); } templ("member", memberParams); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 324893c5e..7b6d66d96 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -181,6 +181,10 @@ public: /// signature: (slot) -> std::string clearStorageArrayFunction(ArrayType const& _type); + /// @returns the name of a function that will copy array from calldata or memory to storage + /// signature (to_slot, from_ptr) -> + std::string copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType); + /// Returns the name of a function that will convert a given length to the /// size in memory (number of storage slots or calldata/memory bytes) it /// will require. diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 790bc4642..8e07edd75 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -387,7 +387,11 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) writeToLValue(*m_currentLValue, value); - if (m_currentLValue->type.category() != Type::Category::Struct && *_assignment.annotation().type != *TypeProvider::emptyTuple()) + if ( + m_currentLValue->type.category() != Type::Category::Struct && + m_currentLValue->type.category() != Type::Category::Array && + *_assignment.annotation().type != *TypeProvider::emptyTuple() + ) define(_assignment, value); m_currentLValue.reset(); diff --git a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol index a046a4376..d09460fa0 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol @@ -15,7 +15,8 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- -// h(uint256[2][]) : 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324 +// h(uint256[2][]): 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324 // i(uint256[2][2]): 123, 124, 223, 224 -> 32, 128, 123, 124, 223, 224 diff --git a/test/libsolidity/semanticTests/array/array_copy_cleanup_uint128.sol b/test/libsolidity/semanticTests/array/array_copy_cleanup_uint128.sol index a2405921d..5cfe4865c 100644 --- a/test/libsolidity/semanticTests/array/array_copy_cleanup_uint128.sol +++ b/test/libsolidity/semanticTests/array/array_copy_cleanup_uint128.sol @@ -19,5 +19,7 @@ contract C { return true; } } +// ==== +// compileViaYul: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/array/array_copy_cleanup_uint40.sol b/test/libsolidity/semanticTests/array/array_copy_cleanup_uint40.sol index ae2de79ce..37d78e6ab 100644 --- a/test/libsolidity/semanticTests/array/array_copy_cleanup_uint40.sol +++ b/test/libsolidity/semanticTests/array/array_copy_cleanup_uint40.sol @@ -44,5 +44,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/array/array_copy_memory_to_storage.sol b/test/libsolidity/semanticTests/array/array_copy_memory_to_storage.sol deleted file mode 100644 index 3055b0fa8..000000000 --- a/test/libsolidity/semanticTests/array/array_copy_memory_to_storage.sol +++ /dev/null @@ -1,11 +0,0 @@ -contract C { - uint[] a; - function f() public returns (uint, uint) { - uint[] memory b = new uint[](3); - b[0] = 1; - a = b; - return (a[0], a.length); - } -} -// ---- -// f() -> 1, 3 diff --git a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol index 9cec148c7..78d60913d 100644 --- a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol +++ b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol @@ -10,6 +10,8 @@ contract Test { return data; } } +// ==== +// compileViaYul: also // ---- // set(uint24[3][]): 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06 // data(uint256,uint256): 0x02, 0x02 -> 0x09 diff --git a/test/libsolidity/semanticTests/array/bytes_delete_element.sol b/test/libsolidity/semanticTests/array/bytes_delete_element.sol index e3a8ec19d..2f6b8176d 100644 --- a/test/libsolidity/semanticTests/array/bytes_delete_element.sol +++ b/test/libsolidity/semanticTests/array/bytes_delete_element.sol @@ -14,6 +14,5 @@ contract c { uint8(data[97]) == 97; } } - // ---- // test1() -> true diff --git a/test/libsolidity/semanticTests/array/bytes_length_member.sol b/test/libsolidity/semanticTests/array/bytes_length_member.sol index 8c4872017..d35fc88d3 100644 --- a/test/libsolidity/semanticTests/array/bytes_length_member.sol +++ b/test/libsolidity/semanticTests/array/bytes_length_member.sol @@ -10,7 +10,6 @@ contract c { bytes data; } - // ---- // getLength() -> 0 // set(): 1, 2 -> true diff --git a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol index 6a34670ff..c696002ad 100644 --- a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol +++ b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol @@ -7,6 +7,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // constructor(): 1, 2, 3 -> // a(uint256): 0 -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_clear_storage.sol b/test/libsolidity/semanticTests/array/copying/array_copy_clear_storage.sol new file mode 100644 index 000000000..98339880b --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_copy_clear_storage.sol @@ -0,0 +1,17 @@ +contract C { + uint256[] x; + function f() public returns(uint256) { + x.push(42); x.push(42); x.push(42); x.push(42); + uint256[] memory y = new uint256[](1); + y[0] = 23; + x = y; + assembly { sstore(x.slot, 4) } + assert(x[1] == 0); + assert(x[2] == 0); + return x[3]; + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_clear_storage_packed.sol b/test/libsolidity/semanticTests/array/copying/array_copy_clear_storage_packed.sol new file mode 100644 index 000000000..1be4c3931 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_copy_clear_storage_packed.sol @@ -0,0 +1,46 @@ +contract C { + uint128[] x; + uint64[] x1; + uint120[] x2; + function f() public returns(uint128) { + x.push(42); x.push(42); x.push(42); x.push(42); + uint128[] memory y = new uint128[](1); + y[0] = 23; + x = y; + assembly { sstore(x.slot, 4) } + assert(x[0] == 23); + assert(x[2] == 0); + assert(x[3] == 0); + return x[1]; + } + + function g() public returns(uint64) { + x1.push(42); x1.push(42); x1.push(42); x1.push(42); + uint64[] memory y = new uint64[](1); + y[0] = 23; + x1 = y; + assembly { sstore(x1.slot, 4) } + assert(x1[0] == 23); + assert(x1[2] == 0); + assert(x1[3] == 0); + return x1[1]; + } + + function h() public returns(uint120) { + x2.push(42); x2.push(42); x2.push(42); x2.push(42); + uint120[] memory y = new uint120[](1); + y[0] = 23; + x2 = y; + assembly { sstore(x2.slot, 4) } + assert(x2[0] == 23); + assert(x2[2] == 0); + assert(x2[3] == 0); + return x2[1]; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 0 +// g() -> 0 +// h() -> 0 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/array/array_copy_different_packing.sol b/test/libsolidity/semanticTests/array/copying/array_copy_different_packing.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_different_packing.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_different_packing.sol diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_copy_memory_to_storage.sol new file mode 100644 index 000000000..76dea2b18 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_copy_memory_to_storage.sol @@ -0,0 +1,30 @@ +contract C { + uint128[13] unused; + uint32[] a; + uint32[3] b; + function f() public returns (uint32, uint256) { + uint32[] memory m = new uint32[](3); + m[0] = 1; + m[1] = 2; + m[2] = 3; + a = m; + assert(a[0] == m[0]); + assert(a[1] == m[1]); + assert(a[2] == m[2]); + return (a[0], a.length); + } + function g() public returns (uint32, uint32, uint32) { + uint32[3] memory m; + m[0] = 1; m[1] = 2; m[2] = 3; + a = m; + b = m; + assert(a[0] == b[0] && a[1] == b[1] && a[2] == b[2]); + assert(a.length == b.length); + return (a[0], b[1], a[2]); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 3 +// g() -> 1, 2, 3 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/array/array_copy_nested_array.sol b/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_nested_array.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol diff --git a/test/libsolidity/semanticTests/array/array_copy_storage_abi_signed.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_abi_signed.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_storage_abi_signed.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_storage_abi_signed.sol diff --git a/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_dynamic.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_dynamic.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_storage_storage_static_dynamic.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_dynamic.sol diff --git a/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_static.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_storage_storage_static_static.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol diff --git a/test/libsolidity/semanticTests/array/array_copy_storage_to_memory.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_storage_to_memory.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_storage_to_memory.sol diff --git a/test/libsolidity/semanticTests/array/array_copy_target_leftover2.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover2.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_target_leftover2.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_target_leftover2.sol diff --git a/test/libsolidity/semanticTests/array/array_copy_target_simple.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol similarity index 100% rename from test/libsolidity/semanticTests/array/array_copy_target_simple.sol rename to test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol diff --git a/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol new file mode 100644 index 000000000..5421eb7a0 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol @@ -0,0 +1,16 @@ +pragma experimental ABIEncoderV2; + +contract c { + uint256[][] a; + + function test(uint256[][] calldata d) external returns (uint256, uint256) { + a = d; + assert(a[0][0] == d[0][0]); + assert(a[0][1] == d[0][1]); + return (a.length, a[1][0] + a[1][1]); + } +} +// ==== +// compileViaYul: true +// ---- +// test(uint256[][]): 0x20, 2, 0x40, 0x40, 2, 23, 42 -> 2, 65 diff --git a/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol new file mode 100644 index 000000000..45714648b --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol @@ -0,0 +1,45 @@ +contract Test { + uint128[13] unused; + uint256[][] a; + uint256[4][] b; + uint256[2][3] c; + + function test() external returns (uint256) { + uint256[][] memory m = new uint256[][](2); + m[0] = new uint256[](3); + m[0][0] = 7; m[0][1] = 8; m[0][2] = 9; + m[1] = new uint256[](4); + m[1][1] = 7; m[1][2] = 8; m[1][3] = 9; + a = m; + return a[0][0] + a[0][1] + a[1][3]; + } + + function test1() external returns (uint256) { + uint256[2][] memory m = new uint256[2][](1); + m[0][0] = 1; m[0][1] = 2; + b = m; + return b[0][0] + b[0][1]; + } + + function test2() external returns (uint256) { + uint256[2][2] memory m; + m[0][0] = 1; m[1][1] = 2; m[0][1] = 3; + c = m; + return c[0][0] + c[1][1] + c[0][1]; + } + + function test3() external returns (uint256) { + uint256[2][3] memory m; + m[0][0] = 7; m[1][0] = 8; m[2][0] = 9; + m[0][1] = 7; m[1][1] = 8; m[2][1] = 9; + a = m; + return a[0][0] + a[1][0] + a[2][1]; + } +} +// ==== +// compileViaYul: also +// ---- +// test() -> 24 +// test1() -> 3 +// test2() -> 6 +// test3() -> 24 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol new file mode 100644 index 000000000..3329391f3 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol @@ -0,0 +1,19 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint128 a; + uint64 b; + uint128 c; + } + uint128[137] unused; + S[] s; + function f(S[] calldata c) public returns (uint128, uint64, uint128) { + s = c; + return (s[2].a, s[1].b, s[0].c); + } +} +// ==== +// compileViaYul: true +// ---- +// f((uint128, uint64, uint128)[]): 0x20, 3, 0, 0, 12, 0, 11, 0, 10, 0, 0 -> 10, 11, 12 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/array/copying/array_of_struct_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_struct_memory_to_storage.sol new file mode 100644 index 000000000..73fde3aba --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_of_struct_memory_to_storage.sol @@ -0,0 +1,21 @@ +contract C { + struct S { + uint128 a; + uint64 b; + uint128 c; + } + uint128[137] unused; + S[] s; + function f() public returns (uint128, uint64, uint128) { + S[] memory m = new S[](3); + m[2].a = 10; + m[1].b = 11; + m[0].c = 12; + s = m; + return (s[2].a, s[1].b, s[0].c); + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 10, 11, 12 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol new file mode 100644 index 000000000..dba6af8ef --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol @@ -0,0 +1,18 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint256[] a; + } + + S[] s; + + function f(S[] calldata c) external returns (uint256, uint256) { + s = c; + return (s[1].a.length, s[1].a[0]); + } +} +// ==== +// compileViaYul: true +// ---- +// f((uint256[])[]): 0x20, 3, 0x60, 0x60, 0x60, 0x20, 3, 1, 2, 3 -> 3, 1 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_memory_to_storage.sol new file mode 100644 index 000000000..d24cd563d --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_memory_to_storage.sol @@ -0,0 +1,28 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint136 p; + uint128[3] b; + uint128[] c; + } + + S[] s; + + function f() external returns (uint256, uint256, uint128, uint128) { + S[] memory m = new S[](3); + m[1] = S(0, [uint128(1), 2, 3], new uint128[](3)); + m[1].c[0] = 1; + m[1].c[1] = 2; + m[1].c[2] = 3; + s = m; + assert(s.length == m.length); + assert(s[1].b[1] == m[1].b[1]); + assert(s[1].c[0] == m[1].c[0]); + return (s[1].b.length, s[1].c.length, s[1].b[2], s[1].c[0]); + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 3, 3, 3, 1 diff --git a/test/libsolidity/semanticTests/array/bytes_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/array/bytes_memory_to_storage.sol rename to test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol diff --git a/test/libsolidity/semanticTests/array/bytes_storage_to_memory.sol b/test/libsolidity/semanticTests/array/copying/bytes_storage_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/array/bytes_storage_to_memory.sol rename to test/libsolidity/semanticTests/array/copying/bytes_storage_to_memory.sol diff --git a/test/libsolidity/semanticTests/array/copying/calldata_array_dynamic_to_storage.sol b/test/libsolidity/semanticTests/array/copying/calldata_array_dynamic_to_storage.sol new file mode 100644 index 000000000..c45c2c52f --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/calldata_array_dynamic_to_storage.sol @@ -0,0 +1,13 @@ +pragma experimental ABIEncoderV2; + +contract C { + uint256[] s; + function f(uint256[] calldata data) external returns (uint) { + s = data; + return s[0]; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256[]): 0x20, 0x03, 0x1, 0x2, 0x3 -> 0x1 diff --git a/test/libsolidity/semanticTests/array/calldata_array_of_struct_to_memory.sol b/test/libsolidity/semanticTests/array/copying/calldata_array_of_struct_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/array/calldata_array_of_struct_to_memory.sol rename to test/libsolidity/semanticTests/array/copying/calldata_array_of_struct_to_memory.sol diff --git a/test/libsolidity/semanticTests/calldata/calldata_bytes_array_to_memory.sol b/test/libsolidity/semanticTests/array/copying/calldata_bytes_array_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/calldata/calldata_bytes_array_to_memory.sol rename to test/libsolidity/semanticTests/array/copying/calldata_bytes_array_to_memory.sol diff --git a/test/libsolidity/semanticTests/calldata/calldata_bytes_to_storage.sol b/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/calldata/calldata_bytes_to_storage.sol rename to test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol diff --git a/test/libsolidity/semanticTests/array/calldata_dynamic_array_to_memory.sol b/test/libsolidity/semanticTests/array/copying/calldata_dynamic_array_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/array/calldata_dynamic_array_to_memory.sol rename to test/libsolidity/semanticTests/array/copying/calldata_dynamic_array_to_memory.sol diff --git a/test/libsolidity/semanticTests/array/copy_function_storage_array.sol b/test/libsolidity/semanticTests/array/copying/copy_function_storage_array.sol similarity index 100% rename from test/libsolidity/semanticTests/array/copy_function_storage_array.sol rename to test/libsolidity/semanticTests/array/copying/copy_function_storage_array.sol diff --git a/test/libsolidity/semanticTests/array/copy_internal_function_array_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/array/copy_internal_function_array_to_storage.sol rename to test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol diff --git a/test/libsolidity/semanticTests/array/fixed_bytes_index_access.sol b/test/libsolidity/semanticTests/array/fixed_bytes_index_access.sol index 9ab74eaf3..40cc65763 100644 --- a/test/libsolidity/semanticTests/array/fixed_bytes_index_access.sol +++ b/test/libsolidity/semanticTests/array/fixed_bytes_index_access.sol @@ -11,6 +11,8 @@ contract C { return uint256(uint8(data[0][4])); } } +// ==== +// compileViaYul: also // ---- // f(bytes32): "789" -> "9" // g(bytes32): "789" -> 0x35 diff --git a/test/libsolidity/semanticTests/array/inline_array_return.sol b/test/libsolidity/semanticTests/array/inline_array_return.sol index e247d1558..5bdb761f1 100644 --- a/test/libsolidity/semanticTests/array/inline_array_return.sol +++ b/test/libsolidity/semanticTests/array/inline_array_return.sol @@ -11,5 +11,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol index d59f2cd19..099202c95 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol @@ -8,6 +8,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // constructor(): 1, 2, 3, 4 -> // a() -> 1 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_storage_memory_1.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_storage_memory_1.sol index 3434cca01..087811c68 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_storage_memory_1.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_storage_memory_1.sol @@ -22,6 +22,8 @@ contract test { return ret; } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1 // f(bool): false -> 2 diff --git a/test/libsolidity/semanticTests/storage/array_accessor.sol b/test/libsolidity/semanticTests/storage/array_accessor.sol index 599931a37..f9efae437 100644 --- a/test/libsolidity/semanticTests/storage/array_accessor.sol +++ b/test/libsolidity/semanticTests/storage/array_accessor.sol @@ -22,6 +22,8 @@ contract test { multiple_map[2][1][2].finalArray[3] = 5; } } +// ==== +// compileViaYul: also // ---- // data(uint256): 0 -> 8 // data(uint256): 8 -> FAILURE diff --git a/test/libsolidity/semanticTests/storage/chop_sign_bits.sol b/test/libsolidity/semanticTests/storage/chop_sign_bits.sol index 51cba0261..4993ecb35 100644 --- a/test/libsolidity/semanticTests/storage/chop_sign_bits.sol +++ b/test/libsolidity/semanticTests/storage/chop_sign_bits.sol @@ -19,6 +19,8 @@ contract Test { return z; } } +// ==== +// compileViaYul: also // ---- // x(uint256): 0 -> -1 // x(uint256): 1 -> -2 diff --git a/test/libsolidity/semanticTests/structs/struct_constructor_nested.sol b/test/libsolidity/semanticTests/structs/struct_constructor_nested.sol index 7ce22e45a..7868a620e 100644 --- a/test/libsolidity/semanticTests/structs/struct_constructor_nested.sol +++ b/test/libsolidity/semanticTests/structs/struct_constructor_nested.sol @@ -26,5 +26,7 @@ contract C { x2 = s.s3.x2; } } +// ==== +// compileViaYul: also // ---- // get() -> 0x01, 0x00, 0x09, 0x00, 0x04, 0x05 diff --git a/test/libsolidity/semanticTests/various/store_bytes.sol b/test/libsolidity/semanticTests/various/store_bytes.sol index 99eb1acff..4b92a251a 100644 --- a/test/libsolidity/semanticTests/various/store_bytes.sol +++ b/test/libsolidity/semanticTests/various/store_bytes.sol @@ -8,7 +8,6 @@ contract C { bytes savedData; } - // ---- // save() -> 24 # empty copy loop # // save(): "abcdefg" -> 24