User-defined operators on structs

This commit is contained in:
Kamil Śliwak
2023-01-25 00:30:03 +01:00
parent 5657515f45
commit 05f4617275
27 changed files with 685 additions and 49 deletions
@@ -0,0 +1,22 @@
struct S {
uint v;
}
using {bitand as &} for S;
function bitand(S storage, S storage) returns (S storage) {
S storage rTmp;
return rTmp;
}
contract C {
S s;
function f() public {
S storage sTmp;
sTmp & s;
}
}
// ----
// TypeError 3464: (145-149): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
// TypeError 3464: (234-238): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
@@ -0,0 +1,22 @@
struct S {
uint v;
}
using {bitor as |} for S;
function bitor(S storage, S storage) returns (S storage) {
S storage rTmp;
return rTmp;
}
contract C {
S s;
function f() public {
S storage sTmp;
sTmp | s;
}
}
// ----
// TypeError 3464: (143-147): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
// TypeError 3464: (232-236): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
@@ -0,0 +1,17 @@
struct S { Z z; }
struct Z { int x; }
using {addS as +} for S;
using {addZ as +} for Z;
function addS(S memory, S memory) pure returns (S memory) {}
function addZ(Z memory, Z memory) pure returns (Z memory) { revert(); }
contract C {
function f() public pure {
S(Z(1)) + S(Z(2) + Z(3));
S(Z(4)) + S(Z(5)); // Unreachable
}
}
// ----
// Warning 5740: (310-327): Unreachable code.
@@ -0,0 +1,17 @@
struct S { Z z; }
struct Z { int x; }
using {unsubS as -} for S;
using {unsubZ as -} for Z;
function unsubS(S memory) pure returns (S memory) {}
function unsubZ(Z memory) pure returns (Z memory) { revert(); }
contract C {
function f() public pure {
-S(-Z(1));
-S(Z(2)); // Unreachable
}
}
// ----
// Warning 5740: (283-291): Unreachable code.
@@ -0,0 +1,36 @@
struct S {
uint8 a;
}
using {
add as +,
sub as -,
mul as *
} for S;
function add(S memory, S memory) pure returns (S memory) {}
function sub(S calldata, S calldata) pure returns (S calldata) {}
function mul(S storage, S storage) pure returns (S storage) {}
contract C {
S s;
function test(S calldata c) public {
S memory m;
c + c; // operator accepts memory, arguments are calldata
s + s; // operator accepts memory, arguments are storage
m - m; // operator accepts calldata, arguments are memory
s - s; // operator accepts calldata, arguments are storage
c * c; // operator accepts storage, arguments are calldata
m * m; // operator accepts storage, arguments are memory
}
}
// ----
// TypeError 1349: (368-373): User-defined binary operator + cannot be applied to type struct S calldata. None of the available definitions accepts calldata arguments.
// TypeError 1349: (434-439): User-defined binary operator + cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 1349: (500-505): User-defined binary operator - cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
// TypeError 1349: (566-571): User-defined binary operator - cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 1349: (634-639): User-defined binary operator * cannot be applied to type struct S calldata. None of the available definitions accepts calldata arguments.
// TypeError 1349: (701-706): User-defined binary operator * cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
@@ -0,0 +1,51 @@
struct S {
uint8 a;
}
using {
add as +,
sub as -,
mul as *
} for S;
function add(S memory, S memory) pure returns (S memory) {}
function sub(S calldata, S calldata) pure returns (S calldata) {}
function mul(S storage, S storage) pure returns (S storage) {}
contract C {
S s;
function test(S calldata c) public {
S memory m;
// operator accepts only memory
m + c;
m + s;
c + m;
s + m;
// operator accepts only calldata
c - m;
c - s;
m - c;
s - c;
// operator accepts only storage
s * c;
s * m;
c * s;
m * s;
}
}
// ----
// TypeError 5653: (408-413): The type of the second operand of this user-defined binary operator + does not match the type of the first operand, which is struct S memory.
// TypeError 5653: (423-428): The type of the second operand of this user-defined binary operator + does not match the type of the first operand, which is struct S memory.
// TypeError 1349: (438-443): User-defined binary operator + cannot be applied to type struct S calldata. None of the available definitions accepts calldata arguments.
// TypeError 1349: (453-458): User-defined binary operator + cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 5653: (511-516): The type of the second operand of this user-defined binary operator - does not match the type of the first operand, which is struct S calldata.
// TypeError 5653: (526-531): The type of the second operand of this user-defined binary operator - does not match the type of the first operand, which is struct S calldata.
// TypeError 1349: (541-546): User-defined binary operator - cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
// TypeError 1349: (556-561): User-defined binary operator - cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 5653: (613-618): The type of the second operand of this user-defined binary operator * does not match the type of the first operand, which is struct S storage pointer.
// TypeError 5653: (628-633): The type of the second operand of this user-defined binary operator * does not match the type of the first operand, which is struct S storage pointer.
// TypeError 1349: (643-648): User-defined binary operator * cannot be applied to type struct S calldata. None of the available definitions accepts calldata arguments.
// TypeError 1349: (658-663): User-defined binary operator * cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
@@ -0,0 +1,70 @@
using {add as +, unsub as -} for S;
using {mul as *, not as !} for S;
struct S {
uint x;
}
function add(S memory, S memory) returns (S memory) {}
function mul(S storage, S storage) returns (S storage) {}
function unsub(S memory) returns (S memory) {}
function not(S storage) returns (S storage) {}
contract C {
S sRef;
function storageToMemory() public {
S storage sPtr;
S memory sMem;
sMem + sPtr;
sPtr + sMem;
sPtr + sPtr;
sMem + sRef;
sRef + sMem;
sRef + sRef;
sRef + sPtr;
sPtr + sRef;
-sPtr;
-sRef;
}
function memoryToStorage() public {
S memory sMem;
S storage sPtr;
sMem * sPtr;
sPtr * sMem;
sMem * sMem;
sMem * sRef;
sRef * sMem;
sMem * sMem;
sRef * sPtr;
sPtr * sRef;
!sMem;
}
}
// ----
// TypeError 5653: (427-438): The type of the second operand of this user-defined binary operator + does not match the type of the first operand, which is struct S memory.
// TypeError 1349: (448-459): User-defined binary operator + cannot be applied to type struct S storage pointer. None of the available definitions accepts storage arguments.
// TypeError 1349: (469-480): User-defined binary operator + cannot be applied to type struct S storage pointer. None of the available definitions accepts storage arguments.
// TypeError 5653: (491-502): The type of the second operand of this user-defined binary operator + does not match the type of the first operand, which is struct S memory.
// TypeError 1349: (512-523): User-defined binary operator + cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 1349: (533-544): User-defined binary operator + cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 1349: (555-566): User-defined binary operator + cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 1349: (576-587): User-defined binary operator + cannot be applied to type struct S storage pointer. None of the available definitions accepts storage arguments.
// TypeError 5652: (598-603): User-defined unary operator - cannot be applied to type struct S storage pointer. None of the available definitions accepts storage arguments.
// TypeError 5652: (613-618): User-defined unary operator - cannot be applied to type struct S storage ref. None of the available definitions accepts storage arguments.
// TypeError 1349: (723-734): User-defined binary operator * cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
// TypeError 5653: (744-755): The type of the second operand of this user-defined binary operator * does not match the type of the first operand, which is struct S storage pointer.
// TypeError 1349: (765-776): User-defined binary operator * cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
// TypeError 1349: (787-798): User-defined binary operator * cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
// TypeError 5653: (808-819): The type of the second operand of this user-defined binary operator * does not match the type of the first operand, which is struct S storage pointer.
// TypeError 1349: (829-840): User-defined binary operator * cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
// TypeError 5652: (894-899): User-defined unary operator ! cannot be applied to type struct S memory. None of the available definitions accepts memory arguments.
@@ -6,8 +6,8 @@ using {f as +} for string;
function f(uint, uint) pure returns (uint) {}
// ----
// TypeError 5332: (7-8): Operators can only be implemented for user-defined value types.
// TypeError 5332: (32-33): Operators can only be implemented for user-defined value types.
// TypeError 5332: (60-61): Operators can only be implemented for user-defined value types.
// TypeError 5332: (102-103): Operators can only be implemented for user-defined value types.
// TypeError 5332: (158-159): Operators can only be implemented for user-defined value types.
// TypeError 5332: (7-8): Operators can only be implemented for user-defined value types and structs.
// TypeError 5332: (32-33): Operators can only be implemented for user-defined value types and structs.
// TypeError 5332: (60-61): Operators can only be implemented for user-defined value types and structs.
// TypeError 5332: (102-103): Operators can only be implemented for user-defined value types and structs.
// TypeError 5332: (158-159): Operators can only be implemented for user-defined value types and structs.
@@ -7,5 +7,5 @@ function fa(A, A) pure returns (A) {}
contract C {}
abstract contract A {}
// ----
// TypeError 5332: (7-9): Operators can only be implemented for user-defined value types.
// TypeError 5332: (30-32): Operators can only be implemented for user-defined value types.
// TypeError 5332: (7-9): Operators can only be implemented for user-defined value types and structs.
// TypeError 5332: (30-32): Operators can only be implemented for user-defined value types and structs.
@@ -7,4 +7,4 @@ enum E {
function add(E, E) pure returns (E) {}
// ----
// TypeError 5332: (7-10): Operators can only be implemented for user-defined value types.
// TypeError 5332: (7-10): Operators can only be implemented for user-defined value types and structs.
@@ -4,4 +4,4 @@ function f(I, I) pure returns (I) {}
interface I {}
// ----
// TypeError 5332: (7-8): Operators can only be implemented for user-defined value types.
// TypeError 5332: (7-8): Operators can only be implemented for user-defined value types and structs.
@@ -5,5 +5,3 @@ struct S {
}
function add(S memory, S memory) pure returns (S memory) {}
// ----
// TypeError 5332: (7-10): Operators can only be implemented for user-defined value types.
@@ -0,0 +1,8 @@
using {add as +} for S;
function add(S memory, S memory) pure returns (S memory) {}
function add(S storage, S storage) pure returns (S storage) {}
struct S { int x; }
// ----
// DeclarationError 7920: (7-10): Identifier not found or not unique.
@@ -0,0 +1,10 @@
using {add as +} for S;
using {add as +} for Z;
function add(S memory, S memory) pure returns (S memory) {}
function add(Z memory, Z memory) pure returns (Z memory) {}
struct S { int x; }
struct Z { int x; }
// ----
// DeclarationError 7920: (7-10): Identifier not found or not unique.
@@ -0,0 +1,24 @@
struct S { uint128 x; }
using {add as +} for S;
using {sub as -} for S;
using {mul as *} for S;
using {div as *} for S;
using {bitor as |} for S;
using {unsub as -} for S;
function add(S memory, S storage) returns (S memory) {}
function sub(S memory, S storage) returns (S storage) {}
function mul(S storage, S memory) returns (S memory) {}
function div(S storage, S memory) returns (S storage) {}
function bitor(S storage, S storage) pure returns (S memory) {}
function unsub(S memory, S memory) pure returns (S storage) {}
// ----
// TypeError 1884: (186-207): Wrong parameters in operator definition. The function "add" needs to have two parameters of type S and the same data location to be used for the operator +.
// TypeError 1884: (242-263): Wrong parameters in operator definition. The function "sub" needs to have one or two parameters of type S and the same data location to be used for the operator -.
// TypeError 7743: (272-283): Wrong return parameters in operator definition. The function "sub" needs to return a value of the same type and data location as its parameters to be used for the operator -.
// TypeError 1884: (299-320): Wrong parameters in operator definition. The function "mul" needs to have two parameters of type S and the same data location to be used for the operator *.
// TypeError 7743: (329-339): Wrong return parameters in operator definition. The function "mul" needs to return a value of the same type and data location as its parameters to be used for the operator *.
// TypeError 1884: (355-376): Wrong parameters in operator definition. The function "div" needs to have two parameters of type S and the same data location to be used for the operator *.
// TypeError 7743: (450-460): Wrong return parameters in operator definition. The function "bitor" needs to return a value of the same type and data location as its parameters to be used for the operator |.
// TypeError 7743: (512-523): Wrong return parameters in operator definition. The function "unsub" needs to return a value of the same type and data location as its parameters to be used for the operator -.
@@ -0,0 +1,38 @@
using {
sub as -,
mul as *,
div as /,
mod as %,
unsub as -,
bitnot as ~
} for S;
struct S {
uint x;
}
function sub(S calldata, uint) pure returns (S calldata r) {}
function mul(S calldata) pure returns (S calldata r) {}
function div(S calldata, S calldata) pure returns (uint) {}
function mod(S calldata, S calldata) pure {}
function unsub(uint) pure returns (S calldata r) {}
function bitnot(S calldata) pure {}
function test(S calldata s) pure {
s - s;
s * s;
s / s;
s % s;
-s;
~s;
}
// ----
// TypeError 1884: (144-162): Wrong parameters in operator definition. The function "sub" needs to have one or two parameters of type S and the same data location to be used for the operator -.
// TypeError 1884: (206-218): Wrong parameters in operator definition. The function "mul" needs to have two parameters of type S and the same data location to be used for the operator *.
// TypeError 7743: (300-306): Wrong return parameters in operator definition. The function "div" needs to return exactly one value of type S to be used for the operator /.
// TypeError 7743: (352-352): Wrong return parameters in operator definition. The function "mod" needs to return exactly one value of type S to be used for the operator %.
// TypeError 1884: (369-375): Wrong parameters in operator definition. The function "unsub" needs to have one or two parameters of type S and the same data location to be used for the operator -.
// TypeError 7743: (389-403): Wrong return parameters in operator definition. The function "unsub" needs to return a value of the same type and data location as its parameters to be used for the operator -.
// TypeError 7743: (440-440): Wrong return parameters in operator definition. The function "bitnot" needs to return exactly one value of type S to be used for the operator ~.
// TypeError 2271: (494-499): Built-in binary operator * cannot be applied to types struct S calldata and struct S calldata. No matching user-defined operator found.
// TypeError 4907: (527-529): Built-in unary operator - cannot be applied to type struct S calldata. No matching user-defined operator found.
@@ -0,0 +1,59 @@
using {
add as +,
sub as -,
mul as *,
div as /,
mod as %,
unsub as -,
bitnot as ~
} for S;
struct S {
uint x;
}
function add(S storage a, S storage) pure returns (S storage) {}
function sub(S storage a, uint) pure returns (S storage) {}
function mul(S storage a) pure returns (S storage) {}
function div(S storage a, S storage) pure returns (uint) {}
function mod(S storage a, S storage) pure {}
function unsub(S storage a) pure {}
function bitnot(S storage a, S storage) pure returns (S storage) {}
contract C {
S a;
S b;
function test() public view {
S storage c;
S storage d;
// storage ref
a + b; // OK
a - b;
a * b;
a / b;
a % b;
-a;
~a;
// storage ptr
c + d; // OK
c - d;
c * a;
a / d;
-c;
~c;
}
}
// ----
// TypeError 1884: (223-242): Wrong parameters in operator definition. The function "sub" needs to have one or two parameters of type S and the same data location to be used for the operator -.
// TypeError 1884: (283-296): Wrong parameters in operator definition. The function "mul" needs to have two parameters of type S and the same data location to be used for the operator *.
// TypeError 7743: (375-381): Wrong return parameters in operator definition. The function "div" needs to return exactly one value of type S to be used for the operator /.
// TypeError 7743: (427-427): Wrong return parameters in operator definition. The function "mod" needs to return exactly one value of type S to be used for the operator %.
// TypeError 7743: (463-463): Wrong return parameters in operator definition. The function "unsub" needs to return exactly one value of type S to be used for the operator -.
// TypeError 1884: (481-505): Wrong parameters in operator definition. The function "bitnot" needs to have exactly one parameter of type S to be used for the operator ~.
// TypeError 2271: (711-716): Built-in binary operator * cannot be applied to types struct S storage ref and struct S storage ref. No matching user-defined operator found.
// TypeError 4907: (768-770): Built-in unary operator ~ cannot be applied to type struct S storage ref. No matching user-defined operator found.
// TypeError 2271: (840-845): Built-in binary operator * cannot be applied to types struct S storage pointer and struct S storage ref. No matching user-defined operator found.
// TypeError 4907: (882-884): Built-in unary operator ~ cannot be applied to type struct S storage pointer. No matching user-defined operator found.