From fc72044b42db341e64f1f43dc4c06e7c7ce31c44 Mon Sep 17 00:00:00 2001 From: Jose Mendoza <56417208+StunxFS@users.noreply.github.com> Date: Tue, 1 Oct 2024 03:45:03 -0400 Subject: [PATCH] checker: improve `fn` argument mismatch error (#22370) --- vlib/v/checker/fn.v | 24 ++++++++++-------- .../checker/tests/ambiguous_function_call.out | 5 ++-- vlib/v/checker/tests/c_fn_surplus_args.out | 25 ++++++++----------- vlib/v/checker/tests/error_fn_with_0_args.out | 5 ++-- .../fn_array_decompose_arg_mismatch_err_c.out | 5 ++-- .../tests/fn_call_with_extra_parenthesis.out | 5 ++-- .../function_count_of_args_mismatch_err.out | 20 ++++++--------- .../tests/generics_fn_arguments_count_err.out | 10 +++----- .../generics_struct_field_fn_args_err.out | 20 ++++++--------- vlib/v/checker/tests/multi_return_err.out | 15 +++++------ .../tests/no_interface_instantiation_b.out | 5 ++-- vlib/v/checker/tests/no_main_println_err.out | 5 ++-- 12 files changed, 62 insertions(+), 82 deletions(-) diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 1b9108d164..de4ffb7418 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1,5 +1,6 @@ module checker +import strings import v.ast import v.util import v.token @@ -2863,7 +2864,8 @@ struct HaveWantParams { } fn (mut c Checker) fn_call_error_have_want(p HaveWantParams) { - mut have_want := '\n\thave (' + mut sb := strings.new_builder(20) + sb.write_string('have (') // Fetch arg types, they are always 0 at this point // Duplicate logic, but we don't care, since this is an error, so no perf cost mut arg_types := []ast.Type{len: p.args.len} @@ -2876,30 +2878,32 @@ fn (mut c Checker) fn_call_error_have_want(p HaveWantParams) { if arg_types[i] == 0 { // arg.typ == 0 { // Arguments can have an unknown (invalid) type // This should never happen. - have_want += '?' + sb.write_string('?') } else { - have_want += c.table.type_to_str(arg_types[i]) // arg.typ) + sb.write_string(c.table.type_to_str(arg_types[i])) // arg.typ } if i < p.args.len - 1 { - have_want += ', ' + sb.write_string(', ') } } + sb.write_string(')') + c.add_error_detail(sb.str()) // Actual parameters we expect - have_want += ')\n\twant (' + sb.write_string(' want (') for i, param in p.params { if i == 0 && p.nr_params == p.params.len - 1 { // Skip receiver continue } - have_want += c.table.type_to_str(param.typ) + sb.write_string(c.table.type_to_str(param.typ)) if i < p.params.len - 1 { - have_want += ', ' + sb.write_string(', ') } } - have_want += ')\n' + sb.write_string(')') + c.add_error_detail(sb.str()) args_plural := if p.nr_params == 1 { 'argument' } else { 'arguments' } - c.error('expected ${p.nr_params} ${args_plural}, but got ${p.nr_args}${have_want}', - p.pos) + c.error('expected ${p.nr_params} ${args_plural}, but got ${p.nr_args}', p.pos) } fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast.CallExpr) { diff --git a/vlib/v/checker/tests/ambiguous_function_call.out b/vlib/v/checker/tests/ambiguous_function_call.out index 0eaaaec5a1..0a087ad3d3 100644 --- a/vlib/v/checker/tests/ambiguous_function_call.out +++ b/vlib/v/checker/tests/ambiguous_function_call.out @@ -12,12 +12,11 @@ vlib/v/checker/tests/ambiguous_function_call.vv:7:2: error: ambiguous call to: ` 8 | } 9 | vlib/v/checker/tests/ambiguous_function_call.vv:7:7: error: expected 0 arguments, but got 1 - have (int) - want () - 5 | fn foo2() { 6 | foo2 := 1 7 | foo2(foo2) | ~~~~ 8 | } 9 | +Details: have (int) + want () diff --git a/vlib/v/checker/tests/c_fn_surplus_args.out b/vlib/v/checker/tests/c_fn_surplus_args.out index 92c794d533..03030dd302 100644 --- a/vlib/v/checker/tests/c_fn_surplus_args.out +++ b/vlib/v/checker/tests/c_fn_surplus_args.out @@ -1,43 +1,39 @@ vlib/v/checker/tests/c_fn_surplus_args.vv:6:7: error: expected 0 arguments, but got 1 - have (int literal) - want () - 4 | 5 | fn main() { 6 | C.no(1) // allowed | ^ 7 | C.y1() 8 | C.y1(1) // ok +Details: have (int literal) + want () vlib/v/checker/tests/c_fn_surplus_args.vv:7:4: error: expected 1 argument, but got 0 - have () - want (int) - 5 | fn main() { 6 | C.no(1) // allowed 7 | C.y1() | ~~~~ 8 | C.y1(1) // ok 9 | C.y1(1, 2) +Details: have () + want (int) vlib/v/checker/tests/c_fn_surplus_args.vv:9:10: error: expected 1 argument, but got 2 - have (int literal, int literal) - want (int) - 7 | C.y1() 8 | C.y1(1) // ok 9 | C.y1(1, 2) | ^ 10 | C.ret() // ok 11 | C.ret(1) +Details: have (int literal, int literal) + want (int) vlib/v/checker/tests/c_fn_surplus_args.vv:11:8: error: expected 0 arguments, but got 1 - have (int literal) - want () - 9 | C.y1(1, 2) 10 | C.ret() // ok 11 | C.ret(1) | ^ 12 | // avoid cgen whilst warning, later above should error 13 | main() +Details: have (int literal) + want () vlib/v/checker/tests/c_fn_surplus_args.vv:13:2: error: the `main` function cannot be called in the program 11 | C.ret(1) 12 | // avoid cgen whilst warning, later above should error @@ -46,12 +42,11 @@ vlib/v/checker/tests/c_fn_surplus_args.vv:13:2: error: the `main` function canno 14 | C.af() // ok 15 | C.af(3) vlib/v/checker/tests/c_fn_surplus_args.vv:15:7: error: expected 0 arguments, but got 1 - have (int literal) - want () - 13 | main() 14 | C.af() // ok 15 | C.af(3) | ^ 16 | } 17 | +Details: have (int literal) + want () diff --git a/vlib/v/checker/tests/error_fn_with_0_args.out b/vlib/v/checker/tests/error_fn_with_0_args.out index 9b38a840db..8b3e2a0d9d 100644 --- a/vlib/v/checker/tests/error_fn_with_0_args.out +++ b/vlib/v/checker/tests/error_fn_with_0_args.out @@ -1,8 +1,7 @@ vlib/v/checker/tests/error_fn_with_0_args.vv:2:9: error: expected 1 argument, but got 0 - have () - want (string) - 1 | fn abc() ! { 2 | return error() | ~~~~~~~ 3 | } +Details: have () + want (string) diff --git a/vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.out b/vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.out index abe4846d78..5b0670b1a4 100644 --- a/vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.out +++ b/vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.out @@ -11,11 +11,10 @@ vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.vv:2:9: error: decomp 3 | } 4 | vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.vv:2:6: error: expected 0 arguments, but got 1 - have (void) - want () - 1 | fn main() { 2 | foo(...args) | ~~~~~~~ 3 | } 4 | +Details: have (void) + want () diff --git a/vlib/v/checker/tests/fn_call_with_extra_parenthesis.out b/vlib/v/checker/tests/fn_call_with_extra_parenthesis.out index ebf0be2aa0..e40544b903 100644 --- a/vlib/v/checker/tests/fn_call_with_extra_parenthesis.out +++ b/vlib/v/checker/tests/fn_call_with_extra_parenthesis.out @@ -1,12 +1,11 @@ vlib/v/checker/tests/fn_call_with_extra_parenthesis.vv:5:2: error: expected 1 argument, but got 0 - have () - want (int) - 3 | 4 | fn main() { 5 | doit()(1) | ~~~~~~ 6 | } +Details: have () + want (int) vlib/v/checker/tests/fn_call_with_extra_parenthesis.vv:5:9: error: unknown function: 3 | 4 | fn main() { diff --git a/vlib/v/checker/tests/function_count_of_args_mismatch_err.out b/vlib/v/checker/tests/function_count_of_args_mismatch_err.out index e3cf907f54..13301c1b01 100644 --- a/vlib/v/checker/tests/function_count_of_args_mismatch_err.out +++ b/vlib/v/checker/tests/function_count_of_args_mismatch_err.out @@ -1,39 +1,35 @@ vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:8:13: error: expected 1 argument, but got 3 - have (bool, bool, int literal) - want (bool) - 6 | 7 | fn main() { 8 | test(true, false, 1) | ~~~~~~~~ 9 | test() 10 | test2(true, false, 1) +Details: have (bool, bool, int literal) + want (bool) vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:9:2: error: expected 1 argument, but got 0 - have () - want (bool) - 7 | fn main() { 8 | test(true, false, 1) 9 | test() | ~~~~~~ 10 | test2(true, false, 1) 11 | test2(true) +Details: have () + want (bool) vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:10:21: error: expected 2 arguments, but got 3 - have (bool, bool, int literal) - want (bool, T) - 8 | test(true, false, 1) 9 | test() 10 | test2(true, false, 1) | ^ 11 | test2(true) 12 | } +Details: have (bool, bool, int literal) + want (bool, T) vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:11:2: error: expected 2 arguments, but got 1 - have (bool) - want (bool, T) - 9 | test() 10 | test2(true, false, 1) 11 | test2(true) | ~~~~~~~~~~~ 12 | } +Details: have (bool) + want (bool, T) diff --git a/vlib/v/checker/tests/generics_fn_arguments_count_err.out b/vlib/v/checker/tests/generics_fn_arguments_count_err.out index d264284be5..1f758baff9 100644 --- a/vlib/v/checker/tests/generics_fn_arguments_count_err.out +++ b/vlib/v/checker/tests/generics_fn_arguments_count_err.out @@ -13,15 +13,14 @@ vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:18: error: expected 2 16 | println(ret2) 17 | vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:45: error: expected 2 arguments, but got 3 - have (int literal, int literal, string) - want (A, B) - 13 | println(ret1) 14 | 15 | ret2 := get_name[int, int, string](11, 22, 'hello') | ~~~~~~~ 16 | println(ret2) 17 | +Details: have (int literal, int literal, string) + want (A, B) vlib/v/checker/tests/generics_fn_arguments_count_err.vv:19:22: error: expected 2 generic parameters, got 1 17 | 18 | foo := Foo{} @@ -37,15 +36,14 @@ vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:22: error: expected 2 23 | println(ret4) 24 | } vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:49: error: expected 2 arguments, but got 3 - have (int literal, int literal, string) - want (A, B) - 20 | println(ret3) 21 | 22 | ret4 := foo.get_name[int, int, string](11, 22, 'hello') | ~~~~~~~ 23 | println(ret4) 24 | } +Details: have (int literal, int literal, string) + want (A, B) vlib/v/checker/tests/generics_fn_arguments_count_err.vv:2:12: error: no known default format for type `A` 1 | fn get_name[A, B](a A, b B) string { 2 | return '${a}, ${b}' diff --git a/vlib/v/checker/tests/generics_struct_field_fn_args_err.out b/vlib/v/checker/tests/generics_struct_field_fn_args_err.out index 12a1faff79..3eea54183d 100644 --- a/vlib/v/checker/tests/generics_struct_field_fn_args_err.out +++ b/vlib/v/checker/tests/generics_struct_field_fn_args_err.out @@ -1,43 +1,39 @@ vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:21:20: error: expected 0 arguments, but got 1 - have (int literal) - want () - 19 | } 20 | println(fun0.call()) 21 | println(fun0.call(1234)) | ~~~~ 22 | println(fun0.call(1234, 5678)) 23 | +Details: have (int literal) + want () vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:22:20: error: expected 0 arguments, but got 2 - have (int literal, int literal) - want () - 20 | println(fun0.call()) 21 | println(fun0.call(1234)) 22 | println(fun0.call(1234, 5678)) | ~~~~~~~~~~ 23 | 24 | fun1 := Fun[fn (int) int]{ +Details: have (int literal, int literal) + want () vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:29:15: error: expected 1 argument, but got 0 - have () - want (int) - 27 | 28 | println(fun1.call(42)) 29 | println(fun1.call()) | ~~~~~~ 30 | println(fun1.call(42, 43)) 31 | +Details: have () + want (int) vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:30:24: error: expected 1 argument, but got 2 - have (int literal, int literal) - want (int) - 28 | println(fun1.call(42)) 29 | println(fun1.call()) 30 | println(fun1.call(42, 43)) | ~~ 31 | 32 | println(fun1.call(true)) +Details: have (int literal, int literal) + want (int) vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:32:20: error: cannot use `bool` as `int` in argument 1 to `Fun[fn (int) int].call` 30 | println(fun1.call(42, 43)) 31 | diff --git a/vlib/v/checker/tests/multi_return_err.out b/vlib/v/checker/tests/multi_return_err.out index e6e94dcf7b..86848492be 100644 --- a/vlib/v/checker/tests/multi_return_err.out +++ b/vlib/v/checker/tests/multi_return_err.out @@ -6,35 +6,32 @@ vlib/v/checker/tests/multi_return_err.vv:18:10: error: cannot use `f64` as `int` 19 | my_func3(my_func2(), 'foo') 20 | my_func4('foo', my_func2()) vlib/v/checker/tests/multi_return_err.vv:19:2: error: expected 3 arguments, but got 2 - have ((int, f64), string) - want (int, int, string) - 17 | fn main() { 18 | my_func(my_func2()) 19 | my_func3(my_func2(), 'foo') | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 | my_func4('foo', my_func2()) 21 | my_func(my_func5()) +Details: have ((int, f64), string) + want (int, int, string) vlib/v/checker/tests/multi_return_err.vv:20:2: error: expected 3 arguments, but got 2 - have (string, (int, f64)) - want (string, int, int) - 18 | my_func(my_func2()) 19 | my_func3(my_func2(), 'foo') 20 | my_func4('foo', my_func2()) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21 | my_func(my_func5()) 22 | my_func(my_func6()) +Details: have (string, (int, f64)) + want (string, int, int) vlib/v/checker/tests/multi_return_err.vv:21:2: error: expected 2 arguments, but got 1 - have (void) - want (int, int) - 19 | my_func3(my_func2(), 'foo') 20 | my_func4('foo', my_func2()) 21 | my_func(my_func5()) | ~~~~~~~~~~~~~~~~~~~ 22 | my_func(my_func6()) 23 | } +Details: have (void) + want (int, int) vlib/v/checker/tests/multi_return_err.vv:22:10: error: expected 2 arguments, but got 3 from multi-return (int, int, int) 20 | my_func4('foo', my_func2()) 21 | my_func(my_func5()) diff --git a/vlib/v/checker/tests/no_interface_instantiation_b.out b/vlib/v/checker/tests/no_interface_instantiation_b.out index da89dbbedd..110e4b6f0c 100644 --- a/vlib/v/checker/tests/no_interface_instantiation_b.out +++ b/vlib/v/checker/tests/no_interface_instantiation_b.out @@ -1,9 +1,8 @@ vlib/v/checker/tests/no_interface_instantiation_b.vv:6:2: error: expected 1 argument, but got 0 - have () - want (Speaker) - 4 | 5 | fn main() { 6 | my_fn() | ~~~~~~~ 7 | } +Details: have () + want (main.Speaker) diff --git a/vlib/v/checker/tests/no_main_println_err.out b/vlib/v/checker/tests/no_main_println_err.out index b1df0c28f1..c20e3cb339 100644 --- a/vlib/v/checker/tests/no_main_println_err.out +++ b/vlib/v/checker/tests/no_main_println_err.out @@ -1,6 +1,5 @@ vlib/v/checker/tests/no_main_println_err.vv:1:1: error: expected 1 argument, but got 0 - have () - want (string) - 1 | println() | ~~~~~~~~~ +Details: have () + want (string)