mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10415 from ethereum/arrayClearingStorageSol2Yul
[Sol->Yul] Fixing copying from storage to storage.
This commit is contained in:
commit
388fcddd23
@ -1000,10 +1000,9 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
std::string YulUtilFunctions::resizeArrayFunction(ArrayType const& _type)
|
||||||
{
|
{
|
||||||
solAssert(_type.location() == DataLocation::Storage, "");
|
solAssert(_type.location() == DataLocation::Storage, "");
|
||||||
solAssert(_type.isDynamicallySized(), "");
|
|
||||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "...");
|
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "...");
|
||||||
|
|
||||||
if (_type.isByteArray())
|
if (_type.isByteArray())
|
||||||
@ -1019,8 +1018,10 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
|||||||
|
|
||||||
let oldLen := <fetchLength>(array)
|
let oldLen := <fetchLength>(array)
|
||||||
|
|
||||||
|
<?isDynamic>
|
||||||
// Store new length
|
// Store new length
|
||||||
sstore(array, newLen)
|
sstore(array, newLen)
|
||||||
|
</isDynamic>
|
||||||
|
|
||||||
// Size was reduced, clear end of array
|
// Size was reduced, clear end of array
|
||||||
if lt(newLen, oldLen) {
|
if lt(newLen, oldLen) {
|
||||||
@ -1041,6 +1042,7 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
|||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("panic", panicFunction())
|
("panic", panicFunction())
|
||||||
("fetchLength", arrayLengthFunction(_type))
|
("fetchLength", arrayLengthFunction(_type))
|
||||||
|
("isDynamic", _type.isDynamicallySized())
|
||||||
("convertToSize", arrayConvertLengthToSize(_type))
|
("convertToSize", arrayConvertLengthToSize(_type))
|
||||||
("dataPosition", arrayDataAreaFunction(_type))
|
("dataPosition", arrayDataAreaFunction(_type))
|
||||||
("clearStorageRange", clearStorageRangeFunction(*_type.baseType()))
|
("clearStorageRange", clearStorageRangeFunction(*_type.baseType()))
|
||||||
@ -1425,7 +1427,7 @@ string YulUtilFunctions::clearStorageArrayFunction(ArrayType const& _type)
|
|||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("dynamic", _type.isDynamicallySized())
|
("dynamic", _type.isDynamicallySized())
|
||||||
("resizeArray", _type.isDynamicallySized() ? resizeDynamicArrayFunction(_type) : "")
|
("resizeArray", _type.isDynamicallySized() ? resizeArrayFunction(_type) : "")
|
||||||
(
|
(
|
||||||
"clearRange",
|
"clearRange",
|
||||||
clearStorageRangeFunction(
|
clearStorageRangeFunction(
|
||||||
@ -1497,6 +1499,9 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
|
|||||||
*_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast<ReferenceType const&>(_toType),
|
*_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast<ReferenceType const&>(_toType),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
if (!_toType.isDynamicallySized())
|
||||||
|
solAssert(!_fromType.isDynamicallySized() && _fromType.length() <= _toType.length(), "");
|
||||||
|
|
||||||
if (_fromType.isByteArray())
|
if (_fromType.isByteArray())
|
||||||
return copyByteArrayToStorageFunction(_fromType, _toType);
|
return copyByteArrayToStorageFunction(_fromType, _toType);
|
||||||
if (_fromType.dataStoredIn(DataLocation::Storage) && _toType.baseType()->isValueType())
|
if (_fromType.dataStoredIn(DataLocation::Storage) && _toType.baseType()->isValueType())
|
||||||
@ -1508,9 +1513,8 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
|
|||||||
function <functionName>(slot, value<?isFromDynamicCalldata>, len</isFromDynamicCalldata>) {
|
function <functionName>(slot, value<?isFromDynamicCalldata>, len</isFromDynamicCalldata>) {
|
||||||
<?fromStorage> if eq(slot, value) { leave } </fromStorage>
|
<?fromStorage> if eq(slot, value) { leave } </fromStorage>
|
||||||
let length := <arrayLength>(value<?isFromDynamicCalldata>, len</isFromDynamicCalldata>)
|
let length := <arrayLength>(value<?isFromDynamicCalldata>, len</isFromDynamicCalldata>)
|
||||||
<?isToDynamic>
|
|
||||||
<resizeArray>(slot, length)
|
<resizeArray>(slot, length)
|
||||||
</isToDynamic>
|
|
||||||
|
|
||||||
let srcPtr := <srcDataLocation>(value)
|
let srcPtr := <srcDataLocation>(value)
|
||||||
|
|
||||||
@ -1564,7 +1568,6 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
|
|||||||
bool fromMemory = _fromType.dataStoredIn(DataLocation::Memory);
|
bool fromMemory = _fromType.dataStoredIn(DataLocation::Memory);
|
||||||
templ("fromMemory", fromMemory);
|
templ("fromMemory", fromMemory);
|
||||||
templ("fromCalldata", fromCalldata);
|
templ("fromCalldata", fromCalldata);
|
||||||
templ("isToDynamic", _toType.isDynamicallySized());
|
|
||||||
templ("srcDataLocation", arrayDataAreaFunction(_fromType));
|
templ("srcDataLocation", arrayDataAreaFunction(_fromType));
|
||||||
if (fromCalldata)
|
if (fromCalldata)
|
||||||
{
|
{
|
||||||
@ -1573,8 +1576,7 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
|
|||||||
if (_fromType.baseType()->isDynamicallyEncoded())
|
if (_fromType.baseType()->isDynamicallyEncoded())
|
||||||
templ("accessCalldataTail", accessCalldataTailFunction(*_fromType.baseType()));
|
templ("accessCalldataTail", accessCalldataTailFunction(*_fromType.baseType()));
|
||||||
}
|
}
|
||||||
if (_toType.isDynamicallySized())
|
templ("resizeArray", resizeArrayFunction(_toType));
|
||||||
templ("resizeArray", resizeDynamicArrayFunction(_toType));
|
|
||||||
templ("arrayLength",arrayLengthFunction(_fromType));
|
templ("arrayLength",arrayLengthFunction(_fromType));
|
||||||
templ("isValueType", _fromType.baseType()->isValueType());
|
templ("isValueType", _fromType.baseType()->isValueType());
|
||||||
templ("dstDataLocation", arrayDataAreaFunction(_toType));
|
templ("dstDataLocation", arrayDataAreaFunction(_toType));
|
||||||
@ -1693,6 +1695,8 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const&
|
|||||||
solAssert(_fromType.dataStoredIn(DataLocation::Storage) && _toType.baseType()->isValueType(), "");
|
solAssert(_fromType.dataStoredIn(DataLocation::Storage) && _toType.baseType()->isValueType(), "");
|
||||||
solAssert(_toType.dataStoredIn(DataLocation::Storage), "");
|
solAssert(_toType.dataStoredIn(DataLocation::Storage), "");
|
||||||
|
|
||||||
|
solUnimplementedAssert(_fromType.storageStride() == _toType.storageStride(), "");
|
||||||
|
|
||||||
string functionName = "copy_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier();
|
string functionName = "copy_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier();
|
||||||
return m_functionCollector.createFunction(functionName, [&](){
|
return m_functionCollector.createFunction(functionName, [&](){
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
@ -1701,9 +1705,7 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const&
|
|||||||
let length := <arrayLength>(src)
|
let length := <arrayLength>(src)
|
||||||
// Make sure array length is sane
|
// Make sure array length is sane
|
||||||
if gt(length, 0xffffffffffffffff) { <panic>() }
|
if gt(length, 0xffffffffffffffff) { <panic>() }
|
||||||
<?isToDynamic>
|
|
||||||
<resizeArray>(dst, length)
|
<resizeArray>(dst, length)
|
||||||
</isToDynamic>
|
|
||||||
|
|
||||||
let srcPtr := <srcDataLocation>(src)
|
let srcPtr := <srcDataLocation>(src)
|
||||||
|
|
||||||
@ -1723,9 +1725,7 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const&
|
|||||||
if (_fromType.dataStoredIn(DataLocation::Storage))
|
if (_fromType.dataStoredIn(DataLocation::Storage))
|
||||||
solAssert(!_fromType.isValueType(), "");
|
solAssert(!_fromType.isValueType(), "");
|
||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
templ("isToDynamic", _toType.isDynamicallySized());
|
templ("resizeArray", resizeArrayFunction(_toType));
|
||||||
if (_toType.isDynamicallySized())
|
|
||||||
templ("resizeArray", resizeDynamicArrayFunction(_toType));
|
|
||||||
templ("arrayLength",arrayLengthFunction(_fromType));
|
templ("arrayLength",arrayLengthFunction(_fromType));
|
||||||
templ("panic", panicFunction());
|
templ("panic", panicFunction());
|
||||||
templ("srcDataLocation", arrayDataAreaFunction(_fromType));
|
templ("srcDataLocation", arrayDataAreaFunction(_fromType));
|
||||||
|
@ -171,8 +171,9 @@ public:
|
|||||||
std::string arrayLengthFunction(ArrayType const& _type);
|
std::string arrayLengthFunction(ArrayType const& _type);
|
||||||
|
|
||||||
/// @returns the name of a function that resizes a storage array
|
/// @returns the name of a function that resizes a storage array
|
||||||
|
/// for statically sized arrays, it will just clean-up elements of array starting from newLen until the end
|
||||||
/// signature: (array, newLen)
|
/// signature: (array, newLen)
|
||||||
std::string resizeDynamicArrayFunction(ArrayType const& _type);
|
std::string resizeArrayFunction(ArrayType const& _type);
|
||||||
|
|
||||||
/// @returns the name of a function that reduces the size of a storage array by one element
|
/// @returns the name of a function that reduces the size of a storage array by one element
|
||||||
/// signature: (array)
|
/// signature: (array)
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
contract c {
|
||||||
|
uint64[] data1;
|
||||||
|
uint256[] data2;
|
||||||
|
|
||||||
|
function test() public returns (uint256 x, uint256 y) {
|
||||||
|
data2.push(11);
|
||||||
|
data1.push(0);
|
||||||
|
data1.push(1);
|
||||||
|
data1.push(2);
|
||||||
|
data1.push(3);
|
||||||
|
data1.push(4);
|
||||||
|
data2 = data1;
|
||||||
|
assert(data1[0] == data2[0]);
|
||||||
|
x = data2.length;
|
||||||
|
y = data2[4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// test() -> 5, 4
|
@ -0,0 +1,22 @@
|
|||||||
|
contract c {
|
||||||
|
uint256[] data1;
|
||||||
|
uint256[] data2;
|
||||||
|
|
||||||
|
function test() public returns (uint256 x, uint256 y) {
|
||||||
|
data2.push(11);
|
||||||
|
data1.push(0);
|
||||||
|
data1.push(1);
|
||||||
|
data1.push(2);
|
||||||
|
data1.push(3);
|
||||||
|
data1.push(4);
|
||||||
|
data2 = data1;
|
||||||
|
assert(data1[0] == data2[0]);
|
||||||
|
x = data2.length;
|
||||||
|
y = data2[4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test() -> 5, 4
|
@ -13,5 +13,7 @@ contract c {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// test() -> 8, 0
|
// test() -> 8, 0
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
byte[32] data1;
|
||||||
|
bytes2[10] data2;
|
||||||
|
function f() external {
|
||||||
|
data1 = data2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 7407: (99-104): Type bytes2[10] storage ref is not implicitly convertible to expected type bytes1[32] storage ref.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
uint64[32] data1;
|
||||||
|
uint256[10] data2;
|
||||||
|
function f() external {
|
||||||
|
data1 = data2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 7407: (102-107): Type uint256[10] storage ref is not implicitly convertible to expected type uint64[32] storage ref.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
uint256[10] data1;
|
||||||
|
uint256[] data2;
|
||||||
|
function f() external {
|
||||||
|
data1 = data2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 7407: (101-106): Type uint256[] storage ref is not implicitly convertible to expected type uint256[10] storage ref.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
uint256[10] data1;
|
||||||
|
uint256[18] data2;
|
||||||
|
function f() external {
|
||||||
|
data1 = data2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 7407: (103-108): Type uint256[18] storage ref is not implicitly convertible to expected type uint256[10] storage ref.
|
Loading…
Reference in New Issue
Block a user