diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index a09801e4bc..e7224f46bb 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2569,18 +2569,28 @@ fn (mut g Gen) expr_with_var(expr ast.Expr, expected_type ast.Type) string { } // expr_with_fixed_array generates code for fixed array initialization with expr which requires tmp var -fn (mut g Gen) expr_with_fixed_array(expr ast.ArrayInit, got_type_raw ast.Type, expected_type ast.Type) string { +fn (mut g Gen) expr_with_fixed_array(expr ast.Expr, got_type_raw ast.Type, expected_type ast.Type) string { stmt_str := g.go_before_last_stmt().trim_space() g.empty_line = true tmp_var := g.new_tmp_var() styp := g.styp(expected_type) - g.writeln('${styp} ${tmp_var};') - // [ foo(), foo() ]! - val_typ := g.table.value_type(got_type_raw) - for i, item_expr in expr.exprs { - g.write('memcpy(${tmp_var}[${i}], ') - g.expr(item_expr) - g.writeln(', sizeof(${g.styp(val_typ)}));') + if expr is ast.ArrayInit { + g.writeln('${styp} ${tmp_var};') + // [ foo(), foo() ]! + val_typ := g.table.value_type(got_type_raw) + for i, item_expr in expr.exprs { + g.write('memcpy(${tmp_var}[${i}], ') + g.expr(item_expr) + g.writeln(', sizeof(${g.styp(val_typ)}));') + } + } else if expr is ast.CallExpr { + // return var.call() where returns is option/result fixed array + g.writeln('${styp} ${tmp_var} = {0};') + g.write('memcpy(&${tmp_var}.data, ') + g.expr(expr) + g.writeln(', sizeof(${g.base_type(expected_type)}));') + } else { + g.expr(expr) } g.write(stmt_str) return tmp_var @@ -5792,22 +5802,46 @@ fn (mut g Gen) return_stmt(node ast.Return) { } } if fn_return_is_option && !expr_type_is_opt && return_sym.name != option_name { - styp := g.base_type(fn_ret_type) - g.writeln('${ret_typ} ${tmpvar};') - g.write('_option_ok(&(${styp}[]) { ') - if !g.unwrap_generic(fn_ret_type).is_ptr() && node.types[0].is_ptr() { - if !(node.exprs[0] is ast.Ident && !g.is_amp) { - g.write('*') + if fn_return_is_fixed_array && (expr0 in [ast.StructInit, ast.CallExpr, ast.CastExpr] + || (expr0 is ast.ArrayInit && expr0.has_callexpr)) + && g.table.final_sym(node.types[0]).kind == .array_fixed { + styp := g.styp(fn_ret_type.clear_option_and_result()) + if expr0 is ast.CallExpr { + tmp_var := g.expr_with_fixed_array(expr0, node.types[0], fn_ret_type) + g.writeln('${ret_typ} ${tmpvar} = ${tmp_var};') + } else { + g.writeln('${ret_typ} ${tmpvar} = (${ret_typ}){ .state=0, .err=_const_none__, .data={EMPTY_STRUCT_INITIALIZATION} };') + if expr0 is ast.StructInit { + g.write('memcpy(${tmpvar}.data, ') + tmp_var := g.expr_with_opt(expr0, node.types[0], fn_ret_type) + g.writeln('.data, sizeof(${styp}));') + if tmp_var != '' { + g.writeln('${tmpvar}.state = ${tmp_var}.state;') + } + } else { + g.write('memcpy(${tmpvar}.data, ') + g.expr(expr0) + g.writeln(', sizeof(${styp}));') + } } - } - if return_sym.kind == .array_fixed && expr0 !is ast.ArrayInit { - info := return_sym.info as ast.ArrayFixed - g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(), - info.elem_type, info.size) } else { - g.expr_with_cast(expr0, node.types[0], fn_ret_type.clear_option_and_result()) + g.writeln('${ret_typ} ${tmpvar};') + styp := g.base_type(fn_ret_type) + g.write('_option_ok(&(${styp}[]) { ') + if !g.unwrap_generic(fn_ret_type).is_ptr() && node.types[0].is_ptr() { + if !(node.exprs[0] is ast.Ident && !g.is_amp) { + g.write('*') + } + } + if return_sym.kind == .array_fixed && expr0 !is ast.ArrayInit { + info := return_sym.info as ast.ArrayFixed + g.fixed_array_var_init(g.expr_string(expr0), expr0.is_auto_deref_var(), + info.elem_type, info.size) + } else { + g.expr_with_cast(expr0, node.types[0], fn_ret_type.clear_option_and_result()) + } + g.writeln(' }, (${option_name}*)(&${tmpvar}), sizeof(${styp}));') } - g.writeln(' }, (${option_name}*)(&${tmpvar}), sizeof(${styp}));') g.write_defer_stmts_when_needed() g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true) g.writeln('return ${tmpvar};') diff --git a/vlib/v/gen/c/for.v b/vlib/v/gen/c/for.v index 622a4cf766..8ab703a10d 100644 --- a/vlib/v/gen/c/for.v +++ b/vlib/v/gen/c/for.v @@ -451,6 +451,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { g.writeln('\tif (${t_var}.state != 0) break;') val := if node.val_var in ['', '_'] { g.new_tmp_var() } else { node.val_var } val_styp := g.styp(ret_typ.clear_option_and_result()) + ret_is_fixed_array := g.table.sym(ret_typ).is_array_fixed() if node.val_is_mut { if ret_typ.has_flag(.option) { g.writeln('\t${val_styp}* ${val} = (${val_styp}*)${t_var}.data;') @@ -458,7 +459,12 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { g.writeln('\t${val_styp} ${val} = (${val_styp})${t_var}.data;') } } else { - g.writeln('\t${val_styp} ${val} = *(${val_styp}*)${t_var}.data;') + if ret_is_fixed_array { + g.writeln('\t${val_styp} ${val} = {0};') + g.write('\tmemcpy(${val}, ${t_var}.data, sizeof(${val_styp}));') + } else { + g.writeln('\t${val_styp} ${val} = *(${val_styp}*)${t_var}.data;') + } } } else if node.kind == .aggregate { for_type := (g.table.sym(node.cond_type).info as ast.Aggregate).types[g.aggregate_type_idx] diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index d85666c7ba..c1deba0de9 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -687,7 +687,7 @@ fn (mut g Gen) struct_init_field(sfield ast.StructInitField, language ast.Langua g.fixed_array_var_init(g.expr_string(sfield.expr), is_auto_deref_var, field_unwrap_sym.info.elem_type, field_unwrap_sym.info.size) } - ast.CallExpr { + ast.CastExpr, ast.CallExpr { tmp_var := g.expr_with_var(sfield.expr, sfield.expected_type) g.fixed_array_var_init(tmp_var, false, field_unwrap_sym.info.elem_type, field_unwrap_sym.info.size) diff --git a/vlib/v/tests/options/option_array_fixed_test.v b/vlib/v/tests/options/option_array_fixed_test.v new file mode 100644 index 0000000000..ff9fadfbbe --- /dev/null +++ b/vlib/v/tests/options/option_array_fixed_test.v @@ -0,0 +1,35 @@ +module main + +type Arr = [4]u8 + +fn foo(a int) ?Arr { + if a > 0 { + return Arr([u8(1), 2, 3, 4]!) + } + return none +} + +fn bar(a int) !Arr { + if a > 0 { + return Arr([u8(1), 2, 3, 4]!) + } + return error('') +} + +fn test_main() { + f := foo(1) or { Arr([u8(0), 0, 0, 0]!) } + dump(f) + assert f == [u8(1), 2, 3, 4]! + + ff := foo(0) + dump(ff) + assert ff == none + + b := bar(1) or { Arr([u8(0), 0, 0, 0]!) } + dump(f) + assert b == [u8(1), 2, 3, 4]! + + bb := bar(0) or { Arr([u8(0), 0, 0, 0]!) } + dump(bb) + assert bb == [u8(0), 0, 0, 0]! +} diff --git a/vlib/v/tests/options/option_fixed_array_2_test.v b/vlib/v/tests/options/option_fixed_array_2_test.v new file mode 100644 index 0000000000..7b805f8de4 --- /dev/null +++ b/vlib/v/tests/options/option_fixed_array_2_test.v @@ -0,0 +1,52 @@ +module main + +import encoding.binary + +type Addr = [4]u8 + +fn Addr.from_u32(a u32) Addr { + mut bytes := [4]u8{} + binary.big_endian_put_u32_fixed(mut bytes, a) + return Addr(bytes) +} + +fn (a Addr) str() string { + return '${a[0]}.${a[1]}.${a[2]}.${a[3]}' +} + +fn (a Addr) u32() u32 { + return binary.big_endian_u32_fixed(a) +} + +struct Net { + netaddr Addr + broadcast Addr +mut: + h u32 +} + +fn (mut n Net) next() ?Addr { + if n.h >= n.broadcast.u32() + 1 { + return none + } + defer { + n.h++ + } + return Addr.from_u32(n.h) +} + +fn test_main() { + net := Net{ + netaddr: Addr([u8(172), 16, 16, 0]!) + broadcast: Addr([u8(172), 16, 16, 3]!) + h: u32(2886733824) + } + mut rets := []string{} + for addr in net { + rets << addr.str() + } + assert rets[0] == '172.16.16.0' + assert rets[1] == '172.16.16.1' + assert rets[2] == '172.16.16.2' + assert rets[3] == '172.16.16.3' +}