Merge pull request #12423 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth
2021-12-20 11:40:40 +01:00
committed by GitHub
77 changed files with 3206 additions and 592 deletions
@@ -0,0 +1,51 @@
pragma abicoder v2;
contract C {
type UnsignedNumber is uint256;
enum Enum { First, Second, Third }
struct Struct {
UnsignedNumber[] dynamicArray;
uint256 justAnInt;
string name;
bytes someBytes;
Enum theEnum;
}
function callMeMaybe(Struct calldata _data, int256 _intVal, string memory _nameVal) external pure {
assert(_data.dynamicArray.length == 3);
assert(UnsignedNumber.unwrap(_data.dynamicArray[0]) == 0);
assert(UnsignedNumber.unwrap(_data.dynamicArray[1]) == 1);
assert(UnsignedNumber.unwrap(_data.dynamicArray[2]) == 2);
assert(_data.justAnInt == 6);
assert(keccak256(bytes(_data.name)) == keccak256("StructName"));
assert(keccak256(_data.someBytes) == keccak256(bytes("1234")));
assert(_data.theEnum == Enum.Second);
assert(_intVal == 5);
assert(keccak256(bytes(_nameVal)) == keccak256("TestName"));
}
function callExternal() public returns (bool) {
Struct memory structToSend;
structToSend.dynamicArray = new UnsignedNumber[](3);
structToSend.dynamicArray[0] = UnsignedNumber.wrap(0);
structToSend.dynamicArray[1] = UnsignedNumber.wrap(1);
structToSend.dynamicArray[2] = UnsignedNumber.wrap(2);
structToSend.justAnInt = 6;
structToSend.name = "StructName";
structToSend.someBytes = bytes("1234");
structToSend.theEnum = Enum.Second;
(bool success,) = address(this).call(abi.encodeCall(this.callMeMaybe, (
structToSend,
5,
"TestName"
)));
return success;
}
}
// ====
// compileViaYul: also
// ----
// callExternal() -> true
@@ -0,0 +1,63 @@
pragma abicoder v2;
contract C {
bool sideEffectRan = false;
function(uint256, string memory) external fPointer;
function fExternal(uint256 p, string memory t) external {}
string xstor;
function getExternalFunctionPointer() public returns (function(uint256, string memory) external) {
sideEffectRan = true;
return this.fExternal;
}
function fSignatureFromLiteral() public pure returns (bytes memory) {
return abi.encodeWithSignature("fExternal(uint256,string)", 1, "123");
}
function fSignatureFromLiteralCall() public view returns (bytes memory) {
return abi.encodeCall(this.fExternal, (1, "123"));
}
function fSignatureFromMemory() public pure returns (bytes memory) {
string memory x = "fExternal(uint256,string)";
return abi.encodeWithSignature(x, 1, "123");
}
function fSignatureFromMemoryCall() public view returns (bytes memory) {
return abi.encodeCall(this.fExternal, (1,"123"));
}
function fSignatureFromMemorys() public returns (bytes memory) {
xstor = "fExternal(uint256,string)";
return abi.encodeWithSignature(xstor, 1, "123");
}
function fPointerCall() public returns(bytes memory) {
fPointer = this.fExternal;
return abi.encodeCall(fPointer, (1, "123"));
}
function fLocalPointerCall() public returns(bytes memory) {
function(uint256, string memory) external localFunctionPointer = this.fExternal;
return abi.encodeCall(localFunctionPointer, (1, "123"));
}
function fReturnedFunctionPointer() public returns (bytes memory) {
return abi.encodeCall(getExternalFunctionPointer(), (1, "123"));
}
function assertConsistentSelectors() public {
assert(keccak256(fSignatureFromLiteral()) == keccak256(fSignatureFromLiteralCall()));
assert(keccak256(fSignatureFromMemory()) == keccak256(fSignatureFromMemoryCall()));
assert(keccak256(fSignatureFromMemoryCall()) == keccak256(fSignatureFromMemorys()));
assert(keccak256(fPointerCall()) == keccak256(fSignatureFromLiteral()));
assert(keccak256(fLocalPointerCall()) == keccak256(fSignatureFromLiteral()));
assert(keccak256(fReturnedFunctionPointer()) == keccak256(fSignatureFromLiteral()));
}
}
// ====
// compileViaYul: also
// ----
// assertConsistentSelectors() ->
// fSignatureFromLiteral() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromLiteralCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromMemory() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromMemoryCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fSignatureFromMemorys() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fPointerCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fLocalPointerCall() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
// fReturnedFunctionPointer() -> 0x20, 0x84, 23450202028776381066253055403048136312616272755117076566855971503345107992576, 26959946667150639794667015087019630673637144422540572481103610249216, 1725436586697640946858688965569256363112777243042596638790631055949824, 86060793054017993816230018372407419485142305772921726565498526629888, 0
@@ -0,0 +1,28 @@
pragma abicoder v2;
contract D {
function something() external pure {}
}
contract C {
function something() external pure {}
function test() external returns (bytes4) {
function() external[2] memory x;
x[0] = this.something;
x[1] = (new D()).something;
function() external f = x[1];
bytes memory a = abi.encodeCall(x[0], ());
bytes memory b = abi.encodeCall(x[1], ());
bytes memory c = abi.encodeCall(f, ());
assert(a.length == 4 && b.length == 4 && c.length == 4);
assert(bytes4(a) == bytes4(b));
assert(bytes4(a) == bytes4(c));
assert(bytes4(a) == f.selector);
return bytes4(a);
}
}
// ====
// compileViaYul: also
// ----
// test() -> 0xa7a0d53700000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,48 @@
pragma abicoder v2;
contract C {
bool sideEffectRan = false;
function fNoArgs() external {}
function fArray(uint[] memory x) external {}
function fUint(uint x, uint y) external returns (uint a, uint b) {}
function fSignatureFromLiteralNoArgs() public pure returns (bytes memory) {
return abi.encodeWithSignature("fNoArgs()");
}
function fPointerNoArgs() public view returns (bytes memory) {
return abi.encodeCall(this.fNoArgs, ());
}
function fSignatureFromLiteralArray() public pure returns (bytes memory) {
uint[] memory x;
return abi.encodeWithSignature("fArray(uint256[])", x);
}
function fPointerArray() public view returns (bytes memory) {
uint[] memory x;
return abi.encodeCall(this.fArray, x);
}
function fSignatureFromLiteralUint() public pure returns (bytes memory) {
return abi.encodeWithSignature("fUint(uint256,uint256)", 12, 13);
}
function fPointerUint() public view returns (bytes memory) {
return abi.encodeCall(this.fUint, (12,13));
}
function assertConsistentSelectors() public view {
assert(keccak256(fSignatureFromLiteralNoArgs()) == keccak256(fPointerNoArgs()));
assert(keccak256(fSignatureFromLiteralArray()) == keccak256(fPointerArray()));
assert(keccak256(fSignatureFromLiteralUint()) == keccak256(fPointerUint()));
}
}
// ====
// compileViaYul: also
// ----
// assertConsistentSelectors() ->
// fSignatureFromLiteralNoArgs() -> 0x20, 0x04, 12200448252684243758085936796735499259670113115893304444050964496075123064832
// fPointerNoArgs() -> 0x20, 4, 12200448252684243758085936796735499259670113115893304444050964496075123064832
// fSignatureFromLiteralArray() -> 0x20, 0x44, 4612216551196396486909126966576324289294165774260092952932219511233230929920, 862718293348820473429344482784628181556388621521298319395315527974912, 0
// fPointerArray() -> 0x20, 0x44, 4612216551196396486909126966576324289294165774260092952932219511233230929920, 862718293348820473429344482784628181556388621521298319395315527974912, 0
// fPointerUint() -> 0x20, 0x44, 30372892641494467502622535050667754357470287521126424526399600764424271429632, 323519360005807677536004181044235568083645733070486869773243322990592, 350479306672958317330671196131255198757282877493027442254346933239808
// fSignatureFromLiteralUint() -> 0x20, 0x44, 30372892641494467502622535050667754357470287521126424526399600764424271429632, 323519360005807677536004181044235568083645733070486869773243322990592, 350479306672958317330671196131255198757282877493027442254346933239808
@@ -26,7 +26,6 @@ contract C {
}
struct S { uint a; string b; uint16 c; }
function f4() public pure returns (bytes memory) {
bytes4 x = 0x12345678;
S memory s;
s.a = 0x1234567;
s.b = "Lorem ipsum dolor sit ethereum........";
@@ -0,0 +1,53 @@
contract C {
function testFunction1() public {}
function testFunction2() public {}
function testFunction3() public {}
function() external [] externalArray0;
function() external [] externalArray1;
function() internal [] internalArray0;
function() internal [] internalArray1;
constructor() {
externalArray0 = new function() external[] (3);
externalArray1 = [
this.testFunction1,
this.testFunction2,
this.testFunction3
];
internalArray0 = new function() internal[] (3);
internalArray1 = [
testFunction1,
testFunction2,
testFunction3
];
}
function copyExternalStorageArrayOfFunctionType() external returns (bool) {
assert(keccak256(abi.encode(externalArray0)) != keccak256(abi.encode(externalArray1)));
externalArray0 = externalArray1;
return keccak256(abi.encode(externalArray0)) == keccak256(abi.encode(externalArray1));
}
function copyInternalArrayOfFunctionType() external returns (bool) {
internalArray0 = internalArray1;
assert(internalArray0.length == 3);
return
internalArray0.length == internalArray1.length &&
internalArray0[0] == internalArray1[0] &&
internalArray0[1] == internalArray1[1] &&
internalArray0[2] == internalArray1[2];
}
}
// ====
// compileViaYul: also
// ----
// copyExternalStorageArrayOfFunctionType() -> true
// gas irOptimized: 104701
// gas legacy: 108725
// gas legacyOptimized: 102441
// copyInternalArrayOfFunctionType() -> true
@@ -0,0 +1,57 @@
contract C {
function testFunction1() public {}
function testFunction2() public view {}
function testFunction3() public pure {}
function() external [] externalArray0;
function() external [] externalArray1;
function() internal [] internalArray0;
function() internal [] internalArray1;
constructor() {
externalArray0 = new function() external[] (3);
externalArray1 = [
this.testFunction1,
this.testFunction2,
this.testFunction3
];
internalArray0 = new function() internal[] (3);
internalArray1 = [
testFunction1,
testFunction2,
testFunction3
];
}
function copyExternalStorageArraysOfFunctionType() external returns (bool)
{
assert(keccak256(abi.encodePacked(externalArray0)) != keccak256(abi.encodePacked(externalArray1)));
externalArray0 = externalArray1;
return keccak256(abi.encodePacked(externalArray0)) == keccak256(abi.encodePacked(externalArray1));
}
function copyInternalArrayOfFunctionType() external returns (bool)
{
internalArray0 = internalArray1;
assert(internalArray0.length == 3);
return
internalArray0.length == internalArray1.length &&
internalArray0[0] == internalArray1[0] &&
internalArray0[1] == internalArray1[1] &&
internalArray0[2] == internalArray1[2];
}
}
// ====
// compileViaYul: also
// ----
// copyExternalStorageArraysOfFunctionType() -> true
// gas irOptimized: 104372
// gas legacy: 108462
// gas legacyOptimized: 102174
// copyInternalArrayOfFunctionType() -> true
// gas legacy: 104178
@@ -18,6 +18,6 @@ contract C {
// compileViaYul: also
// ----
// test() -> 7
// gas irOptimized: 126552
// gas irOptimized: 124080
// gas legacy: 205196
// gas legacyOptimized: 204987
@@ -0,0 +1,33 @@
contract receiver {
uint public received;
function recv(uint x) public { received += x + 1; }
fallback() external { received = 0x80; }
}
contract sender {
constructor() { rec = new receiver(); }
fallback() external { savedData1 = savedData2 = msg.data; }
function forward(bool selector) public returns (bool) {
if (selector) { address(rec).call(savedData1); delete savedData1; }
else { address(rec).call(savedData2); delete savedData2; }
return true;
}
function val() public returns (uint) { return rec.received(); }
receiver rec;
bytes savedData1;
bytes savedData2;
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// (): 7 ->
// gas irOptimized: 110941
// gas legacy: 111082
// gas legacyOptimized: 111027
// val() -> 0
// forward(bool): true -> true
// val() -> 0x80
// forward(bool): false -> true
// val() -> 0x80
// forward(bool): true -> true
// val() -> 0x80
@@ -0,0 +1,19 @@
contract c {
function set() public returns (bool) { data = msg.data; return true; }
function checkIfDataIsEmpty() public returns (bool) { return data.length == 0; }
function sendMessage() public returns (bool, bytes memory) { bytes memory emptyData; return address(this).call(emptyData);}
fallback() external { data = msg.data; }
bytes data;
}
// ====
// EVMVersion: >=byzantium
// compileToEwasm: false
// compileViaYul: also
// ----
// (): 1, 2, 3, 4, 5 ->
// gas irOptimized: 155178
// gas legacy: 155254
// gas legacyOptimized: 155217
// checkIfDataIsEmpty() -> false
// sendMessage() -> true, 0x40, 0
// checkIfDataIsEmpty() -> true
@@ -0,0 +1,41 @@
interface I {
enum Direction { A, B, Left, Right }
}
library L {
enum Direction { Left, Right }
function f() public pure returns (Direction) {
return Direction.Right;
}
function g() public pure returns (I.Direction) {
return I.Direction.Right;
}
}
contract C is I {
function f() public pure returns (Direction) {
return Direction.Right;
}
function g() public pure returns (I.Direction) {
return I.Direction.Right;
}
function h() public pure returns (L.Direction) {
return L.Direction.Right;
}
function x() public pure returns (L.Direction) {
return L.f();
}
function y() public pure returns (I.Direction) {
return L.g();
}
}
// ====
// compileViaYul: also
// compileToEwasm: false
// ----
// library: L
// f() -> 3
// g() -> 3
// f() -> 3
// g() -> 3
// h() -> 1
// x() -> 1
// y() -> 3
@@ -0,0 +1,27 @@
contract receiver {
uint256 public received;
function recv(uint256 x) public { received += x + 1; }
fallback() external { received = 0x80; }
}
contract sender {
constructor() { rec = new receiver();}
fallback() external { savedData = msg.data; }
function forward() public returns (bool) { address(rec).call(savedData); return true; }
function clear() public returns (bool) { delete savedData; return true; }
function val() public returns (uint) { return rec.received(); }
receiver rec;
bytes savedData;
}
// ====
// allowNonExistingFunctions: true
// compileToEwasm: false
// compileViaYul: also
// ----
// recv(uint256): 7 ->
// val() -> 0
// forward() -> true
// val() -> 8
// clear() -> true
// val() -> 8
// forward() -> true
// val() -> 0x80
@@ -0,0 +1,16 @@
library L {
function g(function() internal returns (uint) _t) internal returns (uint) { return _t(); }
}
contract C {
using L for *;
function f() public returns (uint) {
return t.g();
}
function t() public pure returns (uint) { return 7; }
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: L
// f() -> 7
@@ -0,0 +1,16 @@
library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } }
contract C {
using D for D.s;
D.s public x;
function f(uint a) public returns (uint) {
x.a = 6;
return (x.mul)({x: a});
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: D
// f(uint256): 7 -> 0x2a
// x() -> 0x2a
@@ -0,0 +1,20 @@
library D { function length(string memory self) public returns (uint) { return bytes(self).length; } }
contract C {
using D for string;
string x;
function f() public returns (uint) {
x = "abc";
return x.length();
}
function g() public returns (uint) {
string memory s = "abc";
return s.length();
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: D
// f() -> 3
// g() -> 3
@@ -0,0 +1,30 @@
library Lib {
function find(uint16[] storage _haystack, uint16 _needle) public view returns (uint)
{
for (uint i = 0; i < _haystack.length; ++i)
if (_haystack[i] == _needle)
return i;
return type(uint).max;
}
}
contract Test {
mapping(string => uint16[]) data;
function f() public returns (uint a, uint b)
{
while (data["abc"].length < 20)
data["abc"].push();
data["abc"][4] = 9;
data["abc"][17] = 3;
a = Lib.find(data["abc"], 9);
b = Lib.find(data["abc"], 3);
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// f() -> 4, 0x11
// gas irOptimized: 115822
// gas legacy: 135952
// gas legacyOptimized: 119643
@@ -0,0 +1,15 @@
library Lib { function m() public returns (address) { return msg.sender; } }
contract Test {
address public sender;
function f() public {
sender = Lib.m();
}
}
// ====
// compileViaYul: also
// compileToEwasm: false
// EVMVersion: >=homestead
// ----
// library: Lib
// f() ->
// sender() -> 0x1212121212121212121212121212120000000012
@@ -0,0 +1,14 @@
library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } }
contract Test {
function f(uint x) public returns (uint) {
Lib;
Lib.m;
return x + 9;
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// f(uint256): 33 -> 0x2a
@@ -0,0 +1,41 @@
library Lib {
function set(mapping(uint => uint) storage m, uint key, uint value) internal
{
m[key] = value;
}
function get(mapping(uint => uint) storage m, uint key) internal view returns (uint)
{
return m[key];
}
}
contract Test {
mapping(uint => uint) m;
function set(uint256 key, uint256 value) public returns (uint)
{
uint oldValue = Lib.get(m, key);
Lib.set(m, key, value);
return oldValue;
}
function get(uint256 key) public view returns (uint) {
return Lib.get(m, key);
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// set(uint256,uint256): 1, 42 -> 0
// set(uint256,uint256): 2, 84 -> 0
// set(uint256,uint256): 21, 7 -> 0
// get(uint256): 0 -> 0
// get(uint256): 1 -> 0x2a
// get(uint256): 2 -> 0x54
// get(uint256): 21 -> 7
// set(uint256,uint256): 1, 21 -> 0x2a
// set(uint256,uint256): 2, 42 -> 0x54
// set(uint256,uint256): 21, 14 -> 7
// get(uint256): 0 -> 0
// get(uint256): 1 -> 0x15
// get(uint256): 2 -> 0x2a
// get(uint256): 21 -> 14
@@ -0,0 +1,75 @@
library Lib {
function choose_mapping(mapping(uint => uint) storage a, mapping(uint => uint) storage b, bool c) internal pure returns(mapping(uint=>uint) storage)
{
return c ? a : b;
}
}
contract Test {
mapping(uint => uint) a;
mapping(uint => uint) b;
function set(bool choice, uint256 key, uint256 value) public returns (uint)
{
mapping(uint => uint) storage m = Lib.choose_mapping(a, b, choice);
uint oldValue = m[key];
m[key] = value;
return oldValue;
}
function get(bool choice, uint256 key) public view returns (uint) {
return Lib.choose_mapping(a, b, choice)[key];
}
function get_a(uint256 key) public view returns (uint) {
return a[key];
}
function get_b(uint256 key) public view returns (uint) {
return b[key];
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// set(bool,uint256,uint256): true, 1, 42 -> 0
// set(bool,uint256,uint256): true, 2, 84 -> 0
// set(bool,uint256,uint256): true, 21, 7 -> 0
// set(bool,uint256,uint256): false, 1, 10 -> 0
// set(bool,uint256,uint256): false, 2, 11 -> 0
// set(bool,uint256,uint256): false, 21, 12 -> 0
// get(bool,uint256): true, 0 -> 0
// get(bool,uint256): true, 1 -> 0x2a
// get(bool,uint256): true, 2 -> 0x54
// get(bool,uint256): true, 21 -> 7
// get_a(uint256): 0 -> 0
// get_a(uint256): 1 -> 0x2a
// get_a(uint256): 2 -> 0x54
// get_a(uint256): 21 -> 7
// get(bool,uint256): false, 0 -> 0
// get(bool,uint256): false, 1 -> 10
// get(bool,uint256): false, 2 -> 11
// get(bool,uint256): false, 21 -> 12
// get_b(uint256): 0 -> 0
// get_b(uint256): 1 -> 10
// get_b(uint256): 2 -> 11
// get_b(uint256): 21 -> 12
// set(bool,uint256,uint256): true, 1, 21 -> 0x2a
// set(bool,uint256,uint256): true, 2, 42 -> 0x54
// set(bool,uint256,uint256): true, 21, 14 -> 7
// set(bool,uint256,uint256): false, 1, 30 -> 10
// set(bool,uint256,uint256): false, 2, 31 -> 11
// set(bool,uint256,uint256): false, 21, 32 -> 12
// get_a(uint256): 0 -> 0
// get_a(uint256): 1 -> 0x15
// get_a(uint256): 2 -> 0x2a
// get_a(uint256): 21 -> 14
// get(bool,uint256): true, 0 -> 0
// get(bool,uint256): true, 1 -> 0x15
// get(bool,uint256): true, 2 -> 0x2a
// get(bool,uint256): true, 21 -> 14
// get_b(uint256): 0 -> 0
// get_b(uint256): 1 -> 0x1e
// get_b(uint256): 2 -> 0x1f
// get_b(uint256): 21 -> 0x20
// get(bool,uint256): false, 0 -> 0
// get(bool,uint256): false, 1 -> 0x1e
// get(bool,uint256): false, 2 -> 0x1f
// get(bool,uint256): false, 21 -> 0x20
@@ -0,0 +1,31 @@
library Lib {
function f(mapping(uint => uint) storage a, mapping(uint => uint) storage b) internal returns(mapping(uint=>uint) storage r)
{
r = a;
r[1] = 42;
r = b;
r[1] = 21;
}
}
contract Test {
mapping(uint => uint) a;
mapping(uint => uint) b;
function f() public returns (uint, uint, uint, uint, uint, uint)
{
Lib.f(a, b)[2] = 84;
return (a[0], a[1], a[2], b[0], b[1], b[2]);
}
function g() public returns (uint, uint, uint, uint, uint, uint)
{
mapping(uint => uint) storage m = Lib.f(a, b);
m[2] = 17;
return (a[0], a[1], a[2], b[0], b[1], b[2]);
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// f() -> 0, 0x2a, 0, 0, 0x15, 0x54
// g() -> 0, 0x2a, 0, 0, 0x15, 0x11
@@ -0,0 +1,14 @@
library L {
function f() public returns (uint) { return 7; }
}
contract C {
function f() public payable returns (uint) {
return L.f();
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: L
// f(): 27 -> 7
@@ -0,0 +1,16 @@
library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } }
contract C {
using D for D.s;
D.s public x;
function f(uint a) public returns (uint) {
x.a = 6;
return x.mul({x: a});
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: D
// f(uint256): 7 -> 0x2a
// x() -> 0x2a
@@ -0,0 +1,20 @@
library D {
struct s { uint a; }
function mul(s storage self, uint x) public returns (uint) { return self.a *= x; }
function mul(s storage self, bytes32 x) public returns (bytes32) { }
}
contract C {
using D for D.s;
D.s public x;
function f(uint a) public returns (uint) {
x.a = 6;
return x.mul(a);
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: D
// f(uint256): 7 -> 0x2a
// x() -> 0x2a
@@ -0,0 +1,27 @@
library Lib {
function set(mapping(uint => uint) storage m, uint key, uint value) public
{
m[key] = value;
}
}
contract Test {
mapping(uint => uint) m1;
mapping(uint => uint) m2;
function f() public returns (uint, uint, uint, uint, uint, uint)
{
Lib.set(m1, 0, 1);
Lib.set(m1, 2, 42);
Lib.set(m2, 0, 23);
Lib.set(m2, 2, 99);
return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]);
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// f() -> 1, 0, 0x2a, 0x17, 0, 0x63
// gas irOptimized: 119757
// gas legacy: 124793
// gas legacyOptimized: 119694
@@ -0,0 +1,25 @@
library Lib {
function choose(mapping(uint => mapping(uint => uint)) storage m, uint key) external returns (mapping(uint => uint) storage) {
return m[key];
}
}
contract Test {
mapping(uint => mapping(uint => uint)) m;
function f() public returns (uint, uint, uint, uint, uint, uint)
{
Lib.choose(m, 0)[0] = 1;
Lib.choose(m, 0)[2] = 42;
Lib.choose(m, 1)[0] = 23;
Lib.choose(m, 1)[2] = 99;
return (m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2]);
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// f() -> 1, 0, 0x2a, 0x17, 0, 0x63
// gas irOptimized: 120471
// gas legacy: 125245
// gas legacyOptimized: 120153
@@ -0,0 +1,27 @@
library Lib {
struct Data { uint a; uint[] b; }
function set(Data storage _s) public
{
_s.a = 7;
while (_s.b.length < 20)
_s.b.push();
_s.b[19] = 8;
}
}
contract Test {
mapping(string => Lib.Data) data;
function f() public returns (uint a, uint b)
{
Lib.set(data["abc"]);
a = data["abc"].a;
b = data["abc"].b[19];
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: Lib
// f() -> 7, 8
// gas irOptimized: 101869
// gas legacy: 101504
@@ -0,0 +1,61 @@
pragma abicoder v2;
interface I {
struct S { uint a; }
}
library L {
struct S { uint b; uint a; }
function f() public pure returns (S memory) {
S memory s;
s.a = 3;
return s;
}
function g() public pure returns (I.S memory) {
I.S memory s;
s.a = 4;
return s;
}
// argument-dependant lookup tests
function a(I.S memory) public pure returns (uint) { return 1; }
function a(S memory) public pure returns (uint) { return 2; }
}
contract C is I {
function f() public pure returns (S memory) {
S memory s;
s.a = 1;
return s;
}
function g() public pure returns (I.S memory) {
I.S memory s;
s.a = 2;
return s;
}
function h() public pure returns (L.S memory) {
L.S memory s;
s.a = 5;
return s;
}
function x() public pure returns (L.S memory) {
return L.f();
}
function y() public pure returns (I.S memory) {
return L.g();
}
function a1() public pure returns (uint) { S memory s; return L.a(s); }
function a2() public pure returns (uint) { L.S memory s; return L.a(s); }
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: L
// f() -> 1
// g() -> 2
// f() -> 1
// g() -> 2
// h() -> 0, 5
// x() -> 0, 3
// y() -> 4
// a1() -> 1
// a2() -> 2
@@ -0,0 +1,16 @@
library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } }
contract C {
using D for D.s;
D.s public x;
function f(uint a) public returns (uint) {
x.a = 3;
return x.mul(a);
}
}
// ====
// compileToEwasm: false
// compileViaYul: also
// ----
// library: D
// f(uint256): 7 -> 0x15
// x() -> 0x15