Disallow redefining <<, >>, ** and !

This commit is contained in:
Kamil Śliwak 2023-01-20 11:26:29 +01:00
parent a1438239c3
commit 56a6613c21
11 changed files with 58 additions and 86 deletions

View File

@ -46,7 +46,7 @@ Note that private library functions can only be specified when ``using for`` is
If you define an operator (e.g. ``using {f as +} for T``), then the type (``T``) must be a
:ref:`user-defined value type <user-defined-value-types>`.
The definition of an operator must be a ``pure`` function with the types of all parameters and
the return value matching ``T``, except for comparison and boolean operators, where the return value must
the return value matching ``T``, except for comparison operators, where the return value must
be of type ``bool``.
The following operators can be defined this way:
@ -54,18 +54,16 @@ The following operators can be defined this way:
+------------+---------+----------------------------------------------+
| Category | Arity | Operators |
+============+=========+==============================================+
| Bitwise | binary | ``&``, ``|``, ``^``, ``<<``, ``>>`` |
| Bitwise | binary | ``&``, ``|``, ``^`` |
| +---------+----------------------------------------------+
| | unary | ``~`` |
+------------+---------+----------------------------------------------+
| Arithmetic | binary | ``+``, ``-``, ``*``, ``/``, ``%``, ``**`` |
| Arithmetic | binary | ``+``, ``-``, ``*``, ``/``, ``%`` |
| +---------+----------------------------------------------+
| | unary | ``-`` |
+------------+---------+----------------------------------------------+
| Comparison | binary | ``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=`` |
+------------+---------+----------------------------------------------+
| Boolean | unary | ``!`` |
+------------+---------+----------------------------------------------+
Note that ``-`` is both binary and unary.
Whether the definition implements one or the other depends on the number of its arguments.

View File

@ -319,11 +319,8 @@ userDefinableOperator:
| BitNot
| BitOr
| BitXor
| Sar
| Shl
| Add
| Div
| Exp
| Mod
| Mul
| Sub
@ -332,8 +329,7 @@ userDefinableOperator:
| GreaterThanOrEqual
| LessThan
| LessThanOrEqual
| NotEqual
| Not;
| NotEqual;
/**
* Using directive to attach library functions and free functions to types.

View File

@ -13,15 +13,12 @@ std::vector<langutil::Token> const userDefinableOperators = {
langutil::Token::BitAnd,
langutil::Token::BitXor,
langutil::Token::BitNot,
langutil::Token::SHL,
langutil::Token::SAR,
// Arithmetic
langutil::Token::Add,
langutil::Token::Sub,
langutil::Token::Mul,
langutil::Token::Div,
langutil::Token::Mod,
langutil::Token::Exp,
// Comparison
langutil::Token::Equal,
langutil::Token::NotEqual,
@ -29,8 +26,6 @@ std::vector<langutil::Token> const userDefinableOperators = {
langutil::Token::GreaterThan,
langutil::Token::LessThanOrEqual,
langutil::Token::GreaterThanOrEqual,
// Boolean
langutil::Token::Not
};
}

View File

@ -1,17 +1,14 @@
type Int is int8;
using {
bitor as |, bitand as &, bitxor as ^, bitnot as ~, shl as <<, sar as >>,
add as +, sub as -, unsub as -, mul as *, div as /, mod as %, exp as **,
eq as ==, noteq as !=, lt as <, gt as >, leq as <=, geq as >=,
not as !
bitor as |, bitand as &, bitxor as ^, bitnot as ~,
add as +, sub as -, unsub as -, mul as *, div as /, mod as %,
eq as ==, noteq as !=, lt as <, gt as >, leq as <=, geq as >=
} for Int;
function bitor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) | Int.unwrap(y)); }
function bitand(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) & Int.unwrap(y)); }
function bitxor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) ^ Int.unwrap(y)); }
function bitnot(Int x) pure returns (Int) { return Int.wrap(~Int.unwrap(x)); }
function shl(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) << uint8(Int.unwrap(y))); }
function sar(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) >> uint8(Int.unwrap(y))); }
function add(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) + Int.unwrap(y)); }
function sub(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) - Int.unwrap(y)); }
@ -19,7 +16,6 @@ function unsub(Int x) pure returns (Int) { return Int.wrap(-Int.unwrap(x)); }
function mul(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) * Int.unwrap(y)); }
function div(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) / Int.unwrap(y)); }
function mod(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) % Int.unwrap(y)); }
function exp(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) ** uint8(Int.unwrap(y))); }
function eq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) == Int.unwrap(y); }
function noteq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) != Int.unwrap(y); }
@ -28,14 +24,11 @@ function gt(Int x, Int y) pure returns (bool) { return Int.unwrap(x) > Int.unwra
function leq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) <= Int.unwrap(y); }
function geq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) >= Int.unwrap(y); }
function not(Int x) pure returns (bool) { return Int.unwrap(x) == 0; }
contract C {
Int constant ZERO = Int.wrap(0);
Int constant ONE = Int.wrap(1);
Int constant TWO = Int.wrap(2);
Int constant THREE = Int.wrap(3);
Int constant FOUR = Int.wrap(4);
Int constant SIX = Int.wrap(6);
function test_bitwise() public pure {
@ -51,12 +44,6 @@ contract C {
assert(Int.unwrap(~ZERO) == -1);
assert(Int.unwrap(~ONE) == -2);
assert(Int.unwrap(~TWO) == -3);
assert(Int.unwrap(ONE << ONE) == 2);
assert(Int.unwrap(ONE << TWO) == 4);
assert(Int.unwrap(TWO >> ONE) == 1);
assert(Int.unwrap(FOUR >> TWO) == 1);
}
function test_arithmetic() public pure {
@ -77,9 +64,6 @@ contract C {
assert(Int.unwrap(SIX % TWO) == 0);
assert(Int.unwrap(THREE % TWO) == 1);
assert(Int.unwrap(ONE ** SIX) == 1);
assert(Int.unwrap(TWO ** TWO) == 4);
}
function test_comparison() public pure {
@ -101,15 +85,8 @@ contract C {
assert((ONE >= TWO) == false);
assert((TWO >= ONE) == true);
}
function test_boolean() public pure {
assert(!ZERO == true);
assert(!ONE == false);
assert(!TWO == false);
}
}
// ----
// test_bitwise() ->
// test_arithmetic() ->
// test_comparison() ->
// test_boolean() ->

View File

@ -1,15 +1,13 @@
type Int is int64;
using {
bitor as |, bitand as &, bitxor as ^, bitnot as ~, shl as <<, sar as >>,
add as +, sub as -, unsub as -, mul as *, div as /, mod as %, exp as **
bitor as |, bitand as &, bitxor as ^, bitnot as ~,
add as +, sub as -, unsub as -, mul as *, div as /, mod as %
} for Int;
function bitor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) | Int.unwrap(y)); }
function bitand(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) & Int.unwrap(y)); }
function bitxor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) ^ Int.unwrap(y)); }
function bitnot(Int x) pure returns (Int) { return Int.wrap(~Int.unwrap(x)); }
function shl(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) << uint64(Int.unwrap(y))); }
function sar(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) >> uint64(Int.unwrap(y))); }
function add(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) + Int.unwrap(y)); }
function sub(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) - Int.unwrap(y)); }
@ -17,7 +15,6 @@ function unsub(Int x) pure returns (Int) { return Int.wrap(-Int.unwrap(x)); }
function mul(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) * Int.unwrap(y)); }
function div(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) / Int.unwrap(y)); }
function mod(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) % Int.unwrap(y)); }
function exp(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) ** uint64(Int.unwrap(y))); }
contract C {
Int constant I0 = Int.wrap(0);
@ -28,6 +25,7 @@ contract C {
Int constant I5 = Int.wrap(5);
Int constant I6 = Int.wrap(6);
Int constant I7 = Int.wrap(7);
Int constant I8 = Int.wrap(8);
Int constant I10 = Int.wrap(10);
Int constant I13 = Int.wrap(13);
Int constant I15 = Int.wrap(15);
@ -40,26 +38,26 @@ contract C {
}
function test_bitwise_arithmetic() public pure {
assert(Int.unwrap(I1 << I1 + I1 & ~I1 | I1 << I2 * I3 - I1 & ~I3) == (1 << 1 + 1 & ~1 | 1 << 2 * 3 - 1 & ~3));
assert(Int.unwrap(I1 << I1 + I1 & ~I1 | I1 << I2 * I3 - I1 & ~I3) == (((1 << (1 + 1)) & (~1)) | ((1 << ((2 * 3) - 1)) & (~3))));
assert(Int.unwrap(I2 + I2 & ~I1 | I6 * I6 - I4 & ~I3) == (2 + 2 & ~1 | 6 * 6 - 4 & ~3));
assert(Int.unwrap(I2 + I2 & ~I1 | I6 * I6 - I4 & ~I3) == (((2 + 2) & (~1)) | (((6 * 6) - 4) & (~3))));
}
function test_arithmetic() public pure {
assert(Int.unwrap(I1 + I2 ** I3 / I4 - I5 % I6 * I7) == (1 + 2 ** 3 / 4 - 5 % 6 * 7));
assert(Int.unwrap(I1 + I2 ** I3 / I4 - I5 % I6 * I7) == ((1 + ((2 ** 3) / 4)) - ((5 % 6) * 7)));
assert(Int.unwrap(I1 + I8 / I4 - I5 % I6 * I7) == (1 + 8 / 4 - 5 % 6 * 7));
assert(Int.unwrap(I1 + I8 / I4 - I5 % I6 * I7) == ((1 + (8 / 4)) - ((5 % 6) * 7)));
}
function test_all() public pure {
assert(
Int.unwrap(I128 + I1 - I10 + I4 & ~I1 ^ ~I1 >> I1 + I1 << I3 ** I2 | -I15 % -I10 * I20 / I2 + I13 & ~I3) ==
(128 + 1 - 10 + 4 & ~1 ^ ~1 >> 1 + 1 << 3 ** 2 | -15 % -10 * 20 / 2 + 13 & ~3)
Int.unwrap(I128 + I1 - I10 + I4 & ~I1 ^ ~I1 * I2 | -I15 % -I10 * I20 / I2 + I13 & ~I3) ==
(128 + 1 - 10 + 4 & ~1 ^ ~1 * 2 | -15 % -10 * 20 / 2 + 13 & ~3)
);
assert(
Int.unwrap(I128 + I1 - I10 + I4 & ~I1 ^ ~I1 >> I1 + I1 << I3 ** I2 | -I15 % -I10 * I20 / I2 + I13 & ~I3) ==
Int.unwrap(I128 + I1 - I10 + I4 & ~I1 ^ ~I1 * I2 | -I15 % -I10 * I20 / I2 + I13 & ~I3) ==
(
(
((((128 + 1) - 10) + 4) & (~1)) ^
(((~1) >> (1 + 1)) << (3 ** 2))
((~1) * 2)
) |
((((((-15) % (-10)) * 20) / 2) + 13) & (~3))
)

View File

@ -1,8 +1,12 @@
using {
f as new,
f as delete,
f as **,
f as <<,
f as >>,
f as &&,
f as ||,
f as !,
f as =,
f as |=,
f as ^=,
@ -18,20 +22,24 @@ using {
f as --
} for int256;
// ----
// ParserError 4403: (17-20): Not a user-definable operator: new. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (31-37): Not a user-definable operator: delete. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (48-50): Not a user-definable operator: &&. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (61-63): Not a user-definable operator: ||. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (74-75): Not a user-definable operator: =. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (86-88): Not a user-definable operator: |=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (99-101): Not a user-definable operator: ^=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (112-114): Not a user-definable operator: &=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (125-128): Not a user-definable operator: <<=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (139-142): Not a user-definable operator: >>=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (153-155): Not a user-definable operator: +=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (166-168): Not a user-definable operator: -=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (179-181): Not a user-definable operator: *=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (192-194): Not a user-definable operator: /=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (205-207): Not a user-definable operator: %=. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (218-220): Not a user-definable operator: ++. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (231-233): Not a user-definable operator: --. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (17-20): Not a user-definable operator: new. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (31-37): Not a user-definable operator: delete. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (48-50): Not a user-definable operator: **. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (61-63): Not a user-definable operator: <<. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (74-76): Not a user-definable operator: >>. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (87-89): Not a user-definable operator: &&. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (100-102): Not a user-definable operator: ||. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (113-114): Not a user-definable operator: !. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (125-126): Not a user-definable operator: =. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (137-139): Not a user-definable operator: |=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (150-152): Not a user-definable operator: ^=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (163-165): Not a user-definable operator: &=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (176-179): Not a user-definable operator: <<=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (190-193): Not a user-definable operator: >>=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (204-206): Not a user-definable operator: +=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (217-219): Not a user-definable operator: -=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (230-232): Not a user-definable operator: *=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (243-245): Not a user-definable operator: /=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (256-258): Not a user-definable operator: %=. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (269-271): Not a user-definable operator: ++. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (282-284): Not a user-definable operator: --. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=

View File

@ -6,9 +6,9 @@ using {
f as ()
} for int256;
// ----
// ParserError 4403: (17-18): Not a user-definable operator: x. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (29-37): Not a user-definable operator: operator. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (48-50): Not a user-definable operator: as. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (61-64): Not a user-definable operator: 123. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (75-76): Not a user-definable operator: (. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (17-18): Not a user-definable operator: x. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (29-37): Not a user-definable operator: operator. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (48-50): Not a user-definable operator: as. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (61-64): Not a user-definable operator: 123. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 4403: (75-76): Not a user-definable operator: (. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 2314: (76-77): Expected '}' but got ')'

View File

@ -1,4 +1,4 @@
using {f as} for uint;
// ----
// ParserError 4403: (11-12): Not a user-definable operator: }. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (11-12): Not a user-definable operator: }. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=
// ParserError 2314: (13-16): Expected '}' but got 'for'

View File

@ -1,3 +1,3 @@
using {f as as} for uint;
// ----
// ParserError 4403: (12-14): Not a user-definable operator: as. Only the following operators can be user-defined: |, &, ^, ~, <<, >>, +, -, *, /, %, **, ==, !=, <, >, <=, >=, !
// ParserError 4403: (12-14): Not a user-definable operator: as. Only the following operators can be user-defined: |, &, ^, ~, +, -, *, /, %, ==, !=, <, >, <=, >=

View File

@ -1,13 +1,13 @@
==== Source: s1.sol ====
type Bool is bool;
type Int is int;
==== Source: s2.sol ====
import "s1.sol";
function not(Bool) pure returns (bool) {}
function bitnot(Int) pure returns (Int) {}
contract C {
using {not as !} for Bool global;
using {bitnot as ~} for Int global;
}
// ----
// SyntaxError 3367: (s2.sol:78-111): "global" can only be used at file level.
// SyntaxError 3367: (s2.sol:79-114): "global" can only be used at file level.

View File

@ -1,11 +1,11 @@
==== Source: s1.sol ====
type Bool is bool;
type Int is int;
==== Source: s2.sol ====
import "s1.sol";
function not(Bool) pure returns (bool) {}
function bitnot(Int) pure returns (Int) {}
using {not as !} for Bool global;
using {bitnot as ~} for Int global;
// ----
// TypeError 4117: (s2.sol:61-94): Can only use "global" with types defined in the same source unit at file level.
// TypeError 4117: (s2.sol:62-97): Can only use "global" with types defined in the same source unit at file level.