checker: improve fn argument mismatch error (#22370)

This commit is contained in:
Jose Mendoza 2024-10-01 03:45:03 -04:00 committed by GitHub
parent 81b9fd8b14
commit fc72044b42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 62 additions and 82 deletions

View file

@ -1,5 +1,6 @@
module checker module checker
import strings
import v.ast import v.ast
import v.util import v.util
import v.token import v.token
@ -2863,7 +2864,8 @@ struct HaveWantParams {
} }
fn (mut c Checker) fn_call_error_have_want(p 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 // 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 // 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} 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 { if arg_types[i] == 0 { // arg.typ == 0 {
// Arguments can have an unknown (invalid) type // Arguments can have an unknown (invalid) type
// This should never happen. // This should never happen.
have_want += '?' sb.write_string('?')
} else { } 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 { if i < p.args.len - 1 {
have_want += ', ' sb.write_string(', ')
} }
} }
sb.write_string(')')
c.add_error_detail(sb.str())
// Actual parameters we expect // Actual parameters we expect
have_want += ')\n\twant (' sb.write_string(' want (')
for i, param in p.params { for i, param in p.params {
if i == 0 && p.nr_params == p.params.len - 1 { if i == 0 && p.nr_params == p.params.len - 1 {
// Skip receiver // Skip receiver
continue 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 { 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' } 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}', c.error('expected ${p.nr_params} ${args_plural}, but got ${p.nr_args}', p.pos)
p.pos)
} }
fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast.CallExpr) { fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast.CallExpr) {

View file

@ -12,12 +12,11 @@ vlib/v/checker/tests/ambiguous_function_call.vv:7:2: error: ambiguous call to: `
8 | } 8 | }
9 | 9 |
vlib/v/checker/tests/ambiguous_function_call.vv:7:7: error: expected 0 arguments, but got 1 vlib/v/checker/tests/ambiguous_function_call.vv:7:7: error: expected 0 arguments, but got 1
have (int)
want ()
5 | fn foo2() { 5 | fn foo2() {
6 | foo2 := 1 6 | foo2 := 1
7 | foo2(foo2) 7 | foo2(foo2)
| ~~~~ | ~~~~
8 | } 8 | }
9 | 9 |
Details: have (int)
want ()

View file

@ -1,43 +1,39 @@
vlib/v/checker/tests/c_fn_surplus_args.vv:6:7: error: expected 0 arguments, but got 1 vlib/v/checker/tests/c_fn_surplus_args.vv:6:7: error: expected 0 arguments, but got 1
have (int literal)
want ()
4 | 4 |
5 | fn main() { 5 | fn main() {
6 | C.no(1) // allowed 6 | C.no(1) // allowed
| ^ | ^
7 | C.y1() 7 | C.y1()
8 | C.y1(1) // ok 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 vlib/v/checker/tests/c_fn_surplus_args.vv:7:4: error: expected 1 argument, but got 0
have ()
want (int)
5 | fn main() { 5 | fn main() {
6 | C.no(1) // allowed 6 | C.no(1) // allowed
7 | C.y1() 7 | C.y1()
| ~~~~ | ~~~~
8 | C.y1(1) // ok 8 | C.y1(1) // ok
9 | C.y1(1, 2) 9 | C.y1(1, 2)
vlib/v/checker/tests/c_fn_surplus_args.vv:9:10: error: expected 1 argument, but got 2 Details: have ()
have (int literal, int literal)
want (int) want (int)
vlib/v/checker/tests/c_fn_surplus_args.vv:9:10: error: expected 1 argument, but got 2
7 | C.y1() 7 | C.y1()
8 | C.y1(1) // ok 8 | C.y1(1) // ok
9 | C.y1(1, 2) 9 | C.y1(1, 2)
| ^ | ^
10 | C.ret() // ok 10 | C.ret() // ok
11 | C.ret(1) 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 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) 9 | C.y1(1, 2)
10 | C.ret() // ok 10 | C.ret() // ok
11 | C.ret(1) 11 | C.ret(1)
| ^ | ^
12 | // avoid cgen whilst warning, later above should error 12 | // avoid cgen whilst warning, later above should error
13 | main() 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 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) 11 | C.ret(1)
12 | // avoid cgen whilst warning, later above should error 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 14 | C.af() // ok
15 | C.af(3) 15 | C.af(3)
vlib/v/checker/tests/c_fn_surplus_args.vv:15:7: error: expected 0 arguments, but got 1 vlib/v/checker/tests/c_fn_surplus_args.vv:15:7: error: expected 0 arguments, but got 1
have (int literal)
want ()
13 | main() 13 | main()
14 | C.af() // ok 14 | C.af() // ok
15 | C.af(3) 15 | C.af(3)
| ^ | ^
16 | } 16 | }
17 | 17 |
Details: have (int literal)
want ()

View file

@ -1,8 +1,7 @@
vlib/v/checker/tests/error_fn_with_0_args.vv:2:9: error: expected 1 argument, but got 0 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() ! { 1 | fn abc() ! {
2 | return error() 2 | return error()
| ~~~~~~~ | ~~~~~~~
3 | } 3 | }
Details: have ()
want (string)

View file

@ -11,11 +11,10 @@ vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.vv:2:9: error: decomp
3 | } 3 | }
4 | 4 |
vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.vv:2:6: error: expected 0 arguments, but got 1 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() { 1 | fn main() {
2 | foo(...args) 2 | foo(...args)
| ~~~~~~~ | ~~~~~~~
3 | } 3 | }
4 | 4 |
Details: have (void)
want ()

View file

@ -1,12 +1,11 @@
vlib/v/checker/tests/fn_call_with_extra_parenthesis.vv:5:2: error: expected 1 argument, but got 0 vlib/v/checker/tests/fn_call_with_extra_parenthesis.vv:5:2: error: expected 1 argument, but got 0
have ()
want (int)
3 | 3 |
4 | fn main() { 4 | fn main() {
5 | doit()(1) 5 | doit()(1)
| ~~~~~~ | ~~~~~~
6 | } 6 | }
Details: have ()
want (int)
vlib/v/checker/tests/fn_call_with_extra_parenthesis.vv:5:9: error: unknown function: vlib/v/checker/tests/fn_call_with_extra_parenthesis.vv:5:9: error: unknown function:
3 | 3 |
4 | fn main() { 4 | fn main() {

View file

@ -1,39 +1,35 @@
vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:8:13: error: expected 1 argument, but got 3 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 | 6 |
7 | fn main() { 7 | fn main() {
8 | test(true, false, 1) 8 | test(true, false, 1)
| ~~~~~~~~ | ~~~~~~~~
9 | test() 9 | test()
10 | test2(true, false, 1) 10 | test2(true, false, 1)
vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:9:2: error: expected 1 argument, but got 0 Details: have (bool, bool, int literal)
have ()
want (bool) want (bool)
vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:9:2: error: expected 1 argument, but got 0
7 | fn main() { 7 | fn main() {
8 | test(true, false, 1) 8 | test(true, false, 1)
9 | test() 9 | test()
| ~~~~~~ | ~~~~~~
10 | test2(true, false, 1) 10 | test2(true, false, 1)
11 | test2(true) 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 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) 8 | test(true, false, 1)
9 | test() 9 | test()
10 | test2(true, false, 1) 10 | test2(true, false, 1)
| ^ | ^
11 | test2(true) 11 | test2(true)
12 | } 12 | }
vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:11:2: error: expected 2 arguments, but got 1 Details: have (bool, bool, int literal)
have (bool)
want (bool, T) want (bool, T)
vlib/v/checker/tests/function_count_of_args_mismatch_err.vv:11:2: error: expected 2 arguments, but got 1
9 | test() 9 | test()
10 | test2(true, false, 1) 10 | test2(true, false, 1)
11 | test2(true) 11 | test2(true)
| ~~~~~~~~~~~ | ~~~~~~~~~~~
12 | } 12 | }
Details: have (bool)
want (bool, T)

View file

@ -13,15 +13,14 @@ vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:18: error: expected 2
16 | println(ret2) 16 | println(ret2)
17 | 17 |
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:45: error: expected 2 arguments, but got 3 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) 13 | println(ret1)
14 | 14 |
15 | ret2 := get_name[int, int, string](11, 22, 'hello') 15 | ret2 := get_name[int, int, string](11, 22, 'hello')
| ~~~~~~~ | ~~~~~~~
16 | println(ret2) 16 | println(ret2)
17 | 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 vlib/v/checker/tests/generics_fn_arguments_count_err.vv:19:22: error: expected 2 generic parameters, got 1
17 | 17 |
18 | foo := Foo{} 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) 23 | println(ret4)
24 | } 24 | }
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:49: error: expected 2 arguments, but got 3 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) 20 | println(ret3)
21 | 21 |
22 | ret4 := foo.get_name[int, int, string](11, 22, 'hello') 22 | ret4 := foo.get_name[int, int, string](11, 22, 'hello')
| ~~~~~~~ | ~~~~~~~
23 | println(ret4) 23 | println(ret4)
24 | } 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` 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 { 1 | fn get_name[A, B](a A, b B) string {
2 | return '${a}, ${b}' 2 | return '${a}, ${b}'

View file

@ -1,43 +1,39 @@
vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:21:20: error: expected 0 arguments, but got 1 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 | } 19 | }
20 | println(fun0.call()) 20 | println(fun0.call())
21 | println(fun0.call(1234)) 21 | println(fun0.call(1234))
| ~~~~ | ~~~~
22 | println(fun0.call(1234, 5678)) 22 | println(fun0.call(1234, 5678))
23 | 23 |
vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:22:20: error: expected 0 arguments, but got 2 Details: have (int literal)
have (int literal, int literal)
want () want ()
vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:22:20: error: expected 0 arguments, but got 2
20 | println(fun0.call()) 20 | println(fun0.call())
21 | println(fun0.call(1234)) 21 | println(fun0.call(1234))
22 | println(fun0.call(1234, 5678)) 22 | println(fun0.call(1234, 5678))
| ~~~~~~~~~~ | ~~~~~~~~~~
23 | 23 |
24 | fun1 := Fun[fn (int) int]{ 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 vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:29:15: error: expected 1 argument, but got 0
have ()
want (int)
27 | 27 |
28 | println(fun1.call(42)) 28 | println(fun1.call(42))
29 | println(fun1.call()) 29 | println(fun1.call())
| ~~~~~~ | ~~~~~~
30 | println(fun1.call(42, 43)) 30 | println(fun1.call(42, 43))
31 | 31 |
vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:30:24: error: expected 1 argument, but got 2 Details: have ()
have (int literal, int literal)
want (int) want (int)
vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:30:24: error: expected 1 argument, but got 2
28 | println(fun1.call(42)) 28 | println(fun1.call(42))
29 | println(fun1.call()) 29 | println(fun1.call())
30 | println(fun1.call(42, 43)) 30 | println(fun1.call(42, 43))
| ~~ | ~~
31 | 31 |
32 | println(fun1.call(true)) 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` 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)) 30 | println(fun1.call(42, 43))
31 | 31 |

View file

@ -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') 19 | my_func3(my_func2(), 'foo')
20 | my_func4('foo', my_func2()) 20 | my_func4('foo', my_func2())
vlib/v/checker/tests/multi_return_err.vv:19:2: error: expected 3 arguments, but got 2 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() { 17 | fn main() {
18 | my_func(my_func2()) 18 | my_func(my_func2())
19 | my_func3(my_func2(), 'foo') 19 | my_func3(my_func2(), 'foo')
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 | my_func4('foo', my_func2()) 20 | my_func4('foo', my_func2())
21 | my_func(my_func5()) 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 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()) 18 | my_func(my_func2())
19 | my_func3(my_func2(), 'foo') 19 | my_func3(my_func2(), 'foo')
20 | my_func4('foo', my_func2()) 20 | my_func4('foo', my_func2())
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
21 | my_func(my_func5()) 21 | my_func(my_func5())
22 | my_func(my_func6()) 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 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') 19 | my_func3(my_func2(), 'foo')
20 | my_func4('foo', my_func2()) 20 | my_func4('foo', my_func2())
21 | my_func(my_func5()) 21 | my_func(my_func5())
| ~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~
22 | my_func(my_func6()) 22 | my_func(my_func6())
23 | } 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) 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()) 20 | my_func4('foo', my_func2())
21 | my_func(my_func5()) 21 | my_func(my_func5())

View file

@ -1,9 +1,8 @@
vlib/v/checker/tests/no_interface_instantiation_b.vv:6:2: error: expected 1 argument, but got 0 vlib/v/checker/tests/no_interface_instantiation_b.vv:6:2: error: expected 1 argument, but got 0
have ()
want (Speaker)
4 | 4 |
5 | fn main() { 5 | fn main() {
6 | my_fn() 6 | my_fn()
| ~~~~~~~ | ~~~~~~~
7 | } 7 | }
Details: have ()
want (main.Speaker)

View file

@ -1,6 +1,5 @@
vlib/v/checker/tests/no_main_println_err.vv:1:1: error: expected 1 argument, but got 0 vlib/v/checker/tests/no_main_println_err.vv:1:1: error: expected 1 argument, but got 0
have ()
want (string)
1 | println() 1 | println()
| ~~~~~~~~~ | ~~~~~~~~~
Details: have ()
want (string)