mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: implement > and < for structs (#7774)
This commit is contained in:
parent
d15d13674c
commit
24b18f05c4
@ -3148,9 +3148,11 @@ operator overloading is an important feature to have in order to improve readabi
|
||||
|
||||
To improve safety and maintainability, operator overloading is limited:
|
||||
|
||||
- It's only possible to overload `+, -, *, /, %` operators.
|
||||
- It's only possible to overload `+, -, *, /, %, <, >` operators.
|
||||
- `==` and `!=` are self generated by the compiler.
|
||||
- Calling other functions inside operator functions is not allowed.
|
||||
- Operator functions can't modify their arguments.
|
||||
- When using `<` and `>`, the return type must be `bool`.
|
||||
- Both arguments must have the same type (just like with all operators in V).
|
||||
|
||||
## Inline assembly
|
||||
|
@ -52,7 +52,7 @@ pub fn (node &FnDecl) stringify(t &table.Table, cur_mod string, m2a map[string]s
|
||||
}
|
||||
}
|
||||
f.write('fn $receiver$name')
|
||||
if name in ['+', '-', '*', '/', '%'] {
|
||||
if name in ['+', '-', '*', '/', '%', '<', '>'] {
|
||||
f.write(' ')
|
||||
}
|
||||
if node.is_generic {
|
||||
|
@ -4949,7 +4949,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
c.error('.str() methods should have 0 arguments', node.pos)
|
||||
}
|
||||
}
|
||||
if node.language == .v && node.is_method && node.name in ['+', '-', '*', '%', '/'] {
|
||||
if node.language == .v && node.is_method && node.name in ['+', '-', '*', '%', '/', '<', '>'] {
|
||||
if node.params.len != 2 {
|
||||
c.error('operator methods should have exactly 1 argument', node.pos)
|
||||
} else {
|
||||
@ -4961,6 +4961,8 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
} else {
|
||||
if node.receiver.typ != node.params[1].typ {
|
||||
c.error('both sides of an operator must be the same type', node.pos)
|
||||
} else if node.name in ['<', '>'] && node.return_type != table.bool_type {
|
||||
c.error('operator comparison methods should return `bool`', node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,16 @@ vlib/v/checker/tests/method_op_err.vv:14:1: error: both sides of an operator mus
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
15 | return User{u.a - f.a, u.b-f.a}
|
||||
16 | }
|
||||
vlib/v/checker/tests/method_op_err.vv:20:24: error: infix expr: cannot use `Foo` (right expression) as `User`
|
||||
18 | fn main() {
|
||||
19 | println(User{3, 4})
|
||||
20 | println(User{3, 4} - Foo{3, 3})
|
||||
vlib/v/checker/tests/method_op_err.vv:18:1: error: operator comparison methods should return `bool`
|
||||
16 | }
|
||||
17 |
|
||||
18 | fn (u User) > (u1 User) User {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
19 | return User{}
|
||||
20 | }
|
||||
vlib/v/checker/tests/method_op_err.vv:24:24: error: infix expr: cannot use `Foo` (right expression) as `User`
|
||||
22 | fn main() {
|
||||
23 | println(User{3, 4})
|
||||
24 | println(User{3, 4} - Foo{3, 3})
|
||||
| ^
|
||||
21 | }
|
||||
25 | }
|
||||
|
@ -15,6 +15,10 @@ fn (u User) - (f Foo) User {
|
||||
return User{u.a - f.a, u.b-f.a}
|
||||
}
|
||||
|
||||
fn (u User) > (u1 User) User {
|
||||
return User{}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println(User{3, 4})
|
||||
println(User{3, 4} - Foo{3, 3})
|
||||
|
@ -3153,13 +3153,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
g.expr(node.left)
|
||||
g.write(')')
|
||||
} else {
|
||||
a := left_sym.name[0].is_capital() || left_sym.name.contains('.')
|
||||
a := (left_sym.name[0].is_capital() || left_sym.name.contains('.')) &&
|
||||
left_sym.kind != .enum_
|
||||
b := left_sym.kind != .alias
|
||||
c := left_sym.kind == .alias && (left_sym.info as table.Alias).language == .c
|
||||
// Check if aliased type is a struct
|
||||
d := !b &&
|
||||
g.typ((left_sym.info as table.Alias).parent_type).split('__').last()[0].is_capital()
|
||||
if node.op in [.plus, .minus, .mul, .div, .mod] && ((a && b) || c || d) {
|
||||
if node.op in [.plus, .minus, .mul, .div, .mod, .lt, .gt] && ((a && b) || c || d) {
|
||||
// Overloaded operators
|
||||
g.write(g.typ(if !d {
|
||||
left_type
|
||||
@ -5006,6 +5007,8 @@ fn op_to_fn_name(name string) string {
|
||||
'*' { '_op_mul' }
|
||||
'/' { '_op_div' }
|
||||
'%' { '_op_mod' }
|
||||
'<' { '_op_lt' }
|
||||
'>' { '_op_gt' }
|
||||
else { 'bad op $name' }
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||
}
|
||||
//
|
||||
mut name := it.name
|
||||
if name[0] in [`+`, `-`, `*`, `/`, `%`] {
|
||||
if name[0] in [`+`, `-`, `*`, `/`, `%`, `<`, `>`] {
|
||||
name = util.replace_op(name)
|
||||
}
|
||||
if it.is_method {
|
||||
|
@ -270,7 +270,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.tok.kind in [.plus, .minus, .mul, .div, .mod] {
|
||||
if p.tok.kind in [.plus, .minus, .mul, .div, .mod, .gt, .lt] && p.peek_tok.kind == .lpar {
|
||||
name = p.tok.kind.str() // op_to_fn_name()
|
||||
if rec_type == table.void_type {
|
||||
p.error_with_pos('cannot use operator overloading with normal functions',
|
||||
|
@ -7,50 +7,60 @@ pub fn (a Vec) str() string {
|
||||
return '{$a.x, $a.y}'
|
||||
}
|
||||
|
||||
fn (a Vec) +(b Vec) Vec {
|
||||
fn (a Vec) + (b Vec) Vec {
|
||||
return Vec{a.x + b.x, a.y + b.y}
|
||||
}
|
||||
|
||||
fn (a Vec) -(b Vec) Vec {
|
||||
fn (a Vec) - (b Vec) Vec {
|
||||
return Vec{a.x - b.x, a.y - b.y}
|
||||
}
|
||||
|
||||
fn (a Vec) *(b Vec) Vec {
|
||||
fn (a Vec) * (b Vec) Vec {
|
||||
return Vec{a.x * b.x, a.y * b.y}
|
||||
}
|
||||
|
||||
fn (a Vec) /(b Vec) Vec {
|
||||
fn (a Vec) / (b Vec) Vec {
|
||||
return Vec{a.x / b.x, a.y / b.y}
|
||||
}
|
||||
|
||||
fn (a Vec) %(b Vec) Vec {
|
||||
fn (a Vec) % (b Vec) Vec {
|
||||
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 {
|
||||
return a.x < b.x && a.y < b.y
|
||||
}
|
||||
|
||||
fn test_operator_overloading_with_string_interpolation() {
|
||||
a := Vec{2, 3}
|
||||
b := Vec{4, 5}
|
||||
|
||||
c := a + b
|
||||
assert a.x + b.x == c.x
|
||||
assert a.y + b.y == c.y
|
||||
|
||||
////// /////
|
||||
d := a - b
|
||||
assert a.x - b.x == d.x
|
||||
assert a.y - b.y == d.y
|
||||
|
||||
////// /////
|
||||
e := a * b
|
||||
assert a.x * b.x == e.x
|
||||
assert a.y * b.y == e.y
|
||||
|
||||
////// /////
|
||||
f := a / b
|
||||
assert a.x / b.x == f.x
|
||||
assert a.y / b.y == f.y
|
||||
|
||||
////// /////
|
||||
g := a % b
|
||||
assert a.x % b.x == g.x
|
||||
assert a.y % b.y == g.y
|
||||
|
||||
////// /////
|
||||
assert b > a == true
|
||||
assert a < b == true
|
||||
////// /////
|
||||
assert c.str() == '{6, 8}'
|
||||
assert d.str() == '{-2, -2}'
|
||||
assert e.str() == '{8, 15}'
|
||||
|
@ -285,6 +285,8 @@ pub fn replace_op(s string) string {
|
||||
`*` { '_mult' }
|
||||
`/` { '_div' }
|
||||
`%` { '_mod' }
|
||||
`<` { '_lt' }
|
||||
`>` { '_gt' }
|
||||
else { '' }
|
||||
}
|
||||
return s[..s.len - 1] + suffix
|
||||
|
Loading…
Reference in New Issue
Block a user