mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fix assignment of struct containing array of mappings
This commit is contained in:
parent
2a2cea08dd
commit
bf8af89bba
@ -25,6 +25,7 @@ Bugfixes:
|
|||||||
* SMTChecker: Fix internal error in fixed point operations.
|
* SMTChecker: Fix internal error in fixed point operations.
|
||||||
* SMTChecker: Fix internal error in assignment to unsupported type.
|
* SMTChecker: Fix internal error in assignment to unsupported type.
|
||||||
* SMTChecker: Fix internal error in branching when inlining function calls that modify local variables.
|
* 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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -371,7 +371,8 @@ shown in the following example:
|
|||||||
campaignID = numCampaigns++; // campaignID is return variable
|
campaignID = numCampaigns++; // campaignID is return variable
|
||||||
// Creates new struct in memory and copies it to storage.
|
// Creates new struct in memory and copies it to storage.
|
||||||
// We leave out the mapping type, because it is not valid in memory.
|
// 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.
|
// are always omitted, because they cannot be enumerated.
|
||||||
campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
|
campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -2068,7 +2068,8 @@ MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const
|
|||||||
{
|
{
|
||||||
TypePointer type = variable->annotation().type;
|
TypePointer type = variable->annotation().type;
|
||||||
solAssert(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())
|
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
|
||||||
continue;
|
continue;
|
||||||
members.emplace_back(
|
members.emplace_back(
|
||||||
|
@ -288,7 +288,8 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
|||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
_sourceType.category() == m_dataType->category(),
|
_sourceType.category() == m_dataType->category(),
|
||||||
"Wrong type conversation for assignment.");
|
"Wrong type conversation for assignment."
|
||||||
|
);
|
||||||
if (m_dataType->category() == Type::Category::Array)
|
if (m_dataType->category() == Type::Category::Array)
|
||||||
{
|
{
|
||||||
m_context << Instruction::POP; // remove byte offset
|
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.");
|
solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
|
||||||
for (auto const& member: structType.members(nullptr))
|
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;
|
TypePointer const& memberType = member.type;
|
||||||
if (memberType->category() == Type::Category::Mapping)
|
if (!memberType->canLiveOutsideStorage())
|
||||||
continue;
|
continue;
|
||||||
TypePointer sourceMemberType = sourceType.memberType(member.name);
|
TypePointer sourceMemberType = sourceType.memberType(member.name);
|
||||||
if (sourceType.location() == DataLocation::Storage)
|
if (sourceType.location() == DataLocation::Storage)
|
||||||
|
@ -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
|
@ -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.
|
Loading…
Reference in New Issue
Block a user