Skip to content

Commit a88d0d6

Browse files
authored
cgen,checker: improve handling of array decompose for dynamic arrays and array init (fix #25838) (#25843)
1 parent 3f68f3f commit a88d0d6

File tree

6 files changed

+149
-8
lines changed

6 files changed

+149
-8
lines changed

vlib/v/checker/fn.v

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,20 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
15241524
}
15251525
}
15261526
has_decompose = call_arg.expr is ast.ArrayDecompose
1527+
if !func.is_variadic && call_arg.expr is ast.ArrayDecompose {
1528+
if mut call_arg.expr is ast.ArrayDecompose {
1529+
if call_arg.expr.expr is ast.ArrayInit {
1530+
extra_params := func.params.len - i
1531+
array_init := call_arg.expr.expr as ast.ArrayInit
1532+
if array_init.exprs.len < extra_params {
1533+
elem_word := if array_init.exprs.len == 1 { 'element' } else { 'elements' }
1534+
verb_word := if extra_params == 1 { 'is' } else { 'are' }
1535+
c.error('array decompose has ${array_init.exprs.len} ${elem_word} but ${extra_params} ${verb_word} needed for `${func.name}`',
1536+
call_arg.pos)
1537+
}
1538+
}
1539+
}
1540+
}
15271541
already_checked := node.language != .js && call_arg.expr is ast.CallExpr
15281542
if func.is_variadic && param_i >= func.params.len - 1 {
15291543
param_sym := c.table.sym(param.typ)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
vlib/v/checker/tests/array_init_decompose_extra_params.vv:33:11: error: array decompose has 1 element but 2 are needed for `print_2`
2+
31 | print_3(...arr4)
3+
32 |
4+
33 | print_2(...['1'])
5+
| ~~~~~~~~
6+
34 | print_3(...['1', '2'])
7+
35 | print_4(...['1', '2', '3'])
8+
vlib/v/checker/tests/array_init_decompose_extra_params.vv:34:11: error: array decompose has 2 elements but 3 are needed for `print_3`
9+
32 |
10+
33 | print_2(...['1'])
11+
34 | print_3(...['1', '2'])
12+
| ~~~~~~~~~~~~~
13+
35 | print_4(...['1', '2', '3'])
14+
36 | }
15+
vlib/v/checker/tests/array_init_decompose_extra_params.vv:35:11: error: array decompose has 3 elements but 4 are needed for `print_4`
16+
33 | print_2(...['1'])
17+
34 | print_3(...['1', '2'])
18+
35 | print_4(...['1', '2', '3'])
19+
| ~~~~~~~~~~~~~~~~~~
20+
36 | }
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
fn print_1(s string) {
2+
dump(s)
3+
}
4+
5+
fn print_2(s string, t string) {
6+
dump('${s} ${t}')
7+
}
8+
9+
fn print_3(s string, t string, u string) {
10+
dump('${s} ${t} ${u}')
11+
}
12+
13+
fn print_4(s string, t string, u string, v string) {
14+
dump('${s} ${t} ${u} ${v}')
15+
}
16+
17+
fn main() {
18+
arr4 := ['Hello', 'World', 'V', '!']
19+
20+
print_1(...['Hello'])
21+
print_2(...['Hello', 'World'])
22+
print_3(...['Hello', 'World', '!'])
23+
print_4(...['Hello', 'World', 'V', '!'])
24+
print_4(...arr4)
25+
26+
print_1(...['Hello', 'World', 'V', '!'])
27+
print_1(...arr4)
28+
print_2(...['Hello', 'World', 'V', '!'])
29+
print_2(...arr4)
30+
print_3(...['Hello', 'World', 'V', '!'])
31+
print_3(...arr4)
32+
33+
print_2(...['1'])
34+
print_3(...['1', '2'])
35+
print_4(...['1', '2', '3'])
36+
}

vlib/v/gen/c/fn.v

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2483,15 +2483,47 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
24832483
}
24842484
} else if arg.expr is ast.ArrayDecompose {
24852485
mut d_count := 0
2486-
for d_i in i .. expected_types.len {
2487-
g.write('*(${g.styp(expected_types[d_i])}*)builtin__array_get(')
2488-
g.expr(arg.expr)
2489-
g.write(', ${d_count})')
2490-
2491-
if d_i < expected_types.len - 1 {
2492-
g.write(', ')
2486+
remaining_params := expected_types.len - i
2487+
if !arg.expr.expr_type.has_flag(.variadic) && remaining_params > 0 {
2488+
tmp_array := g.new_tmp_var()
2489+
line := g.go_before_last_stmt()
2490+
array_typ := g.styp(arg.expr.expr_type)
2491+
g.write('\t${array_typ} ${tmp_array} = ')
2492+
g.expr(arg.expr.expr)
2493+
g.writeln(';')
2494+
g.writeln('if (${tmp_array}.len < ${remaining_params}) {')
2495+
elem_word := if remaining_params == 1 { 'element is' } else { 'elements are' }
2496+
tmp_err_msg := g.new_tmp_var()
2497+
g.writeln('\tstring ${tmp_err_msg};')
2498+
g.writeln('\tif (${tmp_array}.len == 1) {')
2499+
g.writeln('\t\t${tmp_err_msg} = builtin__str_intp(2, _MOV((StrIntpData[]){')
2500+
g.writeln('\t\t\t{_S("array decompose: array has "), 0xfe07, {.d_i32 = ${tmp_array}.len}},')
2501+
g.writeln('\t\t\t{_S(" element but ${remaining_params} ${elem_word} needed"), 0, {.d_c = 0 }}}));')
2502+
g.writeln('\t} else {')
2503+
g.writeln('\t\t${tmp_err_msg} = builtin__str_intp(2, _MOV((StrIntpData[]){')
2504+
g.writeln('\t\t\t{_S("array decompose: array has "), 0xfe07, {.d_i32 = ${tmp_array}.len}},')
2505+
g.writeln('\t\t\t{_S(" elements but ${remaining_params} ${elem_word} needed"), 0, {.d_c = 0 }}}));')
2506+
g.writeln('\t}')
2507+
g.writeln('\tbuiltin___v_panic(${tmp_err_msg});')
2508+
g.writeln('}')
2509+
g.write(line.trim_left('\t'))
2510+
for d_i in i .. expected_types.len {
2511+
g.write('*(${g.styp(expected_types[d_i])}*)builtin__array_get(${tmp_array}, ${d_count})')
2512+
if d_i < expected_types.len - 1 {
2513+
g.write(', ')
2514+
}
2515+
d_count++
2516+
}
2517+
} else {
2518+
for d_i in i .. expected_types.len {
2519+
g.write('*(${g.styp(expected_types[d_i])}*)builtin__array_get(')
2520+
g.expr(arg.expr)
2521+
g.write(', ${d_count})')
2522+
if d_i < expected_types.len - 1 {
2523+
g.write(', ')
2524+
}
2525+
d_count++
24932526
}
2494-
d_count++
24952527
}
24962528
already_decomposed = true
24972529
continue
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv:2] s: a
2+
[vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv:2] s: a
3+
[vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv:6] '$s $t': a b
4+
[vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv:10] '$s $t $u': a b c
5+
[vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv:2] s: b
6+
[vlib/v/slow_tests/inout/panic_array_decompose_extra_args.vv:6] '$s $t': b c
7+
================ V panic ================
8+
V panic: array decompose: array has 3 elements but 4 elements are needed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
fn print_1(s string) {
2+
dump(s)
3+
}
4+
5+
fn print_2(s string, t string) {
6+
dump('${s} ${t}')
7+
}
8+
9+
fn print_3(s string, t string, u string) {
10+
dump('${s} ${t} ${u}')
11+
}
12+
13+
fn print_4(s string, t string, u string, v string) {
14+
dump('${s} ${t} ${u} ${v}')
15+
}
16+
17+
fn main() {
18+
array := ['a', 'b', 'c']
19+
20+
print_1(array[0])
21+
22+
print_1(...array)
23+
print_2(...array)
24+
print_3(...array)
25+
26+
print_1(...array[1..2])
27+
print_2(...array[1..])
28+
29+
println('================ V panic ================')
30+
print_4(...array)
31+
}

0 commit comments

Comments
 (0)