checker: add type check for arithmetic assignment ops
parent
3b00132e14
commit
6c59b306c7
|
@ -327,6 +327,8 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
|
|||
// println('setting exp type to $c.expected_type $t.name')
|
||||
right_type := c.expr(assign_expr.val)
|
||||
assign_expr.right_type = right_type
|
||||
right := c.table.get_type_symbol(right_type)
|
||||
left := c.table.get_type_symbol(left_type)
|
||||
if ast.expr_is_blank_ident(assign_expr.left) {
|
||||
return
|
||||
}
|
||||
|
@ -347,6 +349,37 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
|
|||
c.error('cannot assign `$right_type_sym.name` to variable `${assign_expr.left.str()}` of type `$left_type_sym.name`',
|
||||
assign_expr.val.position())
|
||||
}
|
||||
else if assign_expr.op == .plus_assign {
|
||||
no_str_related_err := left_type == table.string_type && right_type == table.string_type
|
||||
no_ptr_related_err := (left.is_pointer() || left.is_int()) && (right.is_pointer() || right.is_int())
|
||||
no_num_related_err := left.is_number() && right.is_number()
|
||||
if !no_str_related_err && !no_ptr_related_err && !no_num_related_err {
|
||||
c.error('operator += not defined on left type `$left.name` and right type `$right.name`', assign_expr.pos)
|
||||
}
|
||||
}
|
||||
else if assign_expr.op == .minus_assign {
|
||||
no_ptr_related_err := (left.is_pointer() || left.is_int()) && (right.is_pointer() || right.is_int())
|
||||
no_num_related_err := left.is_number() && right.is_number()
|
||||
if !no_ptr_related_err && !no_num_related_err {
|
||||
c.error('operator -= not defined on left type `$left.name` and right type `$right.name`', assign_expr.pos)
|
||||
}
|
||||
}
|
||||
else if assign_expr.op in [.mult_assign, .div_assign] {
|
||||
if !left.is_number() {
|
||||
c.error('operator ${assign_expr.op.str()} not defined on left type `$left.name`', assign_expr.pos)
|
||||
}
|
||||
else if !right.is_number() {
|
||||
c.error('operator ${assign_expr.op.str()} not defined on right type `$right.name`', assign_expr.pos)
|
||||
}
|
||||
}
|
||||
else if assign_expr.op in [.and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, .right_shift_assign] {
|
||||
if !left.is_int() {
|
||||
c.error('operator ${assign_expr.op.str()} not defined on left type `$left.name`', assign_expr.pos)
|
||||
}
|
||||
else if !right.is_int() {
|
||||
c.error('operator ${assign_expr.op.str()} not defined on right type `$right.name`', assign_expr.pos)
|
||||
}
|
||||
}
|
||||
c.check_expr_opt_call(assign_expr.val, right_type, true)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/inout/assign_expr_type_err_a.v:3:8: error: operator <<= not defined on right type `f64`
|
||||
1| fn main() {
|
||||
2| mut a := 10
|
||||
3| a <<= 0.5
|
||||
~~~
|
||||
4| }
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
mut a := 10
|
||||
a <<= 0.5
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/inout/assign_expr_type_err_b.v:3:7: error: operator *= not defined on left type `bool`
|
||||
1| fn main() {
|
||||
2| mut a := true
|
||||
3| a *= false
|
||||
~~~~~
|
||||
4| }
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
mut a := true
|
||||
a *= false
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/inout/assign_expr_type_err_c.v:3:7: error: operator -= not defined on left type `string` and right type `string`
|
||||
1| fn main() {
|
||||
2| mut a := 'hello'
|
||||
3| a -= 'world'
|
||||
~~~~~~~
|
||||
4| }
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
mut a := 'hello'
|
||||
a -= 'world'
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/inout/assign_expr_type_err_d.v:5:7: error: operator += not defined on left type `Foo` and right type `Foo`
|
||||
3| fn main() {
|
||||
4| mut a := Foo{ }
|
||||
5| a += Foo{ }
|
||||
~~~
|
||||
6| }
|
|
@ -0,0 +1,6 @@
|
|||
struct Foo { }
|
||||
|
||||
fn main() {
|
||||
mut a := Foo{ }
|
||||
a += Foo{ }
|
||||
}
|
Loading…
Reference in New Issue