cgen: fix array data for option array/fixed array(?[]u8/?[3]u8), add tests (#24847)

This commit is contained in:
Krchi 2025-07-05 17:14:02 +08:00 committed by GitHub
parent c216e59bfc
commit 52ae3f2476
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 74 additions and 5 deletions

View File

@ -627,7 +627,7 @@ fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string
if sym.kind == .function {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
} else {
if sym.kind == .array_fixed {
if !typ.has_flag(.option) && sym.kind == .array_fixed {
g.auto_str_funcs.writeln('\t\t${field_styp} it;')
g.auto_str_funcs.writeln('\t\tmemcpy(*(${field_styp}*)it, (byte*)array_get(a, i), sizeof(${field_styp}));')
} else {

View File

@ -253,12 +253,13 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
tcc_bug := c_name(node.val_var)
g.write_fn_ptr_decl(&val_sym.info, tcc_bug)
g.writeln(' = ((voidptr*)${cond_var}${op_field}data)[${i}];')
} else if val_sym.kind == .array_fixed && !node.val_is_mut {
} else if !node.val_type.has_flag(.option) && val_sym.kind == .array_fixed
&& !node.val_is_mut {
right := '((${styp}*)${cond_var}${op_field}data)[${i}]'
g.writeln('\t${styp} ${c_name(node.val_var)};')
g.writeln('\tmemcpy(*(${styp}*)${c_name(node.val_var)}, (byte*)${right}, sizeof(${styp}));')
} else {
needs_memcpy := !node.val_type.is_ptr()
needs_memcpy := !node.val_type.is_ptr() && !node.val_type.has_flag(.option)
&& g.table.final_sym(node.val_type).kind == .array_fixed
// If val is mutable (pointer behind the scenes), we need to generate
// `int* val = ((int*)arr.data) + i;`
@ -311,6 +312,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
if node.val_var != '_' {
val_sym := g.table.sym(node.val_type)
is_fixed_array := val_sym.kind == .array_fixed && !node.val_is_mut
&& !node.val_type.has_flag(.option)
if val_sym.info is ast.FnType {
g.write('\t')
tcc_bug := c_name(node.val_var)

View File

@ -371,6 +371,9 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
left_var_name := c_name(branch.cond.vars[0].name)
if is_auto_heap {
g.writeln('\t${base_type}* ${left_var_name} = HEAP(${base_type}, *(${base_type}*)${var_name}.data);')
} else if base_type.starts_with('Array_fixed') {
g.writeln('\t${base_type} ${left_var_name} = {0};')
g.writeln('memcpy(${left_var_name}, (${base_type}*)${var_name}.data, sizeof(${base_type}));')
} else {
dot_or_ptr := if !branch.cond.expr_type.has_flag(.option_mut_param_t) {
'.'

View File

@ -991,10 +991,11 @@ fn (mut g Gen) infix_expr_left_shift_op(node ast.InfixExpr) {
tmp_var := g.new_tmp_var()
array_info := left.unaliased_sym.info as ast.Array
noscan := g.check_noscan(array_info.elem_type)
elem_is_option := array_info.elem_type.has_flag(.option)
if (right.unaliased_sym.kind == .array
|| (right.unaliased_sym.kind == .struct && right.unaliased_sym.name == 'array'))
&& left.sym.nr_dims() == right.sym.nr_dims() && array_info.elem_type != right.typ
&& !(right.sym.kind == .alias
&& !elem_is_option && !(right.sym.kind == .alias
&& g.table.sumtype_has_variant(array_info.elem_type, node.right_type, false)) {
// push an array => PUSH_MANY, but not if pushing an array to 2d array (`[][]int << []int`)
g.write('_PUSH_MANY${noscan}(')
@ -1028,7 +1029,8 @@ fn (mut g Gen) infix_expr_left_shift_op(node ast.InfixExpr) {
// push a single element
elem_type_str := g.styp(array_info.elem_type)
elem_sym := g.table.final_sym(array_info.elem_type)
elem_is_array_var := elem_sym.kind in [.array, .array_fixed] && node.right is ast.Ident
elem_is_array_var := !elem_is_option && elem_sym.kind in [.array, .array_fixed]
&& node.right is ast.Ident
g.write('array_push${noscan}((array*)')
mut needs_addr := false
if !left.typ.is_ptr()

View File

@ -0,0 +1,30 @@
fn test_array_of_option_array() {
mut arr := []?[]int{}
arr1 := []int{}
arr << arr1
arr2 := [1, 2, 3]
arr << arr2
arr << none
println(arr)
for i, item in arr {
if arr_item := item {
if i == 0 {
assert arr_item == []
} else if i == 1 {
assert arr_item == [1, 2, 3]
}
} else {
assert item == none
}
}
assert arr.len == 3
assert '${arr[0]}' == 'Option([])'
assert '${arr[1]}' == 'Option([1, 2, 3])'
assert '${arr[2]}' == 'Option(none)'
}

View File

@ -0,0 +1,32 @@
module builtin_arrays
fn test_array_of_option_fixed_array() {
mut arr := []?[3]u8{}
fixed_arr1 := [3]u8{}
arr << fixed_arr1
fixed_arr2 := [u8(1), 2, 3]!
arr << fixed_arr2
arr << none
println(arr)
for i, item in arr {
if arr1 := item {
if i == 0 {
assert arr1 == [3]u8{}
} else if i == 1 {
assert arr1 == [u8(1), 2, 3]!
}
} else {
assert item == none
}
}
assert arr.len == 3
assert '${arr[0]}' == 'Option([0, 0, 0])'
assert '${arr[1]}' == 'Option([1, 2, 3])'
assert '${arr[2]}' == 'Option(none)'
}