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