mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix cgen errors for overloaded operators using reference types for the receiver and operand (fix #16725) (fix #15859) (#16726)
This commit is contained in:
parent
d19c1ef087
commit
1cde55478d
@ -278,8 +278,12 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||||||
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 {
|
||||||
receiver_sym := c.table.sym(node.receiver.typ)
|
receiver_type := node.receiver.typ
|
||||||
param_sym := c.table.sym(node.params[1].typ)
|
receiver_sym := c.table.sym(receiver_type)
|
||||||
|
|
||||||
|
param_type := node.params[1].typ
|
||||||
|
param_sym := c.table.sym(param_type)
|
||||||
|
|
||||||
if param_sym.kind == .string && receiver_sym.kind == .string {
|
if param_sym.kind == .string && receiver_sym.kind == .string {
|
||||||
// bypass check for strings
|
// bypass check for strings
|
||||||
// TODO there must be a better way to handle that
|
// TODO there must be a better way to handle that
|
||||||
@ -302,6 +306,11 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||||||
} 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}`',
|
||||||
node.pos)
|
node.pos)
|
||||||
|
} else if receiver_type != param_type {
|
||||||
|
srtype := c.table.type_to_str(receiver_type)
|
||||||
|
sptype := c.table.type_to_str(param_type)
|
||||||
|
c.error('the receiver type `${srtype}` should be the same type as the operand `${sptype}`',
|
||||||
|
node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
vlib/v/checker/tests/method_op_alias_err.vv:4:18: error: expected `Foo` not `Foo2` - both operands must be the same type for operator overloading
|
vlib/v/checker/tests/method_op_alias_err.vv:4:18: error: expected `Foo` not `Foo2` - both operands must be the same type for operator overloading
|
||||||
2 | type Foo2 = string
|
2 | type Foo2 = string
|
||||||
3 |
|
3 |
|
||||||
4 | fn (f Foo) + (f1 Foo2) Foo2 {
|
4 | fn (f Foo) + (f1 Foo2) Foo2 {
|
||||||
| ~~~~
|
| ~~~~
|
||||||
5 | return Foo2(f + f1)
|
5 | return Foo2(f + f1)
|
||||||
6 | }
|
6 | }
|
||||||
vlib/v/checker/tests/method_op_alias_err.vv:5:17: error: infix expr: cannot use `string` (right expression) as `string`
|
vlib/v/checker/tests/method_op_alias_err.vv:5:17: error: infix expr: cannot use `string` (right expression) as `string`
|
||||||
3 |
|
3 |
|
||||||
4 | fn (f Foo) + (f1 Foo2) Foo2 {
|
4 | fn (f Foo) + (f1 Foo2) Foo2 {
|
||||||
5 | return Foo2(f + f1)
|
5 | return Foo2(f + f1)
|
||||||
| ~~~~~~
|
| ~~~~~~
|
||||||
@ -14,7 +14,7 @@ vlib/v/checker/tests/method_op_alias_err.vv:5:17: error: infix expr: cannot use
|
|||||||
7 |
|
7 |
|
||||||
vlib/v/checker/tests/method_op_alias_err.vv:8:1: error: cannot define operator methods on type alias for `string`
|
vlib/v/checker/tests/method_op_alias_err.vv:8:1: error: cannot define operator methods on type alias for `string`
|
||||||
6 | }
|
6 | }
|
||||||
7 |
|
7 |
|
||||||
8 | fn (f Foo) * (f1 Foo) Foo {
|
8 | fn (f Foo) * (f1 Foo) Foo {
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
9 | return Foo(f + f1)
|
9 | return Foo(f + f1)
|
||||||
@ -31,12 +31,12 @@ vlib/v/checker/tests/method_op_alias_err.vv:15:9: error: cannot assign to `f`: e
|
|||||||
14 | f += 'fg'
|
14 | f += 'fg'
|
||||||
15 | f *= Foo2('2')
|
15 | f *= Foo2('2')
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~
|
||||||
16 | f -= Foo('fo')
|
16 | f -= Foo('fo')
|
||||||
17 | println(f)
|
17 | println(f)
|
||||||
vlib/v/checker/tests/method_op_alias_err.vv:16:6: error: cannot use operator methods on type alias for `string`
|
vlib/v/checker/tests/method_op_alias_err.vv:16:6: error: cannot use operator methods on type alias for `string`
|
||||||
14 | f += 'fg'
|
14 | f += 'fg'
|
||||||
15 | f *= Foo2('2')
|
15 | f *= Foo2('2')
|
||||||
16 | f -= Foo('fo')
|
16 | f -= Foo('fo')
|
||||||
| ~~
|
| ~~
|
||||||
17 | println(f)
|
17 | println(f)
|
||||||
18 | }
|
18 | }
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
vlib/v/checker/tests/overload_operator_difference_in_operand_types.vv:9:1: error: the receiver type `Resources` should be the same type as the operand `&Resources`
|
||||||
|
7 | }
|
||||||
|
8 |
|
||||||
|
9 | fn (a Resources) < (b &Resources) bool {
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
10 | return a.hru < b.hru && a.sru < b.sru && a.cru < b.cru && a.mru < b.mru
|
||||||
|
11 | }
|
||||||
|
vlib/v/checker/tests/overload_operator_difference_in_operand_types.vv:13:1: error: the receiver type `&Resources` should be the same type as the operand `Resources`
|
||||||
|
11 | }
|
||||||
|
12 |
|
||||||
|
13 | fn (a &Resources) == (b Resources) bool {
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
14 | return a.hru == b.hru
|
||||||
|
15 | }
|
@ -0,0 +1,26 @@
|
|||||||
|
struct Resources {
|
||||||
|
mut:
|
||||||
|
hru u64
|
||||||
|
sru u64
|
||||||
|
cru u64
|
||||||
|
mru u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a Resources) < (b &Resources) bool {
|
||||||
|
return a.hru < b.hru && a.sru < b.sru && a.cru < b.cru && a.mru < b.mru
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a &Resources) == (b Resources) bool {
|
||||||
|
return a.hru == b.hru
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_struct_with_reference_operands_for_the_overloaded_operators_do_work() {
|
||||||
|
aa := Resources{}
|
||||||
|
bb := Resources{}
|
||||||
|
assert dump(aa < bb) == false
|
||||||
|
assert dump(aa == bb) == true
|
||||||
|
assert dump(aa != bb) == false
|
||||||
|
assert dump(aa > bb) == false
|
||||||
|
assert dump(aa <= bb) == true
|
||||||
|
assert dump(aa >= bb) == true
|
||||||
|
}
|
@ -85,7 +85,13 @@ fn (mut g Gen) infix_expr_arrow_op(node ast.InfixExpr) {
|
|||||||
fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
||||||
left := g.unwrap(node.left_type)
|
left := g.unwrap(node.left_type)
|
||||||
right := g.unwrap(node.right_type)
|
right := g.unwrap(node.right_type)
|
||||||
has_defined_eq_operator := g.table.has_method(left.sym, '==')
|
mut has_defined_eq_operator := false
|
||||||
|
mut eq_operator_expects_ptr := false
|
||||||
|
if m := g.table.find_method(left.sym, '==') {
|
||||||
|
has_defined_eq_operator = true
|
||||||
|
eq_operator_expects_ptr = m.receiver_type.is_ptr()
|
||||||
|
}
|
||||||
|
// TODO: investigate why the following is needed for vlib/v/tests/string_alias_test.v and vlib/v/tests/anon_fn_with_alias_args_test.v
|
||||||
has_alias_eq_op_overload := left.sym.info is ast.Alias && left.sym.has_method('==')
|
has_alias_eq_op_overload := left.sym.info is ast.Alias && left.sym.has_method('==')
|
||||||
if g.pref.translated && !g.is_builtin_mod {
|
if g.pref.translated && !g.is_builtin_mod {
|
||||||
g.gen_plain_infix_expr(node)
|
g.gen_plain_infix_expr(node)
|
||||||
@ -113,9 +119,15 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
}
|
}
|
||||||
g.write('__eq(')
|
g.write('__eq(')
|
||||||
g.write('*'.repeat(left.typ.nr_muls()))
|
g.write('*'.repeat(left.typ.nr_muls()))
|
||||||
|
if eq_operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.write('*'.repeat(right.typ.nr_muls()))
|
g.write('*'.repeat(right.typ.nr_muls()))
|
||||||
|
if eq_operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
} else if left.typ.idx() == right.typ.idx()
|
} else if left.typ.idx() == right.typ.idx()
|
||||||
@ -294,7 +306,14 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
fn (mut g Gen) infix_expr_cmp_op(node ast.InfixExpr) {
|
fn (mut g Gen) infix_expr_cmp_op(node ast.InfixExpr) {
|
||||||
left := g.unwrap(node.left_type)
|
left := g.unwrap(node.left_type)
|
||||||
right := g.unwrap(node.right_type)
|
right := g.unwrap(node.right_type)
|
||||||
has_operator_overloading := g.table.has_method(left.sym, '<')
|
|
||||||
|
mut has_operator_overloading := false
|
||||||
|
mut operator_expects_ptr := false
|
||||||
|
if m := g.table.find_method(left.sym, '<') {
|
||||||
|
has_operator_overloading = true
|
||||||
|
operator_expects_ptr = m.receiver_type.is_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
if g.pref.translated && !g.is_builtin_mod {
|
if g.pref.translated && !g.is_builtin_mod {
|
||||||
g.gen_plain_infix_expr(node)
|
g.gen_plain_infix_expr(node)
|
||||||
return
|
return
|
||||||
@ -310,17 +329,29 @@ fn (mut g Gen) infix_expr_cmp_op(node ast.InfixExpr) {
|
|||||||
if node.op in [.lt, .ge] {
|
if node.op in [.lt, .ge] {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
g.write('*'.repeat(left.typ.nr_muls()))
|
g.write('*'.repeat(left.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.write('*'.repeat(right.typ.nr_muls()))
|
g.write('*'.repeat(right.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
} else {
|
} else {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
g.write('*'.repeat(right.typ.nr_muls()))
|
g.write('*'.repeat(right.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.write('*'.repeat(left.typ.nr_muls()))
|
g.write('*'.repeat(left.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
@ -333,17 +364,29 @@ fn (mut g Gen) infix_expr_cmp_op(node ast.InfixExpr) {
|
|||||||
if node.op in [.lt, .ge] {
|
if node.op in [.lt, .ge] {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
g.write('*'.repeat(left.typ.nr_muls()))
|
g.write('*'.repeat(left.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.write('*'.repeat(right.typ.nr_muls()))
|
g.write('*'.repeat(right.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
} else {
|
} else {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
g.write('*'.repeat(right.typ.nr_muls()))
|
g.write('*'.repeat(right.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.write('*'.repeat(left.typ.nr_muls()))
|
g.write('*'.repeat(left.typ.nr_muls()))
|
||||||
|
if operator_expects_ptr {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
struct Resources {
|
||||||
|
mut:
|
||||||
|
hru u64
|
||||||
|
sru u64
|
||||||
|
cru u64
|
||||||
|
mru u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a &Resources) < (b &Resources) bool {
|
||||||
|
return a.hru < b.hru && a.sru < b.sru && a.cru < b.cru && a.mru < b.mru
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a &Resources) == (b &Resources) bool {
|
||||||
|
return a.hru == b.hru
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_struct_with_reference_operands_for_the_overloaded_operators_do_work() {
|
||||||
|
aa := Resources{}
|
||||||
|
bb := Resources{}
|
||||||
|
assert dump(aa < bb) == false
|
||||||
|
assert dump(aa == bb) == true
|
||||||
|
assert dump(aa != bb) == false
|
||||||
|
assert dump(aa > bb) == false
|
||||||
|
assert dump(aa <= bb) == true
|
||||||
|
assert dump(aa >= bb) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue: https://github.com/vlang/v/issues/15859
|
||||||
|
struct Foo {
|
||||||
|
id u32
|
||||||
|
x u32
|
||||||
|
y u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f &Foo) == (o &Foo) bool {
|
||||||
|
return f.id == o.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_eq_operator_with_reference_operands() {
|
||||||
|
a := Foo{1, 4, 5}
|
||||||
|
b := Foo{1, 9, 10}
|
||||||
|
if a == b {
|
||||||
|
assert true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert false
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user