cgen: fix codegen for returning option aliased fixed array (fix #22910, fix #22911) (#22912)

This commit is contained in:
Felipe Pena 2024-11-20 05:54:55 -03:00 committed by GitHub
parent 26837d4862
commit 2fbb3df9fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 150 additions and 23 deletions

View File

@ -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 // 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() stmt_str := g.go_before_last_stmt().trim_space()
g.empty_line = true g.empty_line = true
tmp_var := g.new_tmp_var() tmp_var := g.new_tmp_var()
styp := g.styp(expected_type) styp := g.styp(expected_type)
g.writeln('${styp} ${tmp_var};') if expr is ast.ArrayInit {
// [ foo(), foo() ]! g.writeln('${styp} ${tmp_var};')
val_typ := g.table.value_type(got_type_raw) // [ foo(), foo() ]!
for i, item_expr in expr.exprs { val_typ := g.table.value_type(got_type_raw)
g.write('memcpy(${tmp_var}[${i}], ') for i, item_expr in expr.exprs {
g.expr(item_expr) g.write('memcpy(${tmp_var}[${i}], ')
g.writeln(', sizeof(${g.styp(val_typ)}));') 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) g.write(stmt_str)
return tmp_var 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 { if fn_return_is_option && !expr_type_is_opt && return_sym.name != option_name {
styp := g.base_type(fn_ret_type) if fn_return_is_fixed_array && (expr0 in [ast.StructInit, ast.CallExpr, ast.CastExpr]
g.writeln('${ret_typ} ${tmpvar};') || (expr0 is ast.ArrayInit && expr0.has_callexpr))
g.write('_option_ok(&(${styp}[]) { ') && g.table.final_sym(node.types[0]).kind == .array_fixed {
if !g.unwrap_generic(fn_ret_type).is_ptr() && node.types[0].is_ptr() { styp := g.styp(fn_ret_type.clear_option_and_result())
if !(node.exprs[0] is ast.Ident && !g.is_amp) { if expr0 is ast.CallExpr {
g.write('*') 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 { } 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.write_defer_stmts_when_needed()
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true) g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
g.writeln('return ${tmpvar};') g.writeln('return ${tmpvar};')

View File

@ -451,6 +451,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
g.writeln('\tif (${t_var}.state != 0) break;') g.writeln('\tif (${t_var}.state != 0) break;')
val := if node.val_var in ['', '_'] { g.new_tmp_var() } else { node.val_var } val := if node.val_var in ['', '_'] { g.new_tmp_var() } else { node.val_var }
val_styp := g.styp(ret_typ.clear_option_and_result()) 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 node.val_is_mut {
if ret_typ.has_flag(.option) { if ret_typ.has_flag(.option) {
g.writeln('\t${val_styp}* ${val} = (${val_styp}*)${t_var}.data;') 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;') g.writeln('\t${val_styp} ${val} = (${val_styp})${t_var}.data;')
} }
} else { } 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 { } else if node.kind == .aggregate {
for_type := (g.table.sym(node.cond_type).info as ast.Aggregate).types[g.aggregate_type_idx] for_type := (g.table.sym(node.cond_type).info as ast.Aggregate).types[g.aggregate_type_idx]

View File

@ -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, 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) 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) 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, g.fixed_array_var_init(tmp_var, false, field_unwrap_sym.info.elem_type,
field_unwrap_sym.info.size) field_unwrap_sym.info.size)

View File

@ -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]!
}

View File

@ -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'
}