From f8b8950b96d78b78b8c7407b977649788919b20f Mon Sep 17 00:00:00 2001 From: yuyi Date: Wed, 16 Feb 2022 17:53:41 +0800 Subject: [PATCH] checker: check mut interface arguments (#13479) --- vlib/v/checker/fn.v | 48 +++++++++---------- .../checker/tests/mut_interface_param_err.out | 6 +++ .../checker/tests/mut_interface_param_err.vv | 20 ++++++++ 3 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 vlib/v/checker/tests/mut_interface_param_err.out create mode 100644 vlib/v/checker/tests/mut_interface_param_err.vv diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 72e7501b4b..14272734a8 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -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', diff --git a/vlib/v/checker/tests/mut_interface_param_err.out b/vlib/v/checker/tests/mut_interface_param_err.out new file mode 100644 index 0000000000..b2e62565f7 --- /dev/null +++ b/vlib/v/checker/tests/mut_interface_param_err.out @@ -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 | } diff --git a/vlib/v/checker/tests/mut_interface_param_err.vv b/vlib/v/checker/tests/mut_interface_param_err.vv new file mode 100644 index 0000000000..68bdfe8093 --- /dev/null +++ b/vlib/v/checker/tests/mut_interface_param_err.vv @@ -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 +}