Skip to content

Commit

Permalink
cgen: fix return with option on orexpr (#20728)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp committed Feb 6, 2024
1 parent a374d25 commit e6570dd
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 6 deletions.
23 changes: 17 additions & 6 deletions vlib/v/gen/c/cgen.v
Expand Up @@ -6624,19 +6624,30 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
is_array_fixed = expr_stmt.expr is ast.ArrayInit
&& g.table.final_sym(return_type).kind == .array_fixed
if !is_array_fixed {
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
if g.inside_return && !g.inside_struct_init
&& expr_stmt.expr is ast.CallExpr
&& return_type.has_option_or_result() {
g.write('${cvar_name} = ')
} else {
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
}
}
} else {
g.write('${cvar_name} = ')
}

if is_array_fixed {
g.write('memcpy(${cvar_name}.data, (${cast_typ})')
}
old_inside_opt_data := g.inside_opt_data
g.inside_opt_data = true
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_option_and_result())
g.inside_opt_data = old_inside_opt_data
// return expr or { fn_returns_option() }
if is_option && g.inside_return && expr_stmt.expr is ast.CallExpr
&& return_type.has_option_or_result() {
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type)
} else {
old_inside_opt_data := g.inside_opt_data
g.inside_opt_data = true
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_option_and_result())
g.inside_opt_data = old_inside_opt_data
}
if is_array_fixed {
g.write(', sizeof(${cast_typ}))')
}
Expand Down
20 changes: 20 additions & 0 deletions vlib/v/tests/option_call_on_orexpr_test.v
@@ -0,0 +1,20 @@
fn find_startswith_string(a []string, search string) ?string {
for s in a {
if s.starts_with(search) {
return s
}
}
return none
}

fn find_any_startswith_string(a []string, b []string, search string) ?string {
// cannot convert 'struct _option_string' to 'struct string'
// V wants the or {} block to return a string, but find_startswith_string returns ?string
return find_startswith_string(a, search) or { find_startswith_string(b, search) }
}

fn test_main() {
deadbeef := find_any_startswith_string(['foobar', 'barfoo'], ['deadbeef', 'beefdead'],
'dead')
assert deadbeef or { panic('unreachable') } == 'deadbeef'
}

0 comments on commit e6570dd

Please sign in to comment.