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
|
||||
}
|
||||
.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe { // binary operators that expect matching types
|
||||
if right.info is table.Alias
|
||||
&& (right.info as table.Alias).language != .c && c.mod == c.table.type_to_str(right_type).split('.')[0] {
|
||||
if right.info is table.Alias && (right.info as table.Alias).language != .c
|
||||
&& 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)
|
||||
}
|
||||
if left.info is table.Alias
|
||||
&& (left.info as table.Alias).language != .c && c.mod == c.table.type_to_str(left_type).split('.')[0] {
|
||||
if left.info is table.Alias && (left.info as table.Alias).language != .c
|
||||
&& 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)
|
||||
}
|
||||
// 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.has_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]
|
||||
if node.op in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && ((a && b && e) || c || d) {
|
||||
// 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.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