Fix assignment of struct containing array of mappings

This commit is contained in:
mingchuan 2019-05-24 16:40:15 +08:00
parent 2a2cea08dd
commit bf8af89bba
No known key found for this signature in database
GPG Key ID: 607CD25FA2D03651
6 changed files with 69 additions and 5 deletions

View File

@ -25,6 +25,7 @@ Bugfixes:
* SMTChecker: Fix internal error in fixed point operations.
* SMTChecker: Fix internal error in assignment to unsupported type.
* SMTChecker: Fix internal error in branching when inlining function calls that modify local variables.
* Code Generator: Fix assertion failure when assign structs containing array of mapping.

View File

@ -371,7 +371,8 @@ shown in the following example:
campaignID = numCampaigns++; // campaignID is return variable
// Creates new struct in memory and copies it to storage.
// We leave out the mapping type, because it is not valid in memory.
// If structs are copied (even from storage to storage), mapping types
// If structs are copied (even from storage to storage),
// types that are not valid outside of storage (ex. mappings and array of mappings)
// are always omitted, because they cannot be enumerated.
campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
}

View File

@ -2068,7 +2068,8 @@ MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const
{
TypePointer type = variable->annotation().type;
solAssert(type, "");
// Skip all mapping members if we are not in storage.
// If we are not in storage, skip all members that cannot live outside of storage,
// ex. mappings and array of mappings
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
continue;
members.emplace_back(

View File

@ -288,7 +288,8 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
{
solAssert(
_sourceType.category() == m_dataType->category(),
"Wrong type conversation for assignment.");
"Wrong type conversation for assignment."
);
if (m_dataType->category() == Type::Category::Array)
{
m_context << Instruction::POP; // remove byte offset
@ -313,9 +314,9 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
for (auto const& member: structType.members(nullptr))
{
// assign each member that is not a mapping
// assign each member that can live outside of storage
TypePointer const& memberType = member.type;
if (memberType->category() == Type::Category::Mapping)
if (!memberType->canLiveOutsideStorage())
continue;
TypePointer sourceMemberType = sourceType.memberType(member.name);
if (sourceType.location() == DataLocation::Storage)

View File

@ -0,0 +1,48 @@
contract Test {
struct A {
mapping(uint=>uint) m;
}
struct B {
mapping(uint=>uint) m;
uint x;
}
struct C {
mapping(uint=>uint)[] ma;
}
struct D {
A[] a;
}
A storageA;
B storageB;
C storageC;
D storageD;
constructor() public {
storageA.m[1] = 2;
storageB.m[3] = 4;
storageB.x = 5;
storageC.ma.length = 6;
storageD.a.length = 7;
}
function run() public returns (uint, uint, uint, uint, uint, uint) {
A memory memoryA = A();
B memory memoryB = B(42);
C memory memoryC = C();
D memory memoryD1 = D(new A[](999));
D memory memoryD2 = storageD;
storageA = memoryA;
storageB = memoryB;
storageC = memoryC;
// the following line does not compile because unimplemented
// storageD = memoryD1;
return (
storageA.m[1],
storageB.x,
memoryB.x,
storageC.ma.length,
memoryD1.a.length,
memoryD2.a.length
);
}
}
// ----
// run() -> 2, 42, 42, 6, 999, 7

View File

@ -0,0 +1,12 @@
contract Test {
struct S1 { uint8 a; mapping(uint => uint)[] b1; uint8 c; }
struct S2 { uint8 a; S1[] b2; uint8 c; }
S2 s2;
function f() public {
S2 memory x = s2;
x.b2.length;
x.b2[1].b1[2][3];
}
}
// ----
// TypeError: (208-218): Member "b1" is not available in struct Test.S1 memory outside of storage.