From 2984751a57f0ea44051e6cf2d9a98fa6b15a3a1a Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 16 Nov 2021 23:19:02 +0800 Subject: [PATCH] checker: fix the argument mismatch of fn call (#12479) --- vlib/encoding/utf8/utf8_tables.v | 2 +- vlib/v/checker/check_types.v | 12 ++++++++---- vlib/v/checker/checker.v | 12 +++++++----- vlib/v/checker/tests/fn_call_arg_mismatch.out | 7 +++++++ vlib/v/checker/tests/fn_call_arg_mismatch.vv | 9 +++++++++ 5 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 vlib/v/checker/tests/fn_call_arg_mismatch.out create mode 100644 vlib/v/checker/tests/fn_call_arg_mismatch.vv diff --git a/vlib/encoding/utf8/utf8_tables.v b/vlib/encoding/utf8/utf8_tables.v index be62316e55..837a1ed8cb 100644 --- a/vlib/encoding/utf8/utf8_tables.v +++ b/vlib/encoding/utf8/utf8_tables.v @@ -1161,7 +1161,7 @@ fn is_excluding_latin(table &RangeTable, r rune) bool { } r32 := &table.r32 if r32.len > 0 && r >= rune((*r32)[0].lo) { - return is_32(r32, u32(r)) + return is_32(*r32, u32(r)) } return false } diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 05da72a032..73fc99e87e 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -6,7 +6,7 @@ module checker import v.ast import v.token -pub fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, language ast.Language) ? { +pub fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, language ast.Language, arg ast.CallArg) ? { mut expected := expected_ // variadic if expected.has_flag(.variadic) { @@ -34,9 +34,6 @@ pub fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, return } } - if c.check_types(got, expected) { - return - } idx_got := got.idx() idx_expected := expected.idx() if idx_got in [ast.byteptr_type_idx, ast.charptr_type_idx] @@ -72,6 +69,13 @@ pub fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, return } } + if c.check_types(got, expected) { + if language != .v || expected.is_ptr() == got.is_ptr() || arg.is_mut + || arg.expr.is_auto_deref_var() || got.has_flag(.shared_f) + || c.table.get_type_symbol(expected_).kind !in [.array, .map] { + return + } + } return error('cannot use `${c.table.type_to_str(got.clear_flag(.variadic))}` as `${c.table.type_to_str(expected.clear_flag(.variadic))}`') } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 747a157b7c..f2826069fe 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2185,7 +2185,8 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { if exp_arg_typ.has_flag(.generic) { continue } - c.check_expected_call_arg(got_arg_typ, c.unwrap_generic(exp_arg_typ), node.language) or { + c.check_expected_call_arg(got_arg_typ, c.unwrap_generic(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 @@ -2326,7 +2327,8 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { if i < info.func.params.len { exp_arg_typ := info.func.params[i].typ - c.check_expected_call_arg(targ, c.unwrap_generic(exp_arg_typ), node.language) or { + c.check_expected_call_arg(targ, c.unwrap_generic(exp_arg_typ), node.language, + arg) or { if targ != ast.void_type { c.error('$err.msg in argument ${i + 1} to `${left_sym.name}.$method_name`', arg.pos) @@ -2372,7 +2374,7 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type ast. } info := left_sym.info as ast.Map arg_type := c.expr(node.args[0].expr) - c.check_expected_call_arg(arg_type, info.key_type, node.language) or { + c.check_expected_call_arg(arg_type, info.key_type, node.language, node.args[0]) or { c.error('$err.msg in argument 1 to `Map.delete`', node.args[0].pos) } } @@ -2866,7 +2868,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) } continue } - c.check_expected_call_arg(typ, c.unwrap_generic(param.typ), node.language) or { + c.check_expected_call_arg(typ, c.unwrap_generic(param.typ), node.language, call_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 @@ -2942,7 +2944,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) } continue } - c.check_expected_call_arg(utyp, unwrap_typ, node.language) or { + c.check_expected_call_arg(utyp, unwrap_typ, node.language, call_arg) or { c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos) } } diff --git a/vlib/v/checker/tests/fn_call_arg_mismatch.out b/vlib/v/checker/tests/fn_call_arg_mismatch.out new file mode 100644 index 0000000000..eade10ddfe --- /dev/null +++ b/vlib/v/checker/tests/fn_call_arg_mismatch.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/fn_call_arg_mismatch.vv:7:9: error: cannot use `&[]int` as `[]int` in argument 1 to `abc` + 5 | fn main() { + 6 | a := [1, 2, 3] + 7 | go abc(&a) + | ~~ + 8 | println('done') + 9 | } diff --git a/vlib/v/checker/tests/fn_call_arg_mismatch.vv b/vlib/v/checker/tests/fn_call_arg_mismatch.vv new file mode 100644 index 0000000000..356722f0e8 --- /dev/null +++ b/vlib/v/checker/tests/fn_call_arg_mismatch.vv @@ -0,0 +1,9 @@ +fn abc(x []int) { + println(x) +} + +fn main() { + a := [1, 2, 3] + go abc(&a) + println('done') +}