Skip to content

Commit e6570dd

Browse files
authored
cgen: fix return with option on orexpr (#20728)
1 parent a374d25 commit e6570dd

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

vlib/v/gen/c/cgen.v

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6624,19 +6624,30 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
66246624
is_array_fixed = expr_stmt.expr is ast.ArrayInit
66256625
&& g.table.final_sym(return_type).kind == .array_fixed
66266626
if !is_array_fixed {
6627-
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
6627+
if g.inside_return && !g.inside_struct_init
6628+
&& expr_stmt.expr is ast.CallExpr
6629+
&& return_type.has_option_or_result() {
6630+
g.write('${cvar_name} = ')
6631+
} else {
6632+
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
6633+
}
66286634
}
66296635
} else {
66306636
g.write('${cvar_name} = ')
66316637
}
6632-
66336638
if is_array_fixed {
66346639
g.write('memcpy(${cvar_name}.data, (${cast_typ})')
66356640
}
6636-
old_inside_opt_data := g.inside_opt_data
6637-
g.inside_opt_data = true
6638-
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_option_and_result())
6639-
g.inside_opt_data = old_inside_opt_data
6641+
// return expr or { fn_returns_option() }
6642+
if is_option && g.inside_return && expr_stmt.expr is ast.CallExpr
6643+
&& return_type.has_option_or_result() {
6644+
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type)
6645+
} else {
6646+
old_inside_opt_data := g.inside_opt_data
6647+
g.inside_opt_data = true
6648+
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_option_and_result())
6649+
g.inside_opt_data = old_inside_opt_data
6650+
}
66406651
if is_array_fixed {
66416652
g.write(', sizeof(${cast_typ}))')
66426653
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
fn find_startswith_string(a []string, search string) ?string {
2+
for s in a {
3+
if s.starts_with(search) {
4+
return s
5+
}
6+
}
7+
return none
8+
}
9+
10+
fn find_any_startswith_string(a []string, b []string, search string) ?string {
11+
// cannot convert 'struct _option_string' to 'struct string'
12+
// V wants the or {} block to return a string, but find_startswith_string returns ?string
13+
return find_startswith_string(a, search) or { find_startswith_string(b, search) }
14+
}
15+
16+
fn test_main() {
17+
deadbeef := find_any_startswith_string(['foobar', 'barfoo'], ['deadbeef', 'beefdead'],
18+
'dead')
19+
assert deadbeef or { panic('unreachable') } == 'deadbeef'
20+
}

0 commit comments

Comments
 (0)