1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

builtin, cgen: fix array of struct with map field initialize (fix #17325) (#17340)

This commit is contained in:
yuyi 2023-02-19 02:34:15 +08:00 committed by GitHub
parent 8011121d43
commit 93a3f5ff7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 0 deletions

View File

@ -78,6 +78,33 @@ fn __new_array_with_default(mylen int, cap int, elm_size int, val voidptr) array
return arr
}
fn __new_array_with_multi_default(mylen int, cap int, elm_size int, val voidptr) array {
cap_ := if cap < mylen { mylen } else { cap }
mut arr := array{
element_size: elm_size
len: mylen
cap: cap_
}
// x := []EmptyStruct{cap:5} ; for clang/gcc with -gc none,
// -> sizeof(EmptyStruct) == 0 -> elm_size == 0
// -> total_size == 0 -> malloc(0) -> panic;
// to avoid it, just allocate a single byte
total_size := u64(cap_) * u64(elm_size)
arr.data = vcalloc(__at_least_one(total_size))
if val != 0 {
mut eptr := &u8(arr.data)
unsafe {
if eptr != nil {
for i in 0 .. arr.len {
vmemcpy(eptr, charptr(val) + i * arr.element_size, arr.element_size)
eptr += arr.element_size
}
}
}
}
return arr
}
fn __new_array_with_array_default(mylen int, cap int, elm_size int, val array, depth int) array {
cap_ := if cap < mylen { mylen } else { cap }
mut arr := array{

View File

@ -42,6 +42,22 @@ fn __new_array_with_default_noscan(mylen int, cap int, elm_size int, val voidptr
return arr
}
fn __new_array_with_multi_default_noscan(mylen int, cap int, elm_size int, val voidptr) array {
cap_ := if cap < mylen { mylen } else { cap }
mut arr := array{
element_size: elm_size
data: vcalloc_noscan(u64(cap_) * u64(elm_size))
len: mylen
cap: cap_
}
if val != 0 && arr.data != unsafe { nil } {
for i in 0 .. arr.len {
unsafe { arr.set_unsafe(i, charptr(val) + i * elm_size) }
}
}
return arr
}
fn __new_array_with_array_default_noscan(mylen int, cap int, elm_size int, val array) array {
cap_ := if cap < mylen { mylen } else { cap }
mut arr := array{

View File

@ -13,6 +13,10 @@ fn __new_array_with_default_noscan(mylen int, cap int, elm_size int, val voidptr
return __new_array_with_default(mylen, cap, elm_size, val)
}
fn __new_array_with_multi_default_noscan(mylen int, cap int, elm_size int, val voidptr) array {
return __new_array_with_multi_default(mylen, cap, elm_size, val)
}
fn __new_array_with_array_default_noscan(mylen int, cap int, elm_size int, val array, depth int) array {
return __new_array_with_array_default(mylen, cap, elm_size, val, depth)
}

View File

@ -1607,3 +1607,27 @@ fn test_using_array_name_variable() {
println(array)
assert array == [0, 1, 2, 3]
}
struct Data {
mut:
sub_map map[int]int
}
fn test_array_of_struct_with_map_field() {
n := 3
mut arr := []Data{len: n}
for i, mut a in arr {
arr[i].sub_map[i] = 1
a.sub_map[i] += 1
}
println(arr)
assert arr[0].sub_map == {
0: 2
}
assert arr[1].sub_map == {
1: 2
}
assert arr[2].sub_map == {
2: 2
}
}

View File

@ -175,12 +175,27 @@ fn (mut g Gen) fixed_array_init(node ast.ArrayInit, array_type Type, var_name st
}
}
fn (mut g Gen) struct_has_array_or_map_field(elem_typ ast.Type) bool {
unaliased_sym := g.table.final_sym(elem_typ)
if unaliased_sym.kind == .struct_ {
info := unaliased_sym.info as ast.Struct
for field in info.fields {
field_sym := g.table.final_sym(field.typ)
if field_sym.kind in [.array, .map] {
return true
}
}
}
return false
}
// `[]int{len: 6, cap: 10, init: it * it}`
fn (mut g Gen) array_init_with_fields(node ast.ArrayInit, elem_type Type, is_amp bool, shared_styp string, var_name string) {
elem_styp := g.typ(elem_type.typ)
noscan := g.check_noscan(elem_type.typ)
is_default_array := elem_type.unaliased_sym.kind == .array && node.has_default
is_default_map := elem_type.unaliased_sym.kind == .map && node.has_default
needs_more_defaults := node.has_len && g.struct_has_array_or_map_field(elem_type.typ)
if node.has_it { // []int{len: 6, init: it * it} when variable it is used in init expression
g.inside_lambda = true
mut tmp := g.new_tmp_var()
@ -278,6 +293,8 @@ fn (mut g Gen) array_init_with_fields(node ast.ArrayInit, elem_type Type, is_amp
g.write('__new_array_with_array_default${noscan}(')
} else if is_default_map {
g.write('__new_array_with_map_default${noscan}(')
} else if needs_more_defaults {
g.write('__new_array_with_multi_default${noscan}(')
} else {
g.write('__new_array_with_default${noscan}(')
}
@ -312,6 +329,27 @@ fn (mut g Gen) array_init_with_fields(node ast.ArrayInit, elem_type Type, is_amp
g.write('(${elem_styp}[]){')
g.expr(node.default_expr)
g.write('}[0])')
} else if needs_more_defaults {
tmp := g.new_tmp_var()
line := g.go_before_stmt(0).trim_space()
g.empty_line = true
g.write('${elem_styp}* ${tmp} = malloc((')
g.expr(node.len_expr)
g.writeln(') * sizeof(${elem_styp}));')
ind := g.new_tmp_var()
g.write('for (int ${ind}=0; ${ind}<')
g.expr(node.len_expr)
g.writeln('; ${ind}++) {')
g.write('\t${tmp}[${ind}] = ')
if node.has_default {
g.expr_with_cast(node.default_expr, node.default_type, node.elem_type)
} else {
g.write(g.type_default(node.elem_type))
}
g.writeln(';')
g.writeln('}')
g.write(line)
g.write(' (voidptr)${tmp})')
} else if node.has_default {
g.write('&(${elem_styp}[]){')
g.expr_with_cast(node.default_expr, node.default_type, node.elem_type)

View File

@ -20,6 +20,7 @@ pub fn mark_used(mut table ast.Table, pref_ &pref.Preferences, ast_files []&ast.
'str_intp',
'format_sb',
'__new_array_with_default',
'__new_array_with_multi_default',
'__new_array_with_array_default',
'init_global_allocator' /* needed for linux_bare and wasm_bare */,
'v_realloc' /* needed for _STR */,