[Sol->Yul] Implementing struct copying from calldata to storage

This commit is contained in:
Djordje Mijovic 2020-08-17 13:50:09 +02:00
parent 381784dd89
commit 762e3f3cee
2 changed files with 35 additions and 3 deletions

View File

@ -1427,7 +1427,7 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool
bool isStruct = structMembers[i].type->category() == Type::Category::Struct;
memberSetValues[i]["setMember"] = Whiskers(R"(
mstore(add(value, <memberMemoryOffset>), <readFromStorage>(add(slot, <memberSlotDiff>)<?notStruct>, <memberStorageOffset></notStruct>))
mstore(add(value, <memberMemoryOffset>), <readFromStorage>(add(slot, <memberSlotDiff>)<?hasOffset>, <memberStorageOffset></hasOffset>))
)")
("memberMemoryOffset", structType.memoryOffsetOfMember(structMembers[i].name).str())
("memberSlotDiff", memberSlotDiff.str())
@ -1437,7 +1437,7 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool
readFromStorage(*structMembers[i].type, memberStorageOffset, true) :
readFromStorageDynamic(*structMembers[i].type, true)
)
("notStruct", !isStruct)
("hasOffset", !isStruct)
.render();
}
@ -1548,11 +1548,16 @@ string YulUtilFunctions::updateStorageValueFunction(
auto const& fromStructType = dynamic_cast<StructType const&>(*_fromType);
auto const& toStructType = dynamic_cast<StructType const&>(_toType);
solAssert(fromStructType.structDefinition() == toStructType.structDefinition(), "");
solUnimplementedAssert(fromStructType.location() == DataLocation::Memory, "");
solAssert(fromStructType.location() != DataLocation::Storage, "");
solUnimplementedAssert(_offset.has_value() && _offset.value() == 0, "");
Whiskers templ(R"(
function <functionName>(slot, value) {
<?fromCalldata>
let valueMem := <convertToMemory>(value)
<!fromCalldata>
let valueMem := value
</fromCalldata>
<#member>
{
<updateMemberCall>
@ -1561,6 +1566,12 @@ string YulUtilFunctions::updateStorageValueFunction(
}
)");
templ("functionName", functionName);
templ("fromCalldata", fromStructType.location() == DataLocation::CallData);
if (fromStructType.location() == DataLocation::CallData)
templ("convertToMemory", conversionFunction(
fromStructType,
*TypeProvider::structType(toStructType.structDefinition(), DataLocation::Memory)
));
MemberList::MemberMap toStructMembers = toStructType.nativeMembers(nullptr);
MemberList::MemberMap fromStructMembers = fromStructType.nativeMembers(nullptr);

View File

@ -0,0 +1,21 @@
pragma experimental ABIEncoderV2;
contract C {
struct S {
uint256 a;
uint256 b;
bytes2 c;
}
S s;
function f(uint32 a, S calldata c, uint256 b) external returns (uint256, uint256, byte) {
s = c;
return (s.a, s.b, s.c[1]);
}
}
// ====
// compileViaYul: true
// ----
// f(uint32, (uint256, uint256, bytes2), uint256): 1, 42, 23, "ab", 1 -> 42, 23, "b"