diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 9c5c7f5673..339ba607d9 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) } diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_a.out b/vlib/v/checker/tests/inout/assign_expr_type_err_a.out new file mode 100644 index 0000000000..81bfe8f1b4 --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_a.out @@ -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| } diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_a.vv b/vlib/v/checker/tests/inout/assign_expr_type_err_a.vv new file mode 100644 index 0000000000..969ea5268e --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_a.vv @@ -0,0 +1,4 @@ +fn main() { + mut a := 10 + a <<= 0.5 +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_b.out b/vlib/v/checker/tests/inout/assign_expr_type_err_b.out new file mode 100644 index 0000000000..532cebf21b --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_b.out @@ -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| } diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_b.vv b/vlib/v/checker/tests/inout/assign_expr_type_err_b.vv new file mode 100644 index 0000000000..382939285a --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_b.vv @@ -0,0 +1,4 @@ +fn main() { + mut a := true + a *= false +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_c.out b/vlib/v/checker/tests/inout/assign_expr_type_err_c.out new file mode 100644 index 0000000000..6cb3ab2dc4 --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_c.out @@ -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| } diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_c.vv b/vlib/v/checker/tests/inout/assign_expr_type_err_c.vv new file mode 100644 index 0000000000..651e60339d --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_c.vv @@ -0,0 +1,4 @@ +fn main() { + mut a := 'hello' + a -= 'world' +} \ No newline at end of file diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_d.out b/vlib/v/checker/tests/inout/assign_expr_type_err_d.out new file mode 100644 index 0000000000..e1dacee6d0 --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_d.out @@ -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| } diff --git a/vlib/v/checker/tests/inout/assign_expr_type_err_d.vv b/vlib/v/checker/tests/inout/assign_expr_type_err_d.vv new file mode 100644 index 0000000000..237d5d83b6 --- /dev/null +++ b/vlib/v/checker/tests/inout/assign_expr_type_err_d.vv @@ -0,0 +1,6 @@ +struct Foo { } + +fn main() { + mut a := Foo{ } + a += Foo{ } +} \ No newline at end of file