Skip to content

Commit 586d34d

Browse files
authored
cgen: fix multi-return match in closure (fix #26558) (#26566)
1 parent c34ea2b commit 586d34d

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

‎vlib/v/gen/c/cgen.v‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5963,13 +5963,25 @@ fn (mut g Gen) concat_expr(node ast.ConcatExpr) {
59635963
} else if g.inside_or_block {
59645964
typ = g.or_expr_return_type.clear_option_and_result()
59655965
}
5966-
styp := g.styp(typ)
59675966
sym := g.table.sym(node.return_type)
59685967
is_multi := sym.kind == .multi_return
59695968
if !is_multi {
59705969
g.expr(node.vals[0])
59715970
} else {
5972-
types := (g.table.sym(typ).info as ast.MultiReturn).types
5971+
// When typ is also a multi-return type, use it to get the types array,
5972+
// as it may have more accurate type information (e.g., with option types).
5973+
// Otherwise, fall back to using node.return_type.
5974+
typ_sym := g.table.sym(typ)
5975+
types := if typ_sym.kind == .multi_return {
5976+
(typ_sym.info as ast.MultiReturn).types
5977+
} else {
5978+
(sym.info as ast.MultiReturn).types
5979+
}
5980+
styp := if typ_sym.kind == .multi_return {
5981+
g.styp(typ)
5982+
} else {
5983+
g.styp(node.return_type.clear_option_and_result())
5984+
}
59735985
g.write('(${styp}){')
59745986
for i, expr in node.vals {
59755987
g.write('.arg${i}=')
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Regression test for https://github.com/vlang/v/issues/26558
2+
// Multi-return match assignment inside closure should work
3+
// when the closure is a field of a @[heap] struct and the
4+
// struct init is inside a return expression.
5+
6+
@[heap]
7+
struct Cfg {
8+
handler fn (string) = unsafe { nil }
9+
}
10+
11+
fn call_it(cfg Cfg) {
12+
if cfg.handler != unsafe { nil } {
13+
cfg.handler('s')
14+
}
15+
}
16+
17+
fn make_cfg(ch string) Cfg {
18+
return Cfg{
19+
handler: fn [ch] (s string) {
20+
x, y, z := match ch {
21+
'h' { f32(1), f32(2), f32(3) }
22+
's' { f32(4), f32(5), f32(6) }
23+
else { f32(7), f32(8), f32(9) }
24+
}
25+
println('${x} ${y} ${z}')
26+
}
27+
}
28+
}
29+
30+
fn test_multi_return_match_in_closure_heap_struct() {
31+
// This test verifies that the compiler does not panic with:
32+
// "as cast: cannot cast `v.ast.UnknownTypeInfo` to `v.ast.MultiReturn`"
33+
call_it(make_cfg('h'))
34+
call_it(make_cfg('s'))
35+
call_it(make_cfg('x'))
36+
}

0 commit comments

Comments
 (0)