diff --git a/vlib/v/gen/c/auto_free_methods.v b/vlib/v/gen/c/auto_free_methods.v index 4e41ee2918..a30c6175ac 100644 --- a/vlib/v/gen/c/auto_free_methods.v +++ b/vlib/v/gen/c/auto_free_methods.v @@ -5,7 +5,8 @@ module c import v.ast 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('*', '') mut sym := g.table.sym(g.unwrap_generic(typ)) 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') { return fn_name } @@ -50,12 +77,20 @@ fn (mut g Gen) gen_free_for_struct(info ast.Struct, styp string, fn_name string) continue } 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}_free' } 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('}') } @@ -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}_free' } 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}') diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 9bf5ebd32b..17e8cea70d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -196,10 +196,12 @@ mut: tests_inited bool has_main bool // main_fn_decl_node ast.FnDecl - 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_fn &ast.FnDecl = 0 // same here - cur_lock ast.LockExpr + 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_fn &ast.FnDecl = 0 // same here + 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 { @@ -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.hotcode_fn_names << g.hotcode_fn_names unsafe { g.free_builders() } + for k, v in g.autofree_methods { + global_g.autofree_methods[k] = v + } } } else { 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_index_methods() global_g.gen_equality_fns() + global_g.gen_free_methods() global_g.timers.show('cgen unification') mut g := global_g diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index dbf23844b9..863fe8c21f 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -911,7 +911,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { if rec_type.has_flag(.shared_f) { 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 if left_sym.kind == .map && node.name in ['clone', 'move'] { diff --git a/vlib/v/tests/autogen_free_test.v b/vlib/v/tests/autogen_free_test.v index e2de36e318..73def0c6a1 100644 --- a/vlib/v/tests/autogen_free_test.v +++ b/vlib/v/tests/autogen_free_test.v @@ -1,6 +1,6 @@ struct Info { name string - notes []string + notes shared []string maps map[int]int info []SubInfo } @@ -15,3 +15,9 @@ fn test_autogen_free() { info.free() assert true } + +fn test_multiple_autogen_free() { + info := &Info{} + info.free() + assert true +}