cgen: fix autogen free method for struct with shared field (#13469)

pull/13471/head
crthpl 2022-02-14 17:55:06 -08:00 committed by GitHub
parent 89e9f8a00c
commit e23db2f9b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 10 deletions

View File

@ -5,7 +5,8 @@ module c
import v.ast import v.ast
import strings import strings
fn (mut g Gen) gen_free_method_for_type(typ ast.Type) string { fn (mut g Gen) get_free_method(typ ast.Type) string {
g.autofree_methods[typ] = true
styp := g.typ(typ).replace('*', '') styp := g.typ(typ).replace('*', '')
mut sym := g.table.sym(g.unwrap_generic(typ)) mut sym := g.table.sym(g.unwrap_generic(typ))
mut fn_name := styp_to_free_fn_name(styp) mut fn_name := styp_to_free_fn_name(styp)
@ -15,6 +16,32 @@ fn (mut g Gen) gen_free_method_for_type(typ ast.Type) string {
} }
} }
if sym.has_method_with_generic_parent('free') {
return fn_name
}
return fn_name
}
fn (mut g Gen) gen_free_methods() {
for typ, _ in g.autofree_methods {
g.gen_free_method(typ)
}
}
fn (mut g Gen) gen_free_method(typ ast.Type) string {
styp := g.typ(typ).replace('*', '')
mut sym := g.table.sym(g.unwrap_generic(typ))
mut fn_name := styp_to_free_fn_name(styp)
if typ in g.generated_free_methods {
return fn_name
}
g.generated_free_methods[typ] = true
if mut sym.info is ast.Alias {
if sym.info.is_import {
sym = g.table.sym(sym.info.parent_type)
}
}
if sym.has_method_with_generic_parent('free') { if sym.has_method_with_generic_parent('free') {
return fn_name return fn_name
} }
@ -50,12 +77,20 @@ fn (mut g Gen) gen_free_for_struct(info ast.Struct, styp string, fn_name string)
continue continue
} }
mut field_styp := g.typ(field.typ).replace('*', '') mut field_styp := g.typ(field.typ).replace('*', '')
is_shared := field_styp.starts_with('__shared')
if is_shared {
field_styp = field_styp.all_after('__shared__')
}
field_styp_fn_name := if sym.has_method('free') { field_styp_fn_name := if sym.has_method('free') {
'${field_styp}_free' '${field_styp}_free'
} else { } else {
g.gen_free_method_for_type(field.typ) g.gen_free_method(field.typ)
}
if is_shared {
fn_builder.writeln('\t${field_styp_fn_name}(&(it->$field.name->val));')
} else {
fn_builder.writeln('\t${field_styp_fn_name}(&(it->$field.name));')
} }
fn_builder.writeln('\t${field_styp_fn_name}(&(it->$field.name));')
} }
fn_builder.writeln('}') fn_builder.writeln('}')
} }
@ -76,7 +111,7 @@ fn (mut g Gen) gen_free_for_array(info ast.Array, styp string, fn_name string) {
elem_styp_fn_name := if sym.has_method('free') { elem_styp_fn_name := if sym.has_method('free') {
'${elem_styp}_free' '${elem_styp}_free'
} else { } else {
g.gen_free_method_for_type(info.elem_type) g.gen_free_method(info.elem_type)
} }
fn_builder.writeln('\t\t${elem_styp_fn_name}(&((($elem_styp*)it->data)[i]));') fn_builder.writeln('\t\t${elem_styp_fn_name}(&((($elem_styp*)it->data)[i]));')
fn_builder.writeln('\t}') fn_builder.writeln('\t}')

View File

@ -196,10 +196,12 @@ mut:
tests_inited bool tests_inited bool
has_main bool has_main bool
// main_fn_decl_node ast.FnDecl // main_fn_decl_node ast.FnDecl
cur_mod ast.Module cur_mod ast.Module
cur_concrete_types []ast.Type // do not use table.cur_concrete_types because table is global, so should not be accessed by different threads cur_concrete_types []ast.Type // do not use table.cur_concrete_types because table is global, so should not be accessed by different threads
cur_fn &ast.FnDecl = 0 // same here cur_fn &ast.FnDecl = 0 // same here
cur_lock ast.LockExpr cur_lock ast.LockExpr
autofree_methods map[int]bool
generated_free_methods map[int]bool
} }
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
@ -346,6 +348,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.json_types << g.json_types global_g.json_types << g.json_types
global_g.hotcode_fn_names << g.hotcode_fn_names global_g.hotcode_fn_names << g.hotcode_fn_names
unsafe { g.free_builders() } unsafe { g.free_builders() }
for k, v in g.autofree_methods {
global_g.autofree_methods[k] = v
}
} }
} else { } else {
for file in files { for file in files {
@ -374,6 +379,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.gen_array_contains_methods() global_g.gen_array_contains_methods()
global_g.gen_array_index_methods() global_g.gen_array_index_methods()
global_g.gen_equality_fns() global_g.gen_equality_fns()
global_g.gen_free_methods()
global_g.timers.show('cgen unification') global_g.timers.show('cgen unification')
mut g := global_g mut g := global_g

View File

@ -911,7 +911,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
if rec_type.has_flag(.shared_f) { if rec_type.has_flag(.shared_f) {
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0) rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
} }
g.gen_free_method_for_type(rec_type) g.get_free_method(rec_type)
} }
mut has_cast := false mut has_cast := false
if left_sym.kind == .map && node.name in ['clone', 'move'] { if left_sym.kind == .map && node.name in ['clone', 'move'] {

View File

@ -1,6 +1,6 @@
struct Info { struct Info {
name string name string
notes []string notes shared []string
maps map[int]int maps map[int]int
info []SubInfo info []SubInfo
} }
@ -15,3 +15,9 @@ fn test_autogen_free() {
info.free() info.free()
assert true assert true
} }
fn test_multiple_autogen_free() {
info := &Info{}
info.free()
assert true
}