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