cgen: fix operator overloading for array/map aliases (#9529)
parent
9b9ef5fe1b
commit
b40d06ec1e
|
@ -796,14 +796,54 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
return table.bool_type
|
return table.bool_type
|
||||||
}
|
}
|
||||||
.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe { // binary operators that expect matching types
|
.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe { // binary operators that expect matching types
|
||||||
if right.info is table.Alias
|
if right.info is table.Alias && (right.info as table.Alias).language != .c
|
||||||
&& (right.info as table.Alias).language != .c && c.mod == c.table.type_to_str(right_type).split('.')[0] {
|
&& c.mod == c.table.type_to_str(right_type).split('.')[0]
|
||||||
|
&& c.table.get_type_symbol((right.info as table.Alias).parent_type).is_primitive() {
|
||||||
right = c.table.get_type_symbol((right.info as table.Alias).parent_type)
|
right = c.table.get_type_symbol((right.info as table.Alias).parent_type)
|
||||||
}
|
}
|
||||||
if left.info is table.Alias
|
if left.info is table.Alias && (left.info as table.Alias).language != .c
|
||||||
&& (left.info as table.Alias).language != .c && c.mod == c.table.type_to_str(left_type).split('.')[0] {
|
&& c.mod == c.table.type_to_str(left_type).split('.')[0]
|
||||||
|
&& c.table.get_type_symbol((left.info as table.Alias).parent_type).is_primitive() {
|
||||||
left = c.table.get_type_symbol((left.info as table.Alias).parent_type)
|
left = c.table.get_type_symbol((left.info as table.Alias).parent_type)
|
||||||
}
|
}
|
||||||
|
// Check if the alias type is not a primitive then allow using operator overloading for aliased `arrays` and `maps`
|
||||||
|
if left.kind == .alias && left.info is table.Alias
|
||||||
|
&& !(c.table.get_type_symbol((left.info as table.Alias).parent_type).is_primitive()) {
|
||||||
|
if left.has_method(infix_expr.op.str()) {
|
||||||
|
if method := left.find_method(infix_expr.op.str()) {
|
||||||
|
return_type = method.return_type
|
||||||
|
} else {
|
||||||
|
return_type = left_type
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
left_name := c.table.type_to_str(left_type)
|
||||||
|
right_name := c.table.type_to_str(right_type)
|
||||||
|
if left_name == right_name {
|
||||||
|
c.error('undefined operation `$left_name` $infix_expr.op.str() `$right_name`',
|
||||||
|
left_right_pos)
|
||||||
|
} else {
|
||||||
|
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if right.kind == .alias && right.info is table.Alias
|
||||||
|
&& !(c.table.get_type_symbol((right.info as table.Alias).parent_type).is_primitive()) {
|
||||||
|
if right.has_method(infix_expr.op.str()) {
|
||||||
|
if method := right.find_method(infix_expr.op.str()) {
|
||||||
|
return_type = method.return_type
|
||||||
|
} else {
|
||||||
|
return_type = right_type
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
left_name := c.table.type_to_str(left_type)
|
||||||
|
right_name := c.table.type_to_str(right_type)
|
||||||
|
if left_name == right_name {
|
||||||
|
c.error('undefined operation `$left_name` $infix_expr.op.str() `$right_name`',
|
||||||
|
left_right_pos)
|
||||||
|
} else {
|
||||||
|
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if left.kind in [.array, .array_fixed, .map, .struct_] {
|
if left.kind in [.array, .array_fixed, .map, .struct_] {
|
||||||
if left.has_method(infix_expr.op.str()) {
|
if left.has_method(infix_expr.op.str()) {
|
||||||
if method := left.find_method(infix_expr.op.str()) {
|
if method := left.find_method(infix_expr.op.str()) {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
vlib/v/checker/tests/alias_array_unknown_op_overloading_err.vv:17:7: error: undefined operation `Tuple` - `Tuple`
|
||||||
|
15 | mut a := new_tuple(12, 4.5, 6.7, 6)
|
||||||
|
16 | b := new_tuple(12, 4.5, 6.7, 6)
|
||||||
|
17 | a -= b
|
||||||
|
| ~~
|
||||||
|
18 | println(a - b)
|
||||||
|
19 | }
|
||||||
|
vlib/v/checker/tests/alias_array_unknown_op_overloading_err.vv:18:13: error: undefined operation `Tuple` - `Tuple`
|
||||||
|
16 | b := new_tuple(12, 4.5, 6.7, 6)
|
||||||
|
17 | a -= b
|
||||||
|
18 | println(a - b)
|
||||||
|
| ~~~~~
|
||||||
|
19 | }
|
|
@ -0,0 +1,19 @@
|
||||||
|
type Tuple = []f64
|
||||||
|
|
||||||
|
fn new_tuple(x f64, y f64, z f64, w f64) Tuple {
|
||||||
|
return Tuple([x, y, z, w])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a Tuple) + (b Tuple) Tuple {
|
||||||
|
mut res := []f64{len: a.len}
|
||||||
|
for i := 0; i < a.len; i++ {
|
||||||
|
res[i] = a[i] + b[i]
|
||||||
|
}
|
||||||
|
return Tuple(res)
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
mut a := new_tuple(12, 4.5, 6.7, 6)
|
||||||
|
b := new_tuple(12, 4.5, 6.7, 6)
|
||||||
|
a -= b
|
||||||
|
println(a - b)
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
vlib/v/checker/tests/alias_map_unknown_op_overloading_err.vv:19:10: error: undefined operation `Map` - `Map`
|
||||||
|
17 | mut a := new_map()
|
||||||
|
18 | b := new_map()
|
||||||
|
19 | println(a - b)
|
||||||
|
| ~~~~~
|
||||||
|
20 | a -= b
|
||||||
|
21 | }
|
||||||
|
vlib/v/checker/tests/alias_map_unknown_op_overloading_err.vv:20:7: error: undefined operation `Map` - `Map`
|
||||||
|
18 | b := new_map()
|
||||||
|
19 | println(a - b)
|
||||||
|
20 | a -= b
|
||||||
|
| ~~
|
||||||
|
21 | }
|
|
@ -0,0 +1,21 @@
|
||||||
|
type Map = map[string]string
|
||||||
|
|
||||||
|
pub fn new_map() Map {
|
||||||
|
return Map(map{
|
||||||
|
'23': 'str'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a Map) + (b Map) Map {
|
||||||
|
str := b['23']
|
||||||
|
return Map(map{
|
||||||
|
'34': str + '12'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut a := new_map()
|
||||||
|
b := new_map()
|
||||||
|
println(a - b)
|
||||||
|
a -= b
|
||||||
|
}
|
|
@ -3703,7 +3703,12 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
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, .eq] && ((a && b && e) || c || d) {
|
if node.op in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && ((a && b && e) || c || d) {
|
||||||
// Overloaded operators
|
// Overloaded operators
|
||||||
the_left_type := if !d { left_type } else { (left_sym.info as table.Alias).parent_type }
|
the_left_type := if !d
|
||||||
|
|| g.table.get_type_symbol((left_sym.info as table.Alias).parent_type).kind in [.array, .array_fixed, .map] {
|
||||||
|
left_type
|
||||||
|
} else {
|
||||||
|
(left_sym.info as table.Alias).parent_type
|
||||||
|
}
|
||||||
g.write(g.typ(the_left_type))
|
g.write(g.typ(the_left_type))
|
||||||
g.write('_')
|
g.write('_')
|
||||||
g.write(util.replace_op(node.op.str()))
|
g.write(util.replace_op(node.op.str()))
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
type Tuple = []f64
|
||||||
|
|
||||||
|
fn new_tuple(x f64, y f64, z f64, w f64) Tuple {
|
||||||
|
return Tuple([x, y, z, w])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a Tuple) + (b Tuple) Tuple {
|
||||||
|
mut res := []f64{len: a.len}
|
||||||
|
for i := 0; i < a.len; i++ {
|
||||||
|
res[i] = a[i] + b[i]
|
||||||
|
}
|
||||||
|
return Tuple(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_tuple_arithmetic() {
|
||||||
|
a := new_tuple(3, -2, 5, 1)
|
||||||
|
b := new_tuple(-2, 3, 1, 0)
|
||||||
|
assert a + b == new_tuple(1, 1, 6, 1)
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
type Map = map[string]string
|
||||||
|
|
||||||
|
pub fn new_map() Map {
|
||||||
|
return Map(map{
|
||||||
|
'23': 'str'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (a Map) + (b Map) Map {
|
||||||
|
str := b['23']
|
||||||
|
return Map(map{
|
||||||
|
'34': str + '12'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_map_alias_op_overloading() {
|
||||||
|
a := new_map()
|
||||||
|
b := new_map()
|
||||||
|
assert a + b == Map(map{
|
||||||
|
'34': 'str12'
|
||||||
|
})
|
||||||
|
assert '${a + b}' == "Map({'34': 'str12'})"
|
||||||
|
}
|
Loading…
Reference in New Issue