Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copying of type struct memory[] memory to storage not yet supported

How do I add a new empty Parent instance to the list of parents in the code sample below? I keep getting

UnimplementedFeatureError: Copying of type struct Test.Child memory[] memory
to storage not yet supported.

Minimal example:

contract Test {
  struct Child { } 
  struct Parent { Child[] children; }

  Parent[] parents;

  function test() {
    parents.push(Parent(new Child[](0)));
  }
}
like image 410
Jonas H. Avatar asked Mar 18 '18 08:03

Jonas H.


2 Answers

You can't really do what you're trying to do with dynamic arrays. You'll need to change your approach slightly to get it to work.

contract Test {
  struct Child { } 
  struct Parent { 
      mapping(uint => Child) children;
      uint childrenSize;
  }

  Parent[] parents;

  function testWithEmptyChildren() public {
      parents.push(Parent({childrenSize: 0}));
  }

  function testWithChild(uint index) public {
      Parent storage p = parents[index];

      p.children[p.childrenSize] = Child();
      p.childrenSize++;
  }
}

Use Parent.childrenSize if you need to iterate through Parent.children somewhere else in your contract.

Alternatively, you can increase the size of the parents array and use Solidity's default zero values.

contract Test {
  struct Child { } 
  struct Parent { Child[] children; }

  Parent[] parents;

  function test() public {
      parents.length++;
      Parent storage p = parents[parents.length - 1];

      Child memory c;

      p.children.push(c);
  }
}
like image 143
Adam Kipnis Avatar answered Nov 19 '22 15:11

Adam Kipnis


It doesn’t work (as of Solidity 0.4.24, at least) if the child array type is another struct, but it works if the child array type is a primitive type like uint256.

So if you have e.g.

struct Child {
  uint256 x;
  bytes32 y;
}

then you could define:

struct Parent {
  uint256[] childXs;
  bytes32[] childYs;
}

and then you could write:

parents.push(Parent({
    childXs: new uint256[](0),
    childYs: new bytes32[](0)
}));

(Same workaround is applicable when you want to pass an array of structs as an argument to a public function.)

It’s not ideal, but it works.

P.S. Actually (if you are using the primitive array children) you could just write:

Parent memory p;
parents.push(p);
like image 33
dwardu Avatar answered Nov 19 '22 13:11

dwardu