Skip to content

Commit 1fbee82

Browse files
authored
Merge pull request #13464 from ethereum/copying_reference_types
Add tests for copying reference types between data locations
2 parents 5f63b3c + 0eae9e7 commit 1fbee82

29 files changed

+1223
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
mapping (uint => uint8[][]) m;
5+
6+
uint8[][] s;
7+
8+
constructor() {
9+
s = new uint8[][](2);
10+
11+
s[0] = new uint8[](2);
12+
s[0][0] = 10;
13+
s[0][1] = 11;
14+
15+
s[1] = new uint8[](3);
16+
s[1][0] = 12;
17+
s[1][1] = 13;
18+
s[1][2] = 14;
19+
}
20+
21+
function from_storage() public returns (uint8[][] memory) {
22+
m[0] = new uint8[][](2);
23+
m[0][0] = s[0];
24+
m[0][1] = s[1];
25+
return m[0];
26+
}
27+
28+
29+
function from_storage_ptr() public returns (uint8[][] memory) {
30+
uint8[][] storage sPtr = s;
31+
m[0] = new uint8[][](2);
32+
m[0][0] = sPtr[0];
33+
m[0][1] = sPtr[1];
34+
return m[0];
35+
}
36+
37+
38+
function from_memory() public returns (uint8[][] memory) {
39+
uint8[][] memory a = s;
40+
m[0] = new uint8[][](2);
41+
m[0][0] = a[0];
42+
m[0][1] = a[1];
43+
return m[0];
44+
}
45+
46+
function from_calldata(uint8[][] calldata _a) public returns (uint8[][] memory) {
47+
m[0] = new uint8[][](2);
48+
m[0][0] = _a[0];
49+
m[0][1] = _a[1];
50+
return m[0];
51+
}
52+
}
53+
54+
// ----
55+
// from_storage() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
56+
// gas irOptimized: 150098
57+
// gas legacy: 150830
58+
// gas legacyOptimized: 148728
59+
// from_storage_ptr() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
60+
// from_memory() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
61+
// from_calldata(uint8[][]): 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14 -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
uint256[][] a1;
5+
uint256[][2] a2;
6+
uint256[2][] a3;
7+
uint256[2][2] a4;
8+
9+
constructor() {
10+
a1 = new uint256[][](2);
11+
a1[0] = [1, 2];
12+
a1[1] = [3, 4, 5];
13+
14+
a2[0] = [6, 7, 8];
15+
a2[1] = [9];
16+
17+
a3.push([1, 2]);
18+
a3.push([3, 4]);
19+
a3.push([5, 6]);
20+
21+
a4 = [[10, 11], [12, 13]];
22+
}
23+
24+
function test1() external returns (uint256[][] memory) {
25+
return a1;
26+
}
27+
28+
function test2() external returns (uint256[][2] memory) {
29+
return a2;
30+
}
31+
32+
function test3() external returns (uint256[2][] memory) {
33+
return a3;
34+
}
35+
36+
function test4() external returns (uint256[2][2] memory) {
37+
return a4;
38+
}
39+
}
40+
41+
// ----
42+
// test1() -> 0x20, 2, 0x40, 0xa0, 2, 1, 2, 3, 3, 4, 5
43+
// test2() -> 0x20, 0x40, 0xc0, 3, 6, 7, 8, 1, 9
44+
// test3() -> 0x20, 3, 1, 2, 3, 4, 5, 6
45+
// test4() -> 10, 11, 12, 13
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
mapping (uint => uint8[][]) m;
5+
6+
uint8[][] s;
7+
8+
constructor() {
9+
s = new uint8[][](2);
10+
11+
s[0] = new uint8[](2);
12+
s[0][0] = 10;
13+
s[0][1] = 11;
14+
15+
s[1] = new uint8[](3);
16+
s[1][0] = 12;
17+
s[1][1] = 13;
18+
s[1][2] = 14;
19+
}
20+
21+
function from_storage() public returns (uint8[][] memory) {
22+
m[0] = s;
23+
return m[0];
24+
}
25+
26+
function from_storage_ptr() public returns (uint8[][] memory) {
27+
uint8[][] storage sPtr = s;
28+
m[0] = sPtr;
29+
return m[0];
30+
}
31+
32+
function from_memory() public returns (uint8[][] memory) {
33+
uint8[][] memory a = s;
34+
m[0] = a;
35+
return m[0];
36+
}
37+
}
38+
39+
// ----
40+
// from_storage() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
41+
// gas irOptimized: 147913
42+
// gas legacy: 148965
43+
// gas legacyOptimized: 146935
44+
// from_storage_ptr() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
45+
// from_memory() -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
mapping (uint => uint8[][]) m;
5+
6+
uint8[][] s;
7+
8+
function from_calldata(uint8[][] calldata _a) public returns (uint8[][] memory) {
9+
m[0] = _a;
10+
return m[0];
11+
}
12+
}
13+
14+
// ====
15+
// compileViaYul: true
16+
// ----
17+
// from_calldata(uint8[][]): 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14 -> 0x20, 2, 0x40, 0xa0, 2, 10, 11, 3, 12, 13, 14
18+
// gas irOptimized: 139927
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
struct S {
5+
uint8[] a;
6+
uint8[2] b;
7+
}
8+
9+
S[][][] s1;
10+
S[][1][] s2;
11+
S[1][][1] s3;
12+
13+
function test1(S[][][] calldata _a) public returns (S[][] memory){
14+
s1.push();
15+
s1[0] = _a[0];
16+
return s1[0];
17+
}
18+
19+
function test2(S[][1][] calldata _a) public returns (S[][1] memory) {
20+
s2.push();
21+
s2[0] = _a[0];
22+
return s2[0];
23+
}
24+
25+
function test3(S[1][][2] calldata _a) public returns (S[1][] memory) {
26+
s3[0] = _a[1];
27+
return s3[0];
28+
}
29+
}
30+
31+
32+
// ====
33+
// compileViaYul: true
34+
// ----
35+
// test1((uint8[],uint8[2])[][][]): 0x20, 1, 0x20, 2, 0x40, 0x0140, 1, 0x20, 0x60, 3, 7, 2, 1, 2, 2, 0x40, 0x0100, 0x60, 17, 19, 2, 11, 13, 0x60, 31, 37, 2, 23, 29 -> 0x20, 2, 0x40, 0x0140, 1, 0x20, 0x60, 3, 7, 2, 1, 2, 2, 0x40, 0x0100, 0x60, 17, 19, 2, 11, 13, 0x60, 31, 37, 2, 23, 29
36+
// gas irOptimized: 327878
37+
// test2((uint8[],uint8[2])[][1][]): 0x20, 2, 0x40, 0x0160, 0x20, 1, 0x20, 0x60, 17, 19, 2, 11, 13, 0x20, 1, 0x20, 0x60, 31, 37, 2, 23, 29 -> 0x20, 0x20, 1, 0x20, 0x60, 17, 19, 2, 11, 13
38+
// gas irOptimized: 140894
39+
// test3((uint8[],uint8[2])[1][][2]): 0x20, 0x40, 0x60, 0, 2, 0x40, 288, 0x20, 0x60, 3, 7, 2, 1, 2, 0x20, 0x60, 17, 19, 2, 11, 13 -> 0x20, 2, 0x40, 288, 0x20, 0x60, 3, 7, 2, 1, 2, 0x20, 0x60, 17, 19, 2, 11, 13
40+
// gas irOptimized: 188509
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
struct S {
5+
uint8[] a;
6+
uint8[2] b;
7+
}
8+
9+
S[][][] s1;
10+
S[][1][] s2;
11+
S[1][][1] s3;
12+
13+
function test1(S[][][] memory _a) public returns (S[][] memory){
14+
s1.push();
15+
s1[0] = _a[0];
16+
return s1[0];
17+
}
18+
19+
function test2(S[][1][] memory _a) public returns (S[][1] memory) {
20+
s2.push();
21+
s2[0] = _a[0];
22+
return s2[0];
23+
}
24+
25+
function test3(S[1][][2] memory _a) public returns (S[1][] memory) {
26+
s3[0] = _a[1];
27+
return s3[0];
28+
}
29+
}
30+
31+
32+
// ====
33+
// compileViaYul: true
34+
// ----
35+
// test1((uint8[],uint8[2])[][][]): 0x20, 1, 0x20, 2, 0x40, 0x0140, 1, 0x20, 0x60, 3, 7, 2, 1, 2, 2, 0x40, 0x0100, 0x60, 17, 19, 2, 11, 13, 0x60, 31, 37, 2, 23, 29 -> 0x20, 2, 0x40, 0x0140, 1, 0x20, 0x60, 3, 7, 2, 1, 2, 2, 0x40, 0x0100, 0x60, 17, 19, 2, 11, 13, 0x60, 31, 37, 2, 23, 29
36+
// gas irOptimized: 332334
37+
// test2((uint8[],uint8[2])[][1][]): 0x20, 2, 0x40, 0x0160, 0x20, 1, 0x20, 0x60, 17, 19, 2, 11, 13, 0x20, 1, 0x20, 0x60, 31, 37, 2, 23, 29 -> 0x20, 0x20, 1, 0x20, 0x60, 17, 19, 2, 11, 13
38+
// gas irOptimized: 145029
39+
// test3((uint8[],uint8[2])[1][][2]): 0x20, 0x40, 0x60, 0, 2, 0x40, 288, 0x20, 0x60, 3, 7, 2, 1, 2, 0x20, 0x60, 17, 19, 2, 11, 13 -> 0x20, 2, 0x40, 288, 0x20, 0x60, 3, 7, 2, 1, 2, 0x20, 0x60, 17, 19, 2, 11, 13
40+
// gas irOptimized: 192344
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
function test1(uint8[][][] calldata _a) public returns (uint8[][] memory) {
5+
return _a[1];
6+
}
7+
8+
function test2(uint8[][1][] calldata _a) public returns (uint8[][1] memory) {
9+
return _a[0];
10+
}
11+
12+
function test3(uint8[2][][2] calldata _a) public returns (uint8[2][] memory) {
13+
return _a[0];
14+
}
15+
16+
function test4(uint16[][] calldata _a) public returns (uint16[][] memory) {
17+
uint16[][][] memory tmp = new uint16[][][](2);
18+
tmp[1] = _a;
19+
return tmp[1];
20+
}
21+
22+
function test5(uint32[][2] calldata _a) public returns (uint32[][2] memory) {
23+
uint32[][2][] memory tmp = new uint32[][2][](1);
24+
tmp[0] = _a;
25+
return tmp[0];
26+
}
27+
28+
function test6(uint32[2][] calldata _a) public returns (uint32[2][] memory) {
29+
uint32[2][][] memory tmp = new uint32[2][][](1);
30+
tmp[0] = _a;
31+
return tmp[0];
32+
}
33+
}
34+
35+
// ----
36+
// test1(uint8[][][]): 0x20, 2, 0x40, 0x60, 0, 2, 0x40, 0x80, 1, 7, 2, 8, 9 -> 0x20, 2, 0x40, 0x80, 1, 7, 2, 8, 9
37+
// test2(uint8[][1][]): 0x20, 2, 0x40, 0xe0, 0x20, 3, 12, 13, 14, 0x20, 3, 15, 16, 17 -> 0x20, 0x20, 3, 12, 13, 14
38+
// test3(uint8[2][][2]): 0x20, 0x40, 0xa0, 1, 7, 7, 2, 8, 8, 0x09, 9 -> 0x20, 1, 7, 7
39+
// test4(uint16[][]): 0x20, 2, 0x40, 0x80, 1, 7, 2, 8, 9 -> 0x20, 2, 0x40, 0x80, 1, 7, 2, 8, 9
40+
// test5(uint32[][2]): 0x20, 0x40, 0x80, 1, 7, 2, 8, 9 -> 0x20, 0x40, 0x80, 1, 7, 2, 8, 9
41+
// test6(uint32[2][]): 0x20, 2, 5, 6, 7, 8 -> 0x20, 2, 5, 6, 7, 8
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
contract C {
2+
uint8[2][2] a;
3+
uint8[2][2][2] a2;
4+
5+
function test(uint8[2][2][2] calldata _a) public {
6+
a = _a[0];
7+
require(a[0][0] == 1);
8+
require(a[0][1] == 2);
9+
require(a[1][0] == 3);
10+
require(a[1][1] == 4);
11+
}
12+
13+
function test2(uint8[2][2] calldata _a) public {
14+
a2[0] = _a;
15+
require(a2[0][0][0] == 1);
16+
require(a2[0][0][1] == 2);
17+
require(a2[0][1][0] == 3);
18+
require(a2[0][1][1] == 4);
19+
require(a2[1][0][0] == 0);
20+
require(a2[1][0][1] == 0);
21+
require(a2[1][1][0] == 0);
22+
require(a2[1][1][1] == 0);
23+
}
24+
}
25+
26+
// ----
27+
// test(uint8[2][2][2]): 1, 2, 3, 4, 5, 6, 7, 8
28+
// test2(uint8[2][2]): 1, 2, 3, 4
29+
// gas irOptimized: 119939
30+
// gas legacyOptimized: 120228
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
pragma abicoder v2;
2+
3+
contract C {
4+
function test1(uint8[][][] memory _a) public returns (uint8[][] memory) {
5+
return _a[1];
6+
}
7+
8+
function test2(uint8[][1][] memory _a) public returns (uint8[][1] memory) {
9+
return _a[0];
10+
}
11+
12+
function test3(uint8[2][][2] memory _a) public returns (uint8[2][] memory) {
13+
return _a[0];
14+
}
15+
16+
function test4(uint16[][] memory _a) public returns (uint16[][] memory) {
17+
uint16[][][] memory tmp = new uint16[][][](2);
18+
tmp[1] = _a;
19+
return tmp[1];
20+
}
21+
22+
function test5(uint32[][2] memory _a) public returns (uint32[][2] memory) {
23+
uint32[][2][] memory tmp = new uint32[][2][](1);
24+
tmp[0] = _a;
25+
return tmp[0];
26+
}
27+
28+
function test6(uint32[2][] memory _a) public returns (uint32[2][] memory) {
29+
uint32[2][][] memory tmp = new uint32[2][][](1);
30+
tmp[0] = _a;
31+
return tmp[0];
32+
}
33+
}
34+
35+
// ----
36+
// test1(uint8[][][]): 0x20, 2, 0x40, 0x60, 0, 2, 0x40, 0x80, 1, 7, 2, 8, 9 -> 0x20, 2, 0x40, 0x80, 1, 7, 2, 8, 9
37+
// test2(uint8[][1][]): 0x20, 2, 0x40, 0xe0, 0x20, 3, 12, 13, 14, 0x20, 3, 15, 16, 17 -> 0x20, 0x20, 3, 12, 13, 14
38+
// test3(uint8[2][][2]): 0x20, 0x40, 0xa0, 1, 7, 7, 2, 8, 8, 0x09, 9 -> 0x20, 1, 7, 7
39+
// test4(uint16[][]): 0x20, 2, 0x40, 0x80, 1, 7, 2, 8, 9 -> 0x20, 2, 0x40, 0x80, 1, 7, 2, 8, 9
40+
// test5(uint32[][2]): 0x20, 0x40, 0x80, 1, 7, 2, 8, 9 -> 0x20, 0x40, 0x80, 1, 7, 2, 8, 9
41+
// test6(uint32[2][]): 0x20, 2, 5, 6, 7, 8 -> 0x20, 2, 5, 6, 7, 8

0 commit comments

Comments
 (0)