all: only allow defining `==` and `<` and auto generate `!=`, `>`, `>=` and `<=` (#8520)
parent
9dcf673216
commit
7ec116d588
|
@ -26,7 +26,8 @@
|
||||||
from local variables.
|
from local variables.
|
||||||
- `__offsetof` for low level needs (works like `offsetof` in C).
|
- `__offsetof` for low level needs (works like `offsetof` in C).
|
||||||
- vfmt now preserves empty lines, like gofmt.
|
- vfmt now preserves empty lines, like gofmt.
|
||||||
- Support for compile time environment variables via `$env('ENV_VAR')`.
|
- Support for compile time environment variables via `$env('ENV_VAR')`.
|
||||||
|
- Allow method declaration of `==` and `<` operators and auto generate `!=`, `>`, `<=` and `>=`.
|
||||||
|
|
||||||
## V 0.2.1
|
## V 0.2.1
|
||||||
*30 Dec 2020*
|
*30 Dec 2020*
|
||||||
|
|
|
@ -3637,7 +3637,8 @@ To improve safety and maintainability, operator overloading is limited:
|
||||||
- `==` and `!=` are self generated by the compiler but can be overriden.
|
- `==` and `!=` are self generated by the compiler but can be overriden.
|
||||||
- Calling other functions inside operator functions is not allowed.
|
- Calling other functions inside operator functions is not allowed.
|
||||||
- Operator functions can't modify their arguments.
|
- Operator functions can't modify their arguments.
|
||||||
- When using `<`, `>`, `>=`, `<=`, `==` and `!=` operators, the return type must be `bool`.
|
- When using `<` and `==` operators, the return type must be `bool`.
|
||||||
|
- `!=`, `>`, `<=` and `>=` are auto generated when `==` and `<` are defined.
|
||||||
- Both arguments must have the same type (just like with all operators in V).
|
- Both arguments must have the same type (just like with all operators in V).
|
||||||
- Assignment operators (`*=`, `+=`, `/=`, etc)
|
- Assignment operators (`*=`, `+=`, `/=`, etc)
|
||||||
are auto generated when the operators are defined though they must return the same type.
|
are auto generated when the operators are defined though they must return the same type.
|
||||||
|
|
|
@ -9,12 +9,6 @@ pub fn (t1 Time) == (t2 Time) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// operator `!=` returns true if provided time is not equal to time
|
|
||||||
[inline]
|
|
||||||
pub fn (t1 Time) != (t2 Time) bool {
|
|
||||||
return !(t1 == t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// operator `<` returns true if provided time is less than time
|
// operator `<` returns true if provided time is less than time
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (t1 Time) < (t2 Time) bool {
|
pub fn (t1 Time) < (t2 Time) bool {
|
||||||
|
@ -24,27 +18,6 @@ pub fn (t1 Time) < (t2 Time) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// operator `<=` returns true if provided time is less or equal to time
|
|
||||||
[inline]
|
|
||||||
pub fn (t1 Time) <= (t2 Time) bool {
|
|
||||||
return t1 < t2 || t1 == t2
|
|
||||||
}
|
|
||||||
|
|
||||||
// operator `>` returns true if provided time is greater than time
|
|
||||||
[inline]
|
|
||||||
pub fn (t1 Time) > (t2 Time) bool {
|
|
||||||
if t1.unix > t2.unix || (t1.unix == t2.unix && t1.microsecond > t2.microsecond) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// operator `>=` returns true if provided time is greater or equal to time
|
|
||||||
[inline]
|
|
||||||
pub fn (t1 Time) >= (t2 Time) bool {
|
|
||||||
return t1 > t2 || t1 == t2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time subtract using operator overloading.
|
// Time subtract using operator overloading.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (lhs Time) - (rhs Time) Duration {
|
pub fn (lhs Time) - (rhs Time) Duration {
|
||||||
|
|
|
@ -882,7 +882,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
.gt, .lt, .ge, .le {
|
.gt, .lt, .ge, .le {
|
||||||
if left.kind in [.array, .array_fixed] && right.kind in [.array, .array_fixed] {
|
if left.kind in [.array, .array_fixed] && right.kind in [.array, .array_fixed] {
|
||||||
c.error('only `==` and `!=` are defined on arrays', infix_expr.pos)
|
c.error('only `==` and `!=` are defined on arrays', infix_expr.pos)
|
||||||
} else if left.kind == .struct_ && right.kind == .struct_ {
|
} else if left.kind == .struct_ && right.kind == .struct_ && infix_expr.op in [.eq, .lt] {
|
||||||
if !(left.has_method(infix_expr.op.str()) && right.has_method(infix_expr.op.str())) {
|
if !(left.has_method(infix_expr.op.str()) && right.has_method(infix_expr.op.str())) {
|
||||||
left_name := c.table.type_to_str(left_type)
|
left_name := c.table.type_to_str(left_type)
|
||||||
right_name := c.table.type_to_str(right_type)
|
right_name := c.table.type_to_str(right_type)
|
||||||
|
@ -894,6 +894,14 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if left.kind == .struct_ && right.kind == .struct_ {
|
||||||
|
if !left.has_method('<') && infix_expr.op in [.ge, .le] {
|
||||||
|
c.error('cannot use `$infix_expr.op` as `<` operator method is not defined',
|
||||||
|
infix_expr.pos)
|
||||||
|
} else if !left.has_method('<') && infix_expr.op == .gt {
|
||||||
|
c.error('cannot use `>` as `<=` operator method is not defined', infix_expr.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.left_shift {
|
.left_shift {
|
||||||
if left.kind == .array {
|
if left.kind == .array {
|
||||||
|
@ -5617,8 +5625,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||||
c.error('.str() methods should have 0 arguments', node.pos)
|
c.error('.str() methods should have 0 arguments', node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.language == .v && node.is_method
|
if node.language == .v && node.is_method && node.name in ['+', '-', '*', '%', '/', '<', '=='] {
|
||||||
&& node.name in ['+', '-', '*', '%', '/', '<', '>', '==', '!=', '>=', '<='] {
|
|
||||||
if node.params.len != 2 {
|
if node.params.len != 2 {
|
||||||
c.error('operator methods should have exactly 1 argument', node.pos)
|
c.error('operator methods should have exactly 1 argument', node.pos)
|
||||||
} else {
|
} else {
|
||||||
|
@ -5636,8 +5643,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||||
} else if node.receiver.typ != node.params[1].typ {
|
} else if node.receiver.typ != node.params[1].typ {
|
||||||
c.error('expected `$receiver_sym.name` not `$param_sym.name` - both operands must be the same type for operator overloading',
|
c.error('expected `$receiver_sym.name` not `$param_sym.name` - both operands must be the same type for operator overloading',
|
||||||
node.params[1].type_pos)
|
node.params[1].type_pos)
|
||||||
} else if node.name in ['<', '>', '==', '!=', '>=', '<=']
|
} else if node.name in ['<', '=='] && node.return_type != table.bool_type {
|
||||||
&& node.return_type != table.bool_type {
|
|
||||||
c.error('operator comparison methods should return `bool`', node.pos)
|
c.error('operator comparison methods should return `bool`', node.pos)
|
||||||
} else if parent_sym.is_primitive() {
|
} else if parent_sym.is_primitive() {
|
||||||
c.error('cannot define operator methods on type alias for `$parent_sym.name`',
|
c.error('cannot define operator methods on type alias for `$parent_sym.name`',
|
||||||
|
|
|
@ -12,65 +12,58 @@ vlib/v/checker/tests/method_op_err.vv:14:18: error: expected `User` not `Foo` -
|
||||||
| ~~~
|
| ~~~
|
||||||
15 | return User{u.a - f.a, u.b-f.a}
|
15 | return User{u.a - f.a, u.b-f.a}
|
||||||
16 | }
|
16 | }
|
||||||
vlib/v/checker/tests/method_op_err.vv:18:1: error: operator comparison methods should return `bool`
|
vlib/v/checker/tests/method_op_err.vv:18:9: error: receiver cannot be `mut` for operator overloading
|
||||||
16 | }
|
16 | }
|
||||||
17 |
|
17 |
|
||||||
18 | fn (u User) > (u1 User) User {
|
18 | fn (mut u User) * (u1 User) User {
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~
|
||||||
19 | return User{}
|
19 | return User{}
|
||||||
20 | }
|
20 | }
|
||||||
vlib/v/checker/tests/method_op_err.vv:22:9: error: receiver cannot be `mut` for operator overloading
|
vlib/v/checker/tests/method_op_err.vv:22:1: error: argument cannot be `mut` for operator overloading
|
||||||
20 | }
|
20 | }
|
||||||
21 |
|
21 |
|
||||||
22 | fn (mut u User) * (u1 User) User {
|
22 | fn (u User) / (mut u1 User) User {
|
||||||
| ~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
23 | return User{}
|
23 | return User{}
|
||||||
24 | }
|
24 | }
|
||||||
vlib/v/checker/tests/method_op_err.vv:26:1: error: argument cannot be `mut` for operator overloading
|
vlib/v/checker/tests/method_op_err.vv:32:24: error: infix expr: cannot use `Foo` (right expression) as `User`
|
||||||
24 | }
|
30 | fn main() {
|
||||||
25 |
|
31 | println(User{3, 4})
|
||||||
26 | fn (u User) / (mut u1 User) User {
|
32 | println(User{3, 4} - Foo{3, 3})
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
27 | return User{}
|
|
||||||
28 | }
|
|
||||||
vlib/v/checker/tests/method_op_err.vv:36:24: error: infix expr: cannot use `Foo` (right expression) as `User`
|
|
||||||
34 | fn main() {
|
|
||||||
35 | println(User{3, 4})
|
|
||||||
36 | println(User{3, 4} - Foo{3, 3})
|
|
||||||
| ^
|
| ^
|
||||||
37 | println(User{3, 2} < User{2, 4})
|
33 | println(User{3, 2} < User{2, 4})
|
||||||
38 | println(User{3, 4} < Foo{3, 4})
|
34 | println(User{3, 4} < Foo{3, 4})
|
||||||
vlib/v/checker/tests/method_op_err.vv:37:24: error: undefined operation `User` < `User`
|
vlib/v/checker/tests/method_op_err.vv:33:24: error: undefined operation `User` < `User`
|
||||||
35 | println(User{3, 4})
|
31 | println(User{3, 4})
|
||||||
36 | println(User{3, 4} - Foo{3, 3})
|
32 | println(User{3, 4} - Foo{3, 3})
|
||||||
37 | println(User{3, 2} < User{2, 4})
|
33 | println(User{3, 2} < User{2, 4})
|
||||||
| ^
|
| ^
|
||||||
38 | println(User{3, 4} < Foo{3, 4})
|
34 | println(User{3, 4} < Foo{3, 4})
|
||||||
39 | mut u := User{3, 4}
|
35 | mut u := User{3, 4}
|
||||||
vlib/v/checker/tests/method_op_err.vv:38:24: error: mismatched types `User` and `Foo`
|
vlib/v/checker/tests/method_op_err.vv:34:24: error: mismatched types `User` and `Foo`
|
||||||
36 | println(User{3, 4} - Foo{3, 3})
|
32 | println(User{3, 4} - Foo{3, 3})
|
||||||
37 | println(User{3, 2} < User{2, 4})
|
33 | println(User{3, 2} < User{2, 4})
|
||||||
38 | println(User{3, 4} < Foo{3, 4})
|
34 | println(User{3, 4} < Foo{3, 4})
|
||||||
| ^
|
| ^
|
||||||
39 | mut u := User{3, 4}
|
35 | mut u := User{3, 4}
|
||||||
40 | u += 12
|
36 | u += 12
|
||||||
vlib/v/checker/tests/method_op_err.vv:40:10: error: cannot assign to `u`: expected `User`, not `int literal`
|
vlib/v/checker/tests/method_op_err.vv:36:10: error: cannot assign to `u`: expected `User`, not `int literal`
|
||||||
38 | println(User{3, 4} < Foo{3, 4})
|
34 | println(User{3, 4} < Foo{3, 4})
|
||||||
39 | mut u := User{3, 4}
|
35 | mut u := User{3, 4}
|
||||||
40 | u += 12
|
36 | u += 12
|
||||||
| ~~
|
| ~~
|
||||||
41 | u %= User{1, 3}
|
37 | u %= User{1, 3}
|
||||||
42 | u += User{2, 3}
|
38 | u += User{2, 3}
|
||||||
vlib/v/checker/tests/method_op_err.vv:41:5: error: operator %= not defined on left operand type `User`
|
vlib/v/checker/tests/method_op_err.vv:37:5: error: operator %= not defined on left operand type `User`
|
||||||
39 | mut u := User{3, 4}
|
35 | mut u := User{3, 4}
|
||||||
40 | u += 12
|
36 | u += 12
|
||||||
41 | u %= User{1, 3}
|
37 | u %= User{1, 3}
|
||||||
| ^
|
| ^
|
||||||
42 | u += User{2, 3}
|
38 | u += User{2, 3}
|
||||||
43 | }
|
39 | }
|
||||||
vlib/v/checker/tests/method_op_err.vv:42:7: error: operator `+` must return `User` to be used as an assignment operator
|
vlib/v/checker/tests/method_op_err.vv:38:7: error: operator `+` must return `User` to be used as an assignment operator
|
||||||
40 | u += 12
|
36 | u += 12
|
||||||
41 | u %= User{1, 3}
|
37 | u %= User{1, 3}
|
||||||
42 | u += User{2, 3}
|
38 | u += User{2, 3}
|
||||||
| ~~
|
| ~~
|
||||||
43 | }
|
39 | }
|
||||||
|
|
|
@ -15,10 +15,6 @@ fn (u User) - (f Foo) User {
|
||||||
return User{u.a - f.a, u.b-f.a}
|
return User{u.a - f.a, u.b-f.a}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (u User) > (u1 User) User {
|
|
||||||
return User{}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut u User) * (u1 User) User {
|
fn (mut u User) * (u1 User) User {
|
||||||
return User{}
|
return User{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,8 +251,8 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
if !is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 {
|
if !is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 {
|
||||||
g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}')
|
g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}')
|
||||||
} else if is_reverse && sym.has_method('>') && infix_expr.left.str().len == 1 {
|
} else if is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 {
|
||||||
g.definitions.writeln('\tif (${styp}__gt(*a, *b)) { return -1; } else { return 1; }}')
|
g.definitions.writeln('\tif (!${styp}__lt(*a, *b)) { return -1; } else { return 1; }}')
|
||||||
} else {
|
} else {
|
||||||
field_type := g.typ(infix_expr.left_type)
|
field_type := g.typ(infix_expr.left_type)
|
||||||
mut left_expr_str := g.write_expr_to_string(infix_expr.left)
|
mut left_expr_str := g.write_expr_to_string(infix_expr.left)
|
||||||
|
|
|
@ -3019,7 +3019,6 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
}
|
}
|
||||||
right_sym := g.table.get_type_symbol(node.right_type)
|
right_sym := g.table.get_type_symbol(node.right_type)
|
||||||
has_eq_overloaded := !left_sym.has_method('==')
|
has_eq_overloaded := !left_sym.has_method('==')
|
||||||
has_ne_overloaded := !left_sym.has_method('!=')
|
|
||||||
unaliased_right := if right_sym.info is table.Alias {
|
unaliased_right := if right_sym.info is table.Alias {
|
||||||
right_sym.info.parent_type
|
right_sym.info.parent_type
|
||||||
} else {
|
} else {
|
||||||
|
@ -3174,16 +3173,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
} else if node.op in [.eq, .ne] && left_sym.kind == .struct_ && right_sym.kind == .struct_ {
|
} else if node.op in [.eq, .ne] && left_sym.kind == .struct_ && right_sym.kind == .struct_ {
|
||||||
if has_eq_overloaded && !has_ne_overloaded {
|
if !has_eq_overloaded {
|
||||||
// Define `!=` as negation of Autogenerated `==`
|
|
||||||
styp := g.typ(left_type)
|
|
||||||
if node.op == .eq {
|
|
||||||
g.write('!${styp}__ne(')
|
|
||||||
} else if node.op == .ne {
|
|
||||||
g.write('${styp}__ne(')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !has_eq_overloaded && has_ne_overloaded {
|
|
||||||
// Define `==` as negation of Autogenerated `!=`
|
// Define `==` as negation of Autogenerated `!=`
|
||||||
styp := g.typ(left_type)
|
styp := g.typ(left_type)
|
||||||
if node.op == .ne {
|
if node.op == .ne {
|
||||||
|
@ -3192,16 +3182,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
g.write('${styp}__eq(')
|
g.write('${styp}__eq(')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !has_eq_overloaded && !has_ne_overloaded {
|
if has_eq_overloaded {
|
||||||
// Overload both User defined `==` and `!=`
|
|
||||||
styp := g.typ(left_type)
|
|
||||||
if node.op == .eq {
|
|
||||||
g.write('${styp}__eq(')
|
|
||||||
} else if node.op == .ne {
|
|
||||||
g.write('${styp}__ne(')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if has_eq_overloaded && has_ne_overloaded {
|
|
||||||
// Auto generate both `==` and `!=`
|
// Auto generate both `==` and `!=`
|
||||||
ptr_typ := g.gen_struct_equality_fn(left_type)
|
ptr_typ := g.gen_struct_equality_fn(left_type)
|
||||||
if node.op == .eq {
|
if node.op == .eq {
|
||||||
|
@ -3374,8 +3355,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
&& g.typ((left_sym.info as table.Alias).parent_type).split('__').last()[0].is_capital()
|
&& g.typ((left_sym.info as table.Alias).parent_type).split('__').last()[0].is_capital()
|
||||||
// Do not generate operator overloading with these `right_sym.kind`.
|
// Do not generate operator overloading with these `right_sym.kind`.
|
||||||
e := right_sym.kind !in [.voidptr, .int_literal, .int]
|
e := right_sym.kind !in [.voidptr, .int_literal, .int]
|
||||||
if node.op in [.plus, .minus, .mul, .div, .mod, .lt, .gt, .eq, .ne, .le, .ge]
|
if node.op in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && ((a && b && e) || c || d) {
|
||||||
&& ((a && b && e) || c|| d) {
|
|
||||||
// Overloaded operators
|
// Overloaded operators
|
||||||
g.write(g.typ(if !d { left_type } else { (left_sym.info as table.Alias).parent_type }))
|
g.write(g.typ(if !d { left_type } else { (left_sym.info as table.Alias).parent_type }))
|
||||||
g.write('_')
|
g.write('_')
|
||||||
|
@ -3385,6 +3365,28 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
} else if node.op in [.ne, .gt, .ge, .le] && ((a && b && e) || c || d) {
|
||||||
|
typ := g.typ(if !d { left_type } else { (left_sym.info as table.Alias).parent_type })
|
||||||
|
g.write('!$typ')
|
||||||
|
g.write('_')
|
||||||
|
if node.op == .ne {
|
||||||
|
g.write('_eq')
|
||||||
|
} else if node.op in [.ge, .le, .gt] {
|
||||||
|
g.write('_lt')
|
||||||
|
}
|
||||||
|
if node.op == .le {
|
||||||
|
g.write('(')
|
||||||
|
g.expr(node.right)
|
||||||
|
g.write(', ')
|
||||||
|
g.expr(node.left)
|
||||||
|
g.write(')')
|
||||||
|
} else {
|
||||||
|
g.write('(')
|
||||||
|
g.expr(node.left)
|
||||||
|
g.write(', ')
|
||||||
|
g.expr(node.right)
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C
|
need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C
|
||||||
if need_par {
|
if need_par {
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
mut name := node.name
|
mut name := node.name
|
||||||
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '<=', '>='] {
|
if name in ['+', '-', '*', '/', '%', '<', '=='] {
|
||||||
name = util.replace_op(name)
|
name = util.replace_op(name)
|
||||||
}
|
}
|
||||||
if node.is_method {
|
if node.is_method {
|
||||||
|
|
|
@ -275,14 +275,16 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.tok.kind in [.plus, .minus, .mul, .div, .mod, .gt, .lt, .eq, .ne, .le, .ge]
|
if p.tok.kind in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && p.peek_tok.kind == .lpar {
|
||||||
&& p.peek_tok.kind == .lpar {
|
|
||||||
name = p.tok.kind.str() // op_to_fn_name()
|
name = p.tok.kind.str() // op_to_fn_name()
|
||||||
if rec_type == table.void_type {
|
if rec_type == table.void_type {
|
||||||
p.error_with_pos('cannot use operator overloading with normal functions',
|
p.error_with_pos('cannot use operator overloading with normal functions',
|
||||||
p.tok.position())
|
p.tok.position())
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
|
} else if p.tok.kind in [.ne, .gt, .ge, .le] && p.peek_tok.kind == .lpar {
|
||||||
|
p.error_with_pos('cannot overload `!=`, `>`, `<=` and `>=` as they are auto generated with `==` and`<`',
|
||||||
|
p.tok.position())
|
||||||
}
|
}
|
||||||
// <T>
|
// <T>
|
||||||
generic_params := p.parse_generic_params()
|
generic_params := p.parse_generic_params()
|
||||||
|
|
|
@ -27,10 +27,6 @@ fn (a Vec) % (b Vec) Vec {
|
||||||
return Vec{a.x % b.x, a.y % b.y}
|
return Vec{a.x % b.x, a.y % b.y}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (a Vec) > (b Vec) bool {
|
|
||||||
return a.x > b.x && a.y > b.y
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (a Vec) < (b Vec) bool {
|
fn (a Vec) < (b Vec) bool {
|
||||||
return a.x < b.x && a.y < b.y
|
return a.x < b.x && a.y < b.y
|
||||||
}
|
}
|
||||||
|
@ -39,18 +35,6 @@ fn (a Vec) == (b Vec) bool {
|
||||||
return a.x == b.y && a.y == b.x
|
return a.x == b.y && a.y == b.x
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (a Vec) != (b Vec) bool {
|
|
||||||
return !(a == b)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (a Vec) >= (b Vec) bool {
|
|
||||||
return a > b || a == b
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (a Vec) <= (b Vec) bool {
|
|
||||||
return a < b || a == b
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_operator_overloading_with_string_interpolation() {
|
fn test_operator_overloading_with_string_interpolation() {
|
||||||
a := Vec{2, 3}
|
a := Vec{2, 3}
|
||||||
b := Vec{4, 5}
|
b := Vec{4, 5}
|
||||||
|
|
|
@ -11,10 +11,6 @@ fn (p Parent) < (p1 Parent) bool {
|
||||||
return p.name < p1.name
|
return p.name < p1.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p Parent) > (p1 Parent) bool {
|
|
||||||
return p.name > p1.name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_sorting_by_different_criteria_in_same_function() {
|
fn test_sorting_by_different_criteria_in_same_function() {
|
||||||
mut arr := [
|
mut arr := [
|
||||||
Parent{Child{0.2}, 'def'},
|
Parent{Child{0.2}, 'def'},
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
struct User {
|
|
||||||
name string
|
|
||||||
num int
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (u User) != (u1 User) bool {
|
|
||||||
return u.num != u1.num
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_eq_op() {
|
|
||||||
u1 := User{'Joe', 23}
|
|
||||||
u2 := User{'Joe', 24}
|
|
||||||
assert u1 != u2
|
|
||||||
assert (u1 == u2) == false
|
|
||||||
}
|
|
|
@ -382,9 +382,6 @@ pub fn replace_op(s string) string {
|
||||||
} else {
|
} else {
|
||||||
suffix := match s {
|
suffix := match s {
|
||||||
'==' { '_eq' }
|
'==' { '_eq' }
|
||||||
'!=' { '_ne' }
|
|
||||||
'<=' { '_le' }
|
|
||||||
'>=' { '_ge' }
|
|
||||||
else { '' }
|
else { '' }
|
||||||
}
|
}
|
||||||
return s[..s.len - 2] + suffix
|
return s[..s.len - 2] + suffix
|
||||||
|
|
Loading…
Reference in New Issue