mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: check undefined operation of the generic infix expr (#15987)
This commit is contained in:
parent
4eeb45b94e
commit
272b3cf8c3
@ -164,19 +164,24 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
}
|
}
|
||||||
.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe {
|
.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe {
|
||||||
// binary operators that expect matching types
|
// binary operators that expect matching types
|
||||||
|
unwrapped_left_type := c.unwrap_generic(left_type)
|
||||||
|
left_sym = c.table.sym(unwrapped_left_type)
|
||||||
|
unwrapped_right_type := c.unwrap_generic(right_type)
|
||||||
|
right_sym = c.table.sym(unwrapped_right_type)
|
||||||
if right_sym.info is ast.Alias && (right_sym.info as ast.Alias).language != .c
|
if right_sym.info is ast.Alias && (right_sym.info as ast.Alias).language != .c
|
||||||
&& c.mod == c.table.type_to_str(right_type).split('.')[0]
|
&& c.mod == c.table.type_to_str(unwrapped_right_type).split('.')[0]
|
||||||
&& c.table.sym((right_sym.info as ast.Alias).parent_type).is_primitive() {
|
&& c.table.sym((right_sym.info as ast.Alias).parent_type).is_primitive() {
|
||||||
right_sym = c.table.sym((right_sym.info as ast.Alias).parent_type)
|
right_sym = c.table.sym((right_sym.info as ast.Alias).parent_type)
|
||||||
}
|
}
|
||||||
if left_sym.info is ast.Alias && (left_sym.info as ast.Alias).language != .c
|
if left_sym.info is ast.Alias && (left_sym.info as ast.Alias).language != .c
|
||||||
&& c.mod == c.table.type_to_str(left_type).split('.')[0]
|
&& c.mod == c.table.type_to_str(unwrapped_left_type).split('.')[0]
|
||||||
&& c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive() {
|
&& c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive() {
|
||||||
left_sym = c.table.sym((left_sym.info as ast.Alias).parent_type)
|
left_sym = c.table.sym((left_sym.info as ast.Alias).parent_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.pref.translated && node.op in [.plus, .minus, .mul]
|
if c.pref.translated && node.op in [.plus, .minus, .mul]
|
||||||
&& left_type.is_any_kind_of_pointer() && right_type.is_any_kind_of_pointer() {
|
&& unwrapped_left_type.is_any_kind_of_pointer()
|
||||||
|
&& unwrapped_right_type.is_any_kind_of_pointer() {
|
||||||
return_type = left_type
|
return_type = left_type
|
||||||
} else if !c.pref.translated && left_sym.kind == .alias && left_sym.info is ast.Alias
|
} else if !c.pref.translated && left_sym.kind == .alias && left_sym.info is ast.Alias
|
||||||
&& !(c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive()) {
|
&& !(c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive()) {
|
||||||
@ -193,8 +198,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
return_type = left_type
|
return_type = left_type
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
left_name := c.table.type_to_str(left_type)
|
left_name := c.table.type_to_str(unwrapped_left_type)
|
||||||
right_name := c.table.type_to_str(right_type)
|
right_name := c.table.type_to_str(unwrapped_right_type)
|
||||||
if left_name == right_name {
|
if left_name == right_name {
|
||||||
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
||||||
left_right_pos)
|
left_right_pos)
|
||||||
@ -217,8 +222,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
return_type = right_type
|
return_type = right_type
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
left_name := c.table.type_to_str(left_type)
|
left_name := c.table.type_to_str(unwrapped_left_type)
|
||||||
right_name := c.table.type_to_str(right_type)
|
right_name := c.table.type_to_str(unwrapped_right_type)
|
||||||
if left_name == right_name {
|
if left_name == right_name {
|
||||||
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
||||||
left_right_pos)
|
left_right_pos)
|
||||||
@ -236,8 +241,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
return_type = left_type
|
return_type = left_type
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
left_name := c.table.type_to_str(left_type)
|
left_name := c.table.type_to_str(unwrapped_left_type)
|
||||||
right_name := c.table.type_to_str(right_type)
|
right_name := c.table.type_to_str(unwrapped_right_type)
|
||||||
if left_name == right_name {
|
if left_name == right_name {
|
||||||
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
||||||
left_right_pos)
|
left_right_pos)
|
||||||
@ -253,8 +258,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
return_type = right_type
|
return_type = right_type
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
left_name := c.table.type_to_str(left_type)
|
left_name := c.table.type_to_str(unwrapped_left_type)
|
||||||
right_name := c.table.type_to_str(right_type)
|
right_name := c.table.type_to_str(unwrapped_right_type)
|
||||||
if left_name == right_name {
|
if left_name == right_name {
|
||||||
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
c.error('undefined operation `$left_name` $node.op.str() `$right_name`',
|
||||||
left_right_pos)
|
left_right_pos)
|
||||||
@ -264,14 +269,14 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
}
|
}
|
||||||
} else if node.left.is_auto_deref_var() || node.right.is_auto_deref_var() {
|
} else if node.left.is_auto_deref_var() || node.right.is_auto_deref_var() {
|
||||||
deref_left_type := if node.left.is_auto_deref_var() {
|
deref_left_type := if node.left.is_auto_deref_var() {
|
||||||
left_type.deref()
|
unwrapped_left_type.deref()
|
||||||
} else {
|
} else {
|
||||||
left_type
|
unwrapped_left_type
|
||||||
}
|
}
|
||||||
deref_right_type := if node.right.is_auto_deref_var() {
|
deref_right_type := if node.right.is_auto_deref_var() {
|
||||||
right_type.deref()
|
unwrapped_right_type.deref()
|
||||||
} else {
|
} else {
|
||||||
right_type
|
unwrapped_right_type
|
||||||
}
|
}
|
||||||
left_name := c.table.type_to_str(ast.mktyp(deref_left_type))
|
left_name := c.table.type_to_str(ast.mktyp(deref_left_type))
|
||||||
right_name := c.table.type_to_str(ast.mktyp(deref_right_type))
|
right_name := c.table.type_to_str(ast.mktyp(deref_right_type))
|
||||||
@ -279,8 +284,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unaliased_left_type := c.table.unalias_num_type(left_type)
|
unaliased_left_type := c.table.unalias_num_type(unwrapped_left_type)
|
||||||
unalias_right_type := c.table.unalias_num_type(right_type)
|
unalias_right_type := c.table.unalias_num_type(unwrapped_right_type)
|
||||||
mut promoted_type := c.promote_keeping_aliases(unaliased_left_type, unalias_right_type,
|
mut promoted_type := c.promote_keeping_aliases(unaliased_left_type, unalias_right_type,
|
||||||
left_sym.kind, right_sym.kind)
|
left_sym.kind, right_sym.kind)
|
||||||
// substract pointers is allowed in unsafe block
|
// substract pointers is allowed in unsafe block
|
||||||
@ -290,17 +295,21 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
promoted_type = ast.int_type
|
promoted_type = ast.int_type
|
||||||
}
|
}
|
||||||
if promoted_type.idx() == ast.void_type_idx {
|
if promoted_type.idx() == ast.void_type_idx {
|
||||||
left_name := c.table.type_to_str(left_type)
|
left_name := c.table.type_to_str(unwrapped_left_type)
|
||||||
right_name := c.table.type_to_str(right_type)
|
right_name := c.table.type_to_str(unwrapped_right_type)
|
||||||
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
||||||
} else if promoted_type.has_flag(.optional) {
|
} else if promoted_type.has_flag(.optional) {
|
||||||
s := c.table.type_to_str(promoted_type)
|
s := c.table.type_to_str(promoted_type)
|
||||||
c.error('`$node.op` cannot be used with `$s`', node.pos)
|
c.error('`$node.op` cannot be used with `$s`', node.pos)
|
||||||
} else if promoted_type.is_float() {
|
} else if promoted_type.is_float() {
|
||||||
if node.op in [.mod, .xor, .amp, .pipe] {
|
if node.op in [.mod, .xor, .amp, .pipe] {
|
||||||
side := if left_type == promoted_type { 'left' } else { 'right' }
|
side := if unwrapped_left_type == promoted_type { 'left' } else { 'right' }
|
||||||
pos := if left_type == promoted_type { left_pos } else { right_pos }
|
pos := if unwrapped_left_type == promoted_type {
|
||||||
name := if left_type == promoted_type {
|
left_pos
|
||||||
|
} else {
|
||||||
|
right_pos
|
||||||
|
}
|
||||||
|
name := if unwrapped_left_type == promoted_type {
|
||||||
left_sym.name
|
left_sym.name
|
||||||
} else {
|
} else {
|
||||||
right_sym.name
|
right_sym.name
|
||||||
|
6
vlib/v/checker/tests/generic_infix_plus_err.out
Normal file
6
vlib/v/checker/tests/generic_infix_plus_err.out
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
vlib/v/checker/tests/generic_infix_plus_err.vv:2:9: error: undefined operation `map[string]int` + `map[string]int`
|
||||||
|
1 | fn sum<T>(a T, b T) T {
|
||||||
|
2 | return a + b
|
||||||
|
| ~~~~~
|
||||||
|
3 | }
|
||||||
|
4 |
|
11
vlib/v/checker/tests/generic_infix_plus_err.vv
Normal file
11
vlib/v/checker/tests/generic_infix_plus_err.vv
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fn sum<T>(a T, b T) T {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
sum({
|
||||||
|
'id': 1
|
||||||
|
}, {
|
||||||
|
'id': 1
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user