From e6570ddcf9208889adfe5f45869073e1305fd009 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Tue, 6 Feb 2024 09:05:25 -0300 Subject: [PATCH] cgen: fix return with option on orexpr (#20728) --- vlib/v/gen/c/cgen.v | 23 +++++++++++++++++------ vlib/v/tests/option_call_on_orexpr_test.v | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 vlib/v/tests/option_call_on_orexpr_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index ed917c85a3..6da3921f15 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -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}))') } diff --git a/vlib/v/tests/option_call_on_orexpr_test.v b/vlib/v/tests/option_call_on_orexpr_test.v new file mode 100644 index 0000000000..594212f4aa --- /dev/null +++ b/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' +}