diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index ed917c85a3e4e1..6da3921f153c53 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 00000000000000..594212f4aa600d --- /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' +}