Skip to content

Commit 1ba4512

Browse files
authored
checker: fix multi return arg passing checking (fix #25167) (fix #25180) (#25177)
1 parent 9e1273a commit 1ba4512

4 files changed

Lines changed: 61 additions & 17 deletions

File tree

‎vlib/v/checker/fn.v‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
14721472
node.pos)
14731473
}
14741474
mut has_decompose := false
1475+
mut nr_multi_values := 0
14751476
for i, mut call_arg in node.args {
14761477
if func.params.len == 0 {
14771478
continue
@@ -1482,21 +1483,22 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
14821483
if !func.is_variadic && has_decompose {
14831484
c.error('cannot have parameter after array decompose', node.pos)
14841485
}
1486+
param_i := i + nr_multi_values
14851487
param := if func.is_variadic && i >= func.params.len - 1 {
14861488
func.params.last()
14871489
} else {
1488-
func.params[i]
1490+
func.params[param_i]
14891491
}
14901492
// registers if the arg must be passed by ref to disable auto deref args
14911493
call_arg.should_be_ptr = param.typ.is_ptr() && !param.is_mut
14921494
if func.is_variadic && call_arg.expr is ast.ArrayDecompose {
1493-
if i > func.params.len - 1 {
1495+
if param_i > func.params.len - 1 {
14941496
c.error('too many arguments in call to `${func.name}`', node.pos)
14951497
}
14961498
}
14971499
has_decompose = call_arg.expr is ast.ArrayDecompose
14981500
already_checked := node.language != .js && call_arg.expr is ast.CallExpr
1499-
if func.is_variadic && i >= func.params.len - 1 {
1501+
if func.is_variadic && param_i >= func.params.len - 1 {
15001502
param_sym := c.table.sym(param.typ)
15011503
mut expected_type := param.typ
15021504
if param_sym.info is ast.Array {
@@ -1688,15 +1690,16 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
16881690
multi_param := if func.is_variadic && i >= func.params.len - 1 {
16891691
func.params.last()
16901692
} else {
1691-
func.params[n + i]
1693+
func.params[n + param_i]
16921694
}
16931695
c.check_expected_call_arg(curr_arg, c.unwrap_generic(multi_param.typ),
16941696
node.language, call_arg) or {
1695-
c.error('${err.msg()} in argument ${i + n + 1} to `${fn_name}` from ${c.table.type_to_str(arg_typ)}',
1697+
c.error('${err.msg()} in argument ${param_i + n + 1} to `${fn_name}` from ${c.table.type_to_str(arg_typ)}',
16961698
call_arg.pos)
16971699
continue out
16981700
}
16991701
}
1702+
nr_multi_values += arg_typ_sym.info.types.len - 1
17001703
continue
17011704
} else if param_typ_sym.info is ast.Struct && arg_typ_sym.info is ast.Struct
17021705
&& param_typ_sym.info.is_anon {
@@ -1788,13 +1791,14 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
17881791
continue
17891792
}
17901793
*/
1791-
c.error('${err.msg()} in argument ${i + 1} to `${fn_name}`', call_arg.pos)
1794+
c.error('${err.msg()} in argument ${i + nr_multi_values + 1} to `${fn_name}`',
1795+
call_arg.pos)
17921796
}
17931797
if final_param_sym.kind == .struct && arg_typ !in [ast.voidptr_type, ast.nil_type]
17941798
&& !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
17951799
got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
1796-
c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i + 1} to `${fn_name}`',
1797-
call_arg.pos)
1800+
c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i +
1801+
nr_multi_values + 1} to `${fn_name}`', call_arg.pos)
17981802
}
17991803
// Warn about automatic (de)referencing, which will be removed soon.
18001804
if func.language != .c && !c.inside_unsafe && !(call_arg.is_mut && param.is_mut) {
@@ -2924,6 +2928,17 @@ fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) !
29242928
return error('')
29252929
}
29262930
}
2931+
} else if node.args.len > 1 && node.args.any(it.expr is ast.CallExpr
2932+
&& it.expr.nr_ret_values > 1) {
2933+
mut check_args := 0
2934+
for arg in node.args {
2935+
if arg.expr is ast.CallExpr && arg.expr.nr_ret_values > 0 {
2936+
check_args += arg.expr.nr_ret_values
2937+
} else {
2938+
check_args += 1
2939+
}
2940+
}
2941+
nr_args = check_args
29272942
}
29282943
if min_required_params < 0 {
29292944
min_required_params = 0
@@ -2966,7 +2981,7 @@ fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) !
29662981
)
29672982
return error('')
29682983
} else if !f.is_variadic && nr_args > nr_params {
2969-
unexpected_args_pos := node.args[min_required_params].pos.extend(node.args.last().pos)
2984+
unexpected_args_pos := node.args[int_min(min_required_params, node.args.len - 1)].pos.extend(node.args.last().pos)
29702985
// c.error('3expected ${min_required_params} arguments, but got ${nr_args}', unexpected_args_pos)
29712986
c.fn_call_error_have_want(
29722987
nr_params: min_required_params
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
vlib/v/checker/tests/multi_return_arg_missing_err.vv:12:14: error: expected 2 arguments, but got 3
2+
10 |
3+
11 | fn main() {
4+
12 | expect_2(1, returning_2())
5+
| ~~~~~~~~~~~~~
6+
13 | expect_2(returning_2(), 1)
7+
14 | expect_4(returning_2(), returning_2())
8+
Details: have (int literal, (int, int))
9+
want (int, int)
10+
vlib/v/checker/tests/multi_return_arg_missing_err.vv:13:26: error: expected 2 arguments, but got 3
11+
11 | fn main() {
12+
12 | expect_2(1, returning_2())
13+
13 | expect_2(returning_2(), 1)
14+
| ^
15+
14 | expect_4(returning_2(), returning_2())
16+
15 | }
17+
Details: have ((int, int), int literal)
18+
want (int, int)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
fn expect_2(a int, b int) {
2+
}
3+
4+
fn expect_4(a int, b int, c int, d int) {
5+
}
6+
7+
fn returning_2() (int, int) {
8+
return 1, 1
9+
}
10+
11+
fn main() {
12+
expect_2(1, returning_2())
13+
expect_2(returning_2(), 1)
14+
expect_4(returning_2(), returning_2())
15+
}

‎vlib/v/checker/tests/multi_return_err.out‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,20 @@ vlib/v/checker/tests/multi_return_err.vv:18:10: error: cannot use `f64` as `int`
55
| ~~~~~~~~~~
66
19 | my_func3(my_func2(), 'foo')
77
20 | my_func4('foo', my_func2())
8-
vlib/v/checker/tests/multi_return_err.vv:19:2: error: expected 3 arguments, but got 2
8+
vlib/v/checker/tests/multi_return_err.vv:19:11: error: cannot use `f64` as `int` in argument 2 to `my_func3` from (int, f64)
99
17 | fn main() {
1010
18 | my_func(my_func2())
1111
19 | my_func3(my_func2(), 'foo')
12-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
12+
| ~~~~~~~~~~
1313
20 | my_func4('foo', my_func2())
1414
21 | my_func(my_func5())
15-
Details: have ((int, f64), string)
16-
want (int, int, string)
17-
vlib/v/checker/tests/multi_return_err.vv:20:2: error: expected 3 arguments, but got 2
15+
vlib/v/checker/tests/multi_return_err.vv:20:18: error: cannot use `f64` as `int` in argument 3 to `my_func4` from (int, f64)
1816
18 | my_func(my_func2())
1917
19 | my_func3(my_func2(), 'foo')
2018
20 | my_func4('foo', my_func2())
21-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
19+
| ~~~~~~~~~~
2220
21 | my_func(my_func5())
2321
22 | my_func(my_func6())
24-
Details: have (string, (int, f64))
25-
want (string, int, int)
2622
vlib/v/checker/tests/multi_return_err.vv:21:2: error: expected 2 arguments, but got 1
2723
19 | my_func3(my_func2(), 'foo')
2824
20 | my_func4('foo', my_func2())

0 commit comments

Comments
 (0)