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 {
|
||||
c.error('operator methods should have exactly 1 argument', node.pos)
|
||||
} else {
|
||||
receiver_sym := c.table.sym(node.receiver.typ)
|
||||
param_sym := c.table.sym(node.params[1].typ)
|
||||
receiver_type := node.receiver.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 {
|
||||
// bypass check for strings
|
||||
// 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() {
|
||||
c.error('cannot define operator methods on type alias for `${parent_sym.name}`',
|
||||
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
|
||||
2 | type Foo2 = string
|
||||
3 |
|
||||
3 |
|
||||
4 | fn (f Foo) + (f1 Foo2) Foo2 {
|
||||
| ~~~~
|
||||
5 | return Foo2(f + f1)
|
||||
6 | }
|
||||
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 {
|
||||
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 |
|
||||
vlib/v/checker/tests/method_op_alias_err.vv:8:1: error: cannot define operator methods on type alias for `string`
|
||||
6 | }
|
||||
7 |
|
||||
7 |
|
||||
8 | fn (f Foo) * (f1 Foo) Foo {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
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'
|
||||
15 | f *= Foo2('2')
|
||||
| ~~~~~~~~~
|
||||
16 | f -= Foo('fo')
|
||||
16 | f -= Foo('fo')
|
||||
17 | println(f)
|
||||
vlib/v/checker/tests/method_op_alias_err.vv:16:6: error: cannot use operator methods on type alias for `string`
|
||||
14 | f += 'fg'
|
||||
15 | f *= Foo2('2')
|
||||
16 | f -= Foo('fo')
|
||||
16 | f -= Foo('fo')
|
||||
| ~~
|
||||
17 | println(f)
|
||||
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) {
|
||||
left := g.unwrap(node.left_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('==')
|
||||
if g.pref.translated && !g.is_builtin_mod {
|
||||
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('*'.repeat(left.typ.nr_muls()))
|
||||
if eq_operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
g.write('*'.repeat(right.typ.nr_muls()))
|
||||
if eq_operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} 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) {
|
||||
left := g.unwrap(node.left_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 {
|
||||
g.gen_plain_infix_expr(node)
|
||||
return
|
||||
@ -310,17 +329,29 @@ fn (mut g Gen) infix_expr_cmp_op(node ast.InfixExpr) {
|
||||
if node.op in [.lt, .ge] {
|
||||
g.write('(')
|
||||
g.write('*'.repeat(left.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
g.write('*'.repeat(right.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write('(')
|
||||
g.write('*'.repeat(right.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.write(', ')
|
||||
g.write('*'.repeat(left.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(')')
|
||||
}
|
||||
@ -333,17 +364,29 @@ fn (mut g Gen) infix_expr_cmp_op(node ast.InfixExpr) {
|
||||
if node.op in [.lt, .ge] {
|
||||
g.write('(')
|
||||
g.write('*'.repeat(left.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
g.write('*'.repeat(right.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else {
|
||||
g.write('(')
|
||||
g.write('*'.repeat(right.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.write(', ')
|
||||
g.write('*'.repeat(left.typ.nr_muls()))
|
||||
if operator_expects_ptr {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.left)
|
||||
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