checker: check mut interface arguments (#13479)

pull/13493/head
yuyi 2022-02-16 17:53:41 +08:00 committed by GitHub
parent 5a14748e7c
commit f8b8950b96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 24 deletions

View File

@ -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',

View File

@ -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 | }

View File

@ -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
}