checker: check mut interface arguments (#13479)
							parent
							
								
									5a14748e7c
								
							
						
					
					
						commit
						f8b8950b96
					
				| 
						 | 
				
			
			@ -1255,18 +1255,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
 | 
			
		|||
				final_arg_typ = exp_arg_sym.array_info().elem_type
 | 
			
		||||
				final_arg_sym = c.table.sym(final_arg_typ)
 | 
			
		||||
			}
 | 
			
		||||
			// Handle expected interface
 | 
			
		||||
			if final_arg_sym.kind == .interface_ {
 | 
			
		||||
				if c.type_implements(got_arg_typ, final_arg_typ, arg.expr.pos()) {
 | 
			
		||||
					if !got_arg_typ.is_ptr() && !got_arg_typ.is_pointer() && !c.inside_unsafe {
 | 
			
		||||
						got_arg_typ_sym := c.table.sym(got_arg_typ)
 | 
			
		||||
						if got_arg_typ_sym.kind != .interface_ {
 | 
			
		||||
							c.mark_as_referenced(mut &arg.expr, true)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if exp_arg_typ.has_flag(.generic) {
 | 
			
		||||
				if concrete_types.len == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
| 
						 | 
				
			
			@ -1290,18 +1278,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
 | 
			
		|||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			c.check_expected_call_arg(got_arg_typ, exp_arg_typ, node.language, arg) or {
 | 
			
		||||
				// str method, allow type with str method if fn arg is string
 | 
			
		||||
				// Passing an int or a string array produces a c error here
 | 
			
		||||
				// Deleting this condition results in propper V error messages
 | 
			
		||||
				// if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
 | 
			
		||||
				// continue
 | 
			
		||||
				// }
 | 
			
		||||
				if got_arg_typ != ast.void_type {
 | 
			
		||||
					c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
 | 
			
		||||
						arg.pos)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			param := if method.is_variadic && i >= method.params.len - 1 {
 | 
			
		||||
				method.params[method.params.len - 1]
 | 
			
		||||
			} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,6 +1313,30 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
 | 
			
		|||
					c.fail_if_unreadable(arg.expr, got_arg_typ, 'argument')
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			// Handle expected interface
 | 
			
		||||
			if final_arg_sym.kind == .interface_ {
 | 
			
		||||
				if c.type_implements(got_arg_typ, final_arg_typ, arg.expr.pos()) {
 | 
			
		||||
					if !got_arg_typ.is_ptr() && !got_arg_typ.is_pointer() && !c.inside_unsafe {
 | 
			
		||||
						got_arg_typ_sym := c.table.sym(got_arg_typ)
 | 
			
		||||
						if got_arg_typ_sym.kind != .interface_ {
 | 
			
		||||
							c.mark_as_referenced(mut &arg.expr, true)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			c.check_expected_call_arg(got_arg_typ, exp_arg_typ, node.language, arg) or {
 | 
			
		||||
				// str method, allow type with str method if fn arg is string
 | 
			
		||||
				// Passing an int or a string array produces a c error here
 | 
			
		||||
				// Deleting this condition results in propper V error messages
 | 
			
		||||
				// if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
 | 
			
		||||
				// continue
 | 
			
		||||
				// }
 | 
			
		||||
				if got_arg_typ != ast.void_type {
 | 
			
		||||
					c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
 | 
			
		||||
						arg.pos)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if method.is_unsafe && !c.inside_unsafe {
 | 
			
		||||
			c.warn('method `${left_sym.name}.$method_name` must be called from an `unsafe` block',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
vlib/v/checker/tests/mut_interface_param_err.vv:19:10: error: `add` parameter `widget` is `mut`, you need to provide `mut` e.g. `mut arg1`
 | 
			
		||||
   17 |     mut win := Window{}
 | 
			
		||||
   18 |     mut btn := Button{}
 | 
			
		||||
   19 |     win.add(btn)  // should be an error here
 | 
			
		||||
      |             ~~~
 | 
			
		||||
   20 | }
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
interface Widget{
 | 
			
		||||
mut:
 | 
			
		||||
	init()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Button{}
 | 
			
		||||
fn (mut b Button) init(){}
 | 
			
		||||
 | 
			
		||||
struct Window{
 | 
			
		||||
mut:
 | 
			
		||||
	widgets []Widget
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut w Window) add(mut widget Widget){}
 | 
			
		||||
 | 
			
		||||
fn main(){
 | 
			
		||||
	mut win := Window{}
 | 
			
		||||
	mut btn := Button{}
 | 
			
		||||
	win.add(btn)  // should be an error here
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue