diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 2fb6f8ce33..b76de4e1ee 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4965,7 +4965,7 @@ fn (mut g Gen) return_stmt(node ast.Return) { fn_return_is_multi := sym.kind == .multi_return fn_return_is_option := fn_ret_type.has_flag(.option) fn_return_is_result := fn_ret_type.has_flag(.result) - fn_return_is_fixed_array := sym.is_array_fixed() && !fn_ret_type.has_flag(.option) + fn_return_is_fixed_array := sym.is_array_fixed() && !fn_ret_type.has_option_or_result() mut has_semicolon := false if node.exprs.len == 0 { @@ -5306,7 +5306,7 @@ fn (mut g Gen) return_stmt(node ast.Return) { if g.fn_decl.return_type.has_flag(.option) { g.expr_with_opt(node.exprs[0], node.types[0], g.fn_decl.return_type) } else { - if fn_return_is_fixed_array && !node.types[0].has_flag(.option) { + if fn_return_is_fixed_array && !node.types[0].has_option_or_result() { g.writeln('{0};') if node.exprs[0] is ast.Ident { typ := if expr0.is_auto_deref_var() { @@ -6394,15 +6394,27 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast g.writeln(';') g.stmt_path_pos.delete_last() } else { + mut is_array_fixed := false if is_option { - g.write('*(${cast_typ}*) ${cvar_name}.data = ') + 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 = ') + } } 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 + if is_array_fixed { + g.write(', sizeof(${cast_typ}))') + } g.writeln(';') g.stmt_path_pos.delete_last() } diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index c8f9407db9..e34c75bd66 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -76,8 +76,8 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) { g.inside_opt_or_res = old_inside_opt_or_res } g.write(')') - if (g.inside_assign || g.expected_fixed_arr) && !expr_type.has_flag(.option) - && g.table.type_kind(expr_type) == .array_fixed { + if (g.inside_assign || g.expected_fixed_arr) && !expr_type.has_option_or_result() + && g.table.final_sym(expr_type).kind == .array_fixed { g.write('.ret_arr') } } @@ -121,7 +121,7 @@ fn (mut g Gen) dump_expr_definitions() { g.go_back(str_tdef.len) dump_typedefs['typedef ${str_tdef};'] = true str_dumparg_ret_type = str_dumparg_type - } else if !typ.has_flag(.option) && dump_sym.is_array_fixed() { + } else if !typ.has_option_or_result() && dump_sym.is_array_fixed() { match dump_sym.kind { .array_fixed { if (dump_sym.info as ast.ArrayFixed).is_fn_ret { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 2c1da74edb..7648bc3a4c 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -228,10 +228,10 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { mut type_name := g.typ(g.unwrap_generic(node.return_type)) ret_sym := g.table.sym(g.unwrap_generic(node.return_type)) - if node.return_type.has_flag(.generic) && !node.return_type.has_flag(.option) + if node.return_type.has_flag(.generic) && !node.return_type.has_option_or_result() && ret_sym.kind == .array_fixed { type_name = '_v_${type_name}' - } else if ret_sym.kind == .alias && !node.return_type.has_flag(.option) { + } else if ret_sym.kind == .alias && !node.return_type.has_option_or_result() { unalias_typ := g.table.unaliased_type(node.return_type) unalias_sym := g.table.sym(unalias_typ) if unalias_sym.kind == .array_fixed { @@ -1606,8 +1606,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.write(', ${array_depth}') } g.write(')') - if node.return_type != 0 && !node.return_type.has_flag(.option) - && !node.return_type.has_flag(.result) + if node.return_type != 0 && !node.return_type.has_option_or_result() && g.table.final_sym(node.return_type).kind == .array_fixed { // it's non-option fixed array, requires accessing .ret_arr member to get the array g.write('.ret_arr') @@ -1946,8 +1945,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { if name != '&' { g.write(')') } - if node.return_type != 0 && !node.return_type.has_flag(.option) - && !node.return_type.has_flag(.result) + if node.return_type != 0 && !node.return_type.has_option_or_result() && g.table.final_sym(node.return_type).kind == .array_fixed { // it's non-option fixed array, requires accessing .ret_arr member to get the array g.write('.ret_arr') diff --git a/vlib/v/gen/c/infix.v b/vlib/v/gen/c/infix.v index ee798e3209..0072312eb2 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -808,7 +808,7 @@ fn (mut g Gen) infix_expr_arithmetic_op(node ast.InfixExpr) { } g.write(')') - if left.typ != 0 && !left.typ.has_flag(.option) && !left.typ.has_flag(.result) + if left.typ != 0 && !left.typ.has_option_or_result() && g.table.final_sym(left.typ).kind == .array_fixed { // it's non-option fixed array, requires accessing .ret_arr member to get the array g.write('.ret_arr') diff --git a/vlib/v/tests/fixed_array_generic_ret_test.v b/vlib/v/tests/fixed_array_generic_ret_test.v index 4dcfdff300..32386af1c9 100644 --- a/vlib/v/tests/fixed_array_generic_ret_test.v +++ b/vlib/v/tests/fixed_array_generic_ret_test.v @@ -2,9 +2,20 @@ fn example[T]() ?T { return T{} } -fn test_main() { +fn test_option() { dump(example[[1]int]()) a := example[[1]int]() assert a? == [0]! } + +fn example2[T]() !T { + return T{} +} + +fn test_result() { + dump(example2[[1]int]()!) + + a := example2[[1]int]()! + assert a == [0]! +} diff --git a/vlib/v/tests/option_or_result_fixed_arr_test.v b/vlib/v/tests/option_or_result_fixed_arr_test.v new file mode 100644 index 0000000000..35b855b430 --- /dev/null +++ b/vlib/v/tests/option_or_result_fixed_arr_test.v @@ -0,0 +1,43 @@ +type Abc = [2]int + +// option +fn a() ?Abc { + return [1, 2]! +} + +fn b() ?Abc { + return none +} + +// result +fn aa() !Abc { + return [1, 2]! +} + +fn bb() !Abc { + return error('b') +} + +fn test_option() { + var_a := dump(a()?) + var_b := Abc([1, 2]!) + assert var_a == var_b +} + +fn test_result() { + var_aa := dump(aa()!) + var_bb := Abc([1, 2]!) + assert var_aa == var_bb +} + +fn test_opt_block() { + var_a := b() or { [0, 0]! } + dump(var_a) + assert var_a == Abc([0, 0]!) +} + +fn test_res_block() { + var_a := bb() or { [0, 0]! } + dump(var_a) + assert var_a == Abc([0, 0]!) +}