From 695dcb2ff8486838b2faf1d25d1ffd0f1230ec23 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 17 Oct 2024 15:09:31 -0300 Subject: [PATCH 1/7] fix --- vlib/v/gen/c/assign.v | 11 +++++--- vlib/v/gen/c/auto_free_methods.v | 28 ++++++++++++++++++- .../testdata/interface_auto_free.c.must_have | 20 +++++++++++++ vlib/v/gen/c/testdata/interface_auto_free.vv | 20 +++++++++++++ 4 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 vlib/v/gen/c/testdata/interface_auto_free.c.must_have create mode 100644 vlib/v/gen/c/testdata/interface_auto_free.vv diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 18e3694cedfe7b..7bfc255c711635 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -723,10 +723,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { g.write(', ') } mut cloned := false - if g.is_autofree && right_sym.kind in [.array, .string] - && !unwrapped_val_type.has_flag(.shared_f) { - if g.gen_clone_assignment(var_type, val, unwrapped_val_type, false) { - cloned = true + if g.is_autofree { + if right_sym.kind in [.array, .string] && !unwrapped_val_type.has_flag(.shared_f) { + if g.gen_clone_assignment(var_type, val, unwrapped_val_type, false) { + cloned = true + } + } else if right_sym.kind == .interface { + g.get_free_method(var_type) } } if !cloned { diff --git a/vlib/v/gen/c/auto_free_methods.v b/vlib/v/gen/c/auto_free_methods.v index 18606ce1069ce1..a4cce176424d4c 100644 --- a/vlib/v/gen/c/auto_free_methods.v +++ b/vlib/v/gen/c/auto_free_methods.v @@ -43,7 +43,7 @@ fn (mut g Gen) gen_free_method(typ ast.Type) string { sym = g.table.sym(sym.info.parent_type) } } - if sym.has_method_with_generic_parent('free') { + if sym.kind != .interface && sym.has_method_with_generic_parent('free') { return fn_name } @@ -57,6 +57,9 @@ fn (mut g Gen) gen_free_method(typ ast.Type) string { ast.Map { g.gen_free_for_map(objtyp, sym.info, styp, fn_name) } + ast.Interface { + g.gen_free_for_interface(sym, sym.info, styp, fn_name) + } else { println(g.table.type_str(typ)) // print_backtrace() @@ -67,6 +70,29 @@ fn (mut g Gen) gen_free_method(typ ast.Type) string { return fn_name } +fn (mut g Gen) gen_free_for_interface(sym ast.TypeSymbol, info ast.Interface, styp string, fn_name string) { + g.definitions.writeln('${g.static_modifier} void ${fn_name}(${styp}* it); // auto') + mut fn_builder := strings.new_builder(128) + defer { + g.auto_fn_definitions << fn_builder.str() + } + fn_builder.writeln('${g.static_modifier} void ${fn_name}(${styp}* it) {') + fn_builder.writeln('\tswitch (it->_typ) {') + for t in info.types { + sub_sym := g.table.sym(ast.mktyp(t)) + if sub_sym.kind !in [.string, .array, .map, .struct] { + continue + } + fn_name_typ := g.get_free_method(t) + fn_builder.writeln('\t\tcase _${sym.cname}_${sub_sym.cname}_index:') + fn_builder.writeln('\t\t\t${fn_name_typ}(it);') + fn_builder.writeln('\t\t\tbreak;') + } + fn_builder.writeln('\t\tdefault:') + fn_builder.writeln('\t}') + fn_builder.writeln('}') +} + fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, fn_name string) { g.definitions.writeln('${g.static_modifier} void ${fn_name}(${styp}* it); // auto') mut fn_builder := strings.new_builder(128) diff --git a/vlib/v/gen/c/testdata/interface_auto_free.c.must_have b/vlib/v/gen/c/testdata/interface_auto_free.c.must_have new file mode 100644 index 00000000000000..8546d66ab5d83e --- /dev/null +++ b/vlib/v/gen/c/testdata/interface_auto_free.c.must_have @@ -0,0 +1,20 @@ + void main__IFoo_free(main__IFoo* it) { + switch (it->_typ) { + case _main__IFoo_main__Foo_index: + main__Foo_free(it); + break; + case _main__IFoo_array_index: + array_free(it); + break; + case _main__IFoo_map_index: + map_free(it); + break; + case _main__IFoo_VAssertMetaInfo_index: + VAssertMetaInfo_free(it); + break; + case _main__IFoo_MessageError_index: + MessageError_free(it); + break; + default: + } +} \ No newline at end of file diff --git a/vlib/v/gen/c/testdata/interface_auto_free.vv b/vlib/v/gen/c/testdata/interface_auto_free.vv new file mode 100644 index 00000000000000..c33f61558eca8f --- /dev/null +++ b/vlib/v/gen/c/testdata/interface_auto_free.vv @@ -0,0 +1,20 @@ +// vtest vflags: -autofree +module main + +interface IFoo { + free() +} + +struct Bar { + a int +} + +struct Foo implements IFoo { + Bar +} + +fn (f &Foo) free() {} + +fn main() { + a := IFoo(Foo{}) +} From c3cc8ff392106c273a07f92351bcbbebe7b01ba3 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 17 Oct 2024 16:01:23 -0300 Subject: [PATCH 2/7] fix --- vlib/v/gen/c/auto_free_methods.v | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/vlib/v/gen/c/auto_free_methods.v b/vlib/v/gen/c/auto_free_methods.v index a4cce176424d4c..d1196dcf97e491 100644 --- a/vlib/v/gen/c/auto_free_methods.v +++ b/vlib/v/gen/c/auto_free_methods.v @@ -77,19 +77,14 @@ fn (mut g Gen) gen_free_for_interface(sym ast.TypeSymbol, info ast.Interface, st g.auto_fn_definitions << fn_builder.str() } fn_builder.writeln('${g.static_modifier} void ${fn_name}(${styp}* it) {') - fn_builder.writeln('\tswitch (it->_typ) {') for t in info.types { sub_sym := g.table.sym(ast.mktyp(t)) if sub_sym.kind !in [.string, .array, .map, .struct] { continue } fn_name_typ := g.get_free_method(t) - fn_builder.writeln('\t\tcase _${sym.cname}_${sub_sym.cname}_index:') - fn_builder.writeln('\t\t\t${fn_name_typ}(it);') - fn_builder.writeln('\t\t\tbreak;') + fn_builder.writeln('\tif (it->_typ == _${sym.cname}_${sub_sym.cname}_index) { ${fn_name_typ}(it); return; }') } - fn_builder.writeln('\t\tdefault:') - fn_builder.writeln('\t}') fn_builder.writeln('}') } From 6577374831faf59be532b812ca3bf587ec6fa487 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 17 Oct 2024 16:12:16 -0300 Subject: [PATCH 3/7] fix test --- .../testdata/interface_auto_free.c.must_have | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/vlib/v/gen/c/testdata/interface_auto_free.c.must_have b/vlib/v/gen/c/testdata/interface_auto_free.c.must_have index 8546d66ab5d83e..01ded274dcf830 100644 --- a/vlib/v/gen/c/testdata/interface_auto_free.c.must_have +++ b/vlib/v/gen/c/testdata/interface_auto_free.c.must_have @@ -1,20 +1,7 @@ void main__IFoo_free(main__IFoo* it) { - switch (it->_typ) { - case _main__IFoo_main__Foo_index: - main__Foo_free(it); - break; - case _main__IFoo_array_index: - array_free(it); - break; - case _main__IFoo_map_index: - map_free(it); - break; - case _main__IFoo_VAssertMetaInfo_index: - VAssertMetaInfo_free(it); - break; - case _main__IFoo_MessageError_index: - MessageError_free(it); - break; - default: - } + if (it->_typ == _main__IFoo_main__Foo_index) { main__Foo_free(it); return; } + if (it->_typ == _main__IFoo_array_index) { array_free(it); return; } + if (it->_typ == _main__IFoo_map_index) { map_free(it); return; } + if (it->_typ == _main__IFoo_VAssertMetaInfo_index) { VAssertMetaInfo_free(it); return; } + if (it->_typ == _main__IFoo_MessageError_index) { MessageError_free(it); return; } } \ No newline at end of file From 07409297dde5989d30a34c912f5e18f051956131 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 17 Oct 2024 17:05:44 -0300 Subject: [PATCH 4/7] fix --- vlib/v/gen/c/assign.v | 8 +++++++- vlib/v/gen/c/auto_free_methods.v | 13 +++++++++---- vlib/v/gen/c/cgen.v | 2 +- .../gen/c/testdata/interface_auto_free.c.must_have | 12 ++++++------ 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 7bfc255c711635..874670b9c2caf1 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -729,7 +729,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { cloned = true } } else if right_sym.kind == .interface { - g.get_free_method(var_type) + if g.table.type_to_str(var_type) != 'IError' { + if var_type.has_flag(.shared_f) { + g.get_free_method(var_type.clear_flag(.shared_f).set_nr_muls(0)) + } else { + g.get_free_method(var_type) + } + } } } if !cloned { diff --git a/vlib/v/gen/c/auto_free_methods.v b/vlib/v/gen/c/auto_free_methods.v index d1196dcf97e491..223d473112d3a6 100644 --- a/vlib/v/gen/c/auto_free_methods.v +++ b/vlib/v/gen/c/auto_free_methods.v @@ -6,7 +6,9 @@ import v.ast import strings fn (mut g Gen) get_free_method(typ ast.Type) string { - g.autofree_methods[typ] = true + if typ in g.autofree_methods { + return g.autofree_methods[typ] + } mut sym := g.table.sym(g.unwrap_generic(typ)) if mut sym.info is ast.Alias { if sym.info.is_import { @@ -16,8 +18,10 @@ fn (mut g Gen) get_free_method(typ ast.Type) string { styp := g.typ(typ).replace('*', '') fn_name := styp_to_free_fn_name(styp) if sym.has_method_with_generic_parent('free') { + g.autofree_methods[typ] = fn_name return fn_name } + g.autofree_methods[typ] = fn_name return fn_name } @@ -78,12 +82,13 @@ fn (mut g Gen) gen_free_for_interface(sym ast.TypeSymbol, info ast.Interface, st } fn_builder.writeln('${g.static_modifier} void ${fn_name}(${styp}* it) {') for t in info.types { - sub_sym := g.table.sym(ast.mktyp(t)) + typ_ := g.unwrap_generic(t) + sub_sym := g.table.sym(typ_) if sub_sym.kind !in [.string, .array, .map, .struct] { continue } - fn_name_typ := g.get_free_method(t) - fn_builder.writeln('\tif (it->_typ == _${sym.cname}_${sub_sym.cname}_index) { ${fn_name_typ}(it); return; }') + fn_name_typ := g.get_free_method(typ_) + fn_builder.writeln('\tif (it->_typ == _${sym.cname}_${sub_sym.cname}_index) { ${fn_name_typ}(it->_${sub_sym.cname}); return; }') } fn_builder.writeln('}') } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 6f24e11518de4b..a956b057b704f1 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -245,7 +245,7 @@ mut: cur_fn &ast.FnDecl = unsafe { nil } // same here cur_lock ast.LockExpr cur_struct_init_typ ast.Type - autofree_methods map[int]bool + autofree_methods map[int]string generated_free_methods map[int]bool autofree_scope_stmts []string use_segfault_handler bool = true diff --git a/vlib/v/gen/c/testdata/interface_auto_free.c.must_have b/vlib/v/gen/c/testdata/interface_auto_free.c.must_have index 01ded274dcf830..41d8ea445035d7 100644 --- a/vlib/v/gen/c/testdata/interface_auto_free.c.must_have +++ b/vlib/v/gen/c/testdata/interface_auto_free.c.must_have @@ -1,7 +1,7 @@ - void main__IFoo_free(main__IFoo* it) { - if (it->_typ == _main__IFoo_main__Foo_index) { main__Foo_free(it); return; } - if (it->_typ == _main__IFoo_array_index) { array_free(it); return; } - if (it->_typ == _main__IFoo_map_index) { map_free(it); return; } - if (it->_typ == _main__IFoo_VAssertMetaInfo_index) { VAssertMetaInfo_free(it); return; } - if (it->_typ == _main__IFoo_MessageError_index) { MessageError_free(it); return; } +void main__IFoo_free(main__IFoo* it) { + if (it->_typ == _main__IFoo_main__Foo_index) { main__Foo_free(it->_main__Foo); return; } + if (it->_typ == _main__IFoo_array_index) { array_free(it->_array); return; } + if (it->_typ == _main__IFoo_map_index) { map_free(it->_map); return; } + if (it->_typ == _main__IFoo_VAssertMetaInfo_index) { VAssertMetaInfo_free(it->_VAssertMetaInfo); return; } + if (it->_typ == _main__IFoo_MessageError_index) { MessageError_free(it->_MessageError); return; } } \ No newline at end of file From cf11ddcc0d72491973556c22c9d2be617c7d2c7e Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Fri, 18 Oct 2024 14:34:19 -0300 Subject: [PATCH 5/7] fix --- vlib/v/gen/c/assign.v | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 874670b9c2caf1..d411f3683f35a2 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -728,13 +728,19 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { if g.gen_clone_assignment(var_type, val, unwrapped_val_type, false) { cloned = true } - } else if right_sym.kind == .interface { + } else if right_sym.info is ast.Interface { if g.table.type_to_str(var_type) != 'IError' { + // register interface types free method if var_type.has_flag(.shared_f) { g.get_free_method(var_type.clear_flag(.shared_f).set_nr_muls(0)) } else { g.get_free_method(var_type) } + for typ in right_sym.info.types { + if g.table.type_kind(typ) in [.struct, .placeholder] { + g.get_free_method(typ) + } + } } } } From 9824633eec6ea9cc6bc79f1fa767ae2f9f6647f9 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Fri, 18 Oct 2024 16:54:57 -0300 Subject: [PATCH 6/7] fix --- vlib/v/gen/c/auto_free_methods.v | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/vlib/v/gen/c/auto_free_methods.v b/vlib/v/gen/c/auto_free_methods.v index 223d473112d3a6..0afac684840593 100644 --- a/vlib/v/gen/c/auto_free_methods.v +++ b/vlib/v/gen/c/auto_free_methods.v @@ -87,7 +87,12 @@ fn (mut g Gen) gen_free_for_interface(sym ast.TypeSymbol, info ast.Interface, st if sub_sym.kind !in [.string, .array, .map, .struct] { continue } - fn_name_typ := g.get_free_method(typ_) + field_styp := g.gen_type_name_for_free_call(typ_) + fn_name_typ := if sub_sym.has_method('free') { + '${field_styp}_free' + } else { + g.gen_free_method(typ_) + } fn_builder.writeln('\tif (it->_typ == _${sym.cname}_${sub_sym.cname}_index) { ${fn_name_typ}(it->_${sub_sym.cname}); return; }') } fn_builder.writeln('}') @@ -107,13 +112,8 @@ fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, f if sym.kind !in [.string, .array, .map, .struct] { continue } - mut field_styp := g.typ(field.typ.set_nr_muls(0).clear_flag(.option)).replace('*', - '') - is_shared := field_styp.starts_with('__shared') + field_styp := g.gen_type_name_for_free_call(field.typ) is_struct_option := typ.has_flag(.option) - if is_shared { - field_styp = field_styp.all_after('__shared__') - } field_styp_fn_name := if sym.has_method('free') { '${field_styp}_free' } else { @@ -121,7 +121,7 @@ fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, f } is_field_option := field.typ.has_flag(.option) expects_opt := field_styp_fn_name.starts_with('_option_') - if is_shared { + if field.typ.has_flag(.shared_f) { fn_builder.writeln('\t${field_styp_fn_name}(&(it->${field_name}->val));') } else if is_struct_option { opt_styp := g.base_type(typ) @@ -152,6 +152,14 @@ fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, f fn_builder.writeln('}') } +fn (mut g Gen) gen_type_name_for_free_call(typ ast.Type) string { + mut styp := g.typ(typ.set_nr_muls(0).clear_flag(.option)).replace('*', '') + if styp.starts_with('__shared') { + styp = styp.all_after('__shared__') + } + return styp +} + fn (mut g Gen) gen_free_for_array(info ast.Array, styp string, fn_name string) { g.definitions.writeln('${g.static_modifier} void ${fn_name}(${styp}* it); // auto') mut fn_builder := strings.new_builder(128) From 86d59fd01a5cb5a942b94beebdff65c7c56849be Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 20 Oct 2024 08:39:08 -0300 Subject: [PATCH 7/7] cleanup --- vlib/v/gen/c/assign.v | 16 ++-------------- vlib/v/gen/c/auto_free_methods.v | 19 +++++++++++++------ vlib/v/gen/c/fn.v | 6 +----- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index d411f3683f35a2..557f206419e0fe 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -728,20 +728,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { if g.gen_clone_assignment(var_type, val, unwrapped_val_type, false) { cloned = true } - } else if right_sym.info is ast.Interface { - if g.table.type_to_str(var_type) != 'IError' { - // register interface types free method - if var_type.has_flag(.shared_f) { - g.get_free_method(var_type.clear_flag(.shared_f).set_nr_muls(0)) - } else { - g.get_free_method(var_type) - } - for typ in right_sym.info.types { - if g.table.type_kind(typ) in [.struct, .placeholder] { - g.get_free_method(typ) - } - } - } + } else if right_sym.info is ast.Interface && var_type != ast.error_type { + g.register_free_method(var_type) } } if !cloned { diff --git a/vlib/v/gen/c/auto_free_methods.v b/vlib/v/gen/c/auto_free_methods.v index 0afac684840593..24fcea577d35cc 100644 --- a/vlib/v/gen/c/auto_free_methods.v +++ b/vlib/v/gen/c/auto_free_methods.v @@ -5,6 +5,15 @@ module c import v.ast import strings +@[inline] +fn (mut g Gen) register_free_method(typ ast.Type) { + if typ.has_flag(.shared_f) { + g.get_free_method(typ.clear_flag(.shared_f).set_nr_muls(0)) + } else { + g.get_free_method(typ) + } +} + fn (mut g Gen) get_free_method(typ ast.Type) string { if typ in g.autofree_methods { return g.autofree_methods[typ] @@ -87,13 +96,11 @@ fn (mut g Gen) gen_free_for_interface(sym ast.TypeSymbol, info ast.Interface, st if sub_sym.kind !in [.string, .array, .map, .struct] { continue } - field_styp := g.gen_type_name_for_free_call(typ_) - fn_name_typ := if sub_sym.has_method('free') { - '${field_styp}_free' - } else { - g.gen_free_method(typ_) + if !sub_sym.has_method_with_generic_parent('free') { + continue } - fn_builder.writeln('\tif (it->_typ == _${sym.cname}_${sub_sym.cname}_index) { ${fn_name_typ}(it->_${sub_sym.cname}); return; }') + type_styp := g.gen_type_name_for_free_call(typ_) + fn_builder.writeln('\tif (it->_typ == _${sym.cname}_${sub_sym.cname}_index) { ${type_styp}_free(it->_${sub_sym.cname}); return; }') } fn_builder.writeln('}') } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 140cc87ed9ef6e..ec0a54af47f742 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1716,11 +1716,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { return } } else if node.name == 'free' { - mut rec_type := node.receiver_type - if rec_type.has_flag(.shared_f) { - rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0) - } - g.get_free_method(rec_type) + g.register_free_method(node.receiver_type) is_free_method = true } mut cast_n := 0