From d3ee62fd99a6c743642ec5a246dfa4a37777b504 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 11 Mar 2026 15:54:31 +0300 Subject: [PATCH] cgen: x__json2__Any_free cgen error (fixes #19289) --- vlib/v/gen/c/auto_free_methods.v | 74 ++++++++++++++++++++- vlib/v/tests/sumtypes/json2_any_free_test.v | 19 ++++++ 2 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/sumtypes/json2_any_free_test.v diff --git a/vlib/v/gen/c/auto_free_methods.v b/vlib/v/gen/c/auto_free_methods.v index b34d0b2a4..23e89495b 100644 --- a/vlib/v/gen/c/auto_free_methods.v +++ b/vlib/v/gen/c/auto_free_methods.v @@ -73,6 +73,9 @@ fn (mut g Gen) gen_free_method(typ ast.Type) string { ast.Interface { g.gen_free_for_interface(sym, sym.info, styp, fn_name) } + ast.SumType { + g.gen_free_for_sumtype(sym.info, styp, fn_name) + } else { println(g.table.type_str(typ)) // print_backtrace() @@ -105,6 +108,73 @@ fn (mut g Gen) gen_free_for_interface(sym ast.TypeSymbol, info ast.Interface, st fn_builder.writeln('}') } +fn (mut g Gen) gen_free_for_sumtype(info ast.SumType, styp string, fn_name string) { + g.definitions.writeln('${g.static_non_parallel}void ${fn_name}(${styp}* it);') + mut fn_builder := strings.new_builder(256) + defer { + g.auto_fn_definitions << fn_builder.str() + } + fn_builder.writeln('${g.static_non_parallel}void ${fn_name}(${styp}* it) {') + mut idxs := []ast.Type{} + for variant in info.variants { + if variant in idxs { + continue + } + idxs << variant + free_typ := variant.clear_flag(.option) + free_sym := g.table.sym(g.unwrap_generic(free_typ)) + variant_name := g.get_sumtype_variant_name(variant, free_sym) + variant_ptr := 'it->_${variant_name}' + fn_builder.writeln('\tif (it->_typ == ${g.type_sidx(variant)}) {') + if variant.has_flag(.option) { + match free_sym.kind { + .string { + fn_builder.writeln('\t\tif (${variant_ptr}->state != 2) {') + fn_builder.writeln('\t\t\tbuiltin__string_free((${g.base_type(variant)}*)${variant_ptr}->data);') + fn_builder.writeln('\t\t}') + } + .array, .map, .struct, .sum_type, .interface { + mut free_fn_name := if free_sym.has_method('free') { + '${g.gen_type_name_for_free_call(free_typ)}_free' + } else { + g.gen_free_method(free_typ) + } + if free_sym.is_builtin() { + free_fn_name = 'builtin__${free_fn_name}' + } + fn_builder.writeln('\t\tif (${variant_ptr}->state != 2) {') + fn_builder.writeln('\t\t\t${free_fn_name}((${g.base_type(variant)}*)${variant_ptr}->data);') + fn_builder.writeln('\t\t}') + } + else {} + } + } else { + match free_sym.kind { + .string { + fn_builder.writeln('\t\tbuiltin__string_free(${variant_ptr});') + } + .array, .map, .struct, .sum_type, .interface { + mut free_fn_name := if free_sym.has_method('free') { + '${g.gen_type_name_for_free_call(free_typ)}_free' + } else { + g.gen_free_method(free_typ) + } + if free_sym.is_builtin() { + free_fn_name = 'builtin__${free_fn_name}' + } + fn_builder.writeln('\t\t${free_fn_name}(${variant_ptr});') + } + else {} + } + } + // Sumtypes box their active payload in heap memory via memdup/HEAP. + fn_builder.writeln('\t\tbuiltin___v_free(${variant_ptr});') + fn_builder.writeln('\t\treturn;') + fn_builder.writeln('\t}') + } + fn_builder.writeln('}') +} + fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, ofn_name string, sym_is_builtin bool) { mut fn_name := ofn_name if sym_is_builtin { @@ -120,7 +190,7 @@ fn (mut g Gen) gen_free_for_struct(typ ast.Type, info ast.Struct, styp string, o field_name := c_name(field.name) sym := g.table.sym(g.unwrap_generic(field.typ)) - if sym.kind !in [.string, .array, .map, .struct] { + if sym.kind !in [.string, .array, .map, .struct, .sum_type] { continue } field_styp := g.gen_type_name_for_free_call(field.typ) @@ -191,7 +261,7 @@ fn (mut g Gen) gen_free_for_array(info ast.Array, styp string, fn_name string) { fn_builder.writeln('${g.static_non_parallel}void ${fn_name}(${styp}* it) {') sym := g.table.sym(g.unwrap_generic(info.elem_type)) - if sym.kind in [.string, .array, .map, .struct] { + if sym.kind in [.string, .array, .map, .struct, .sum_type] { fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < it->len; i++) {') mut elem_styp := g.styp(info.elem_type).replace('*', '') diff --git a/vlib/v/tests/sumtypes/json2_any_free_test.v b/vlib/v/tests/sumtypes/json2_any_free_test.v new file mode 100644 index 000000000..f1686e69e --- /dev/null +++ b/vlib/v/tests/sumtypes/json2_any_free_test.v @@ -0,0 +1,19 @@ +import x.json2 + +fn test_json2_any_free() { + c := json2.Any(123) + unsafe { c.free() } + assert true +} + +fn test_json2_any_free_recursive_variants() { + arr := json2.Any([json2.Any('abc')]) + obj := json2.Any({ + 'key': json2.Any('value') + }) + unsafe { + arr.free() + obj.free() + } + assert true +} -- 2.39.5