From 275285d72623d07b82f74c37112de201d6f5e699 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 14 Apr 2026 23:58:22 +0300 Subject: [PATCH] cgen: fix json.encode failing under some circumstances (fixes #15840) --- ...code_generic_fixed_array_regression_test.v | 21 ++++++++++++++ vlib/v/gen/c/auto_eq_methods.v | 28 +++++++++---------- vlib/v/gen/c/struct.v | 13 +++++++++ 3 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 vlib/json/tests/json_encode_generic_fixed_array_regression_test.v diff --git a/vlib/json/tests/json_encode_generic_fixed_array_regression_test.v b/vlib/json/tests/json_encode_generic_fixed_array_regression_test.v new file mode 100644 index 000000000..244a53f7f --- /dev/null +++ b/vlib/json/tests/json_encode_generic_fixed_array_regression_test.v @@ -0,0 +1,21 @@ +import json + +struct Wrap[T] { + val T +} + +fn encode[T](value T) string { + return json.encode(Wrap[T]{ + val: value + }) +} + +fn test_json_encode_generic_fixed_array_regression() { + assert encode('x') == '{"val":"x"}' + assert encode([1, 2]!) == '{"val":[1,2]}' +} + +fn test_json_encode_generic_fixed_array_regression_reversed() { + assert encode([1, 2]!) == '{"val":[1,2]}' + assert encode('x') == '{"val":"x"}' +} diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index 032000b77..2537caf51 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -461,6 +461,7 @@ fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string { elem_info := left_typ.sym.array_fixed_info() elem := g.unwrap(elem_info.elem_type) + ptr_elem_styp := g.styp(elem.typ) size := elem_info.size mut arg_styp := ptr_styp if elem_info.is_fn_ret { @@ -469,9 +470,8 @@ fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string { g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b);') is_option := left_type.has_flag(.option) - inner_type := g.base_type(left_typ.typ.set_nr_muls(0)) - left := if is_option { '(*(${inner_type}*)a.data)' } else { 'a' } - right := if is_option { '(*(${inner_type}*)b.data)' } else { 'b' } + left_item := if is_option { '((${ptr_elem_styp}*)a.data)' } else { 'a' } + right_item := if is_option { '((${ptr_elem_styp}*)b.data)' } else { 'b' } mut fn_builder := strings.new_builder(512) fn_builder.writeln('${g.static_non_parallel}inline bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b) {') @@ -493,34 +493,34 @@ fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string { fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < ${size}; ++i) {') // compare every pair of elements of the two fixed arrays if elem.sym.kind == .string { - left_arg := '${left}[i]' - right_arg := '${right}[i]' + left_arg := '${left_item}[i]' + right_arg := '${right_item}[i]' fn_builder.writeln('\t\tif (!${string_eq_expr(left_arg, right_arg, elem.typ.is_ptr())}) {') } else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() { eq_fn := g.gen_sumtype_equality_fn(elem.typ) - fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(${left}[i], ${right}[i])) {') + fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(${left_item}[i], ${right_item}[i])) {') } else if elem.sym.kind == .struct && !elem.typ.is_ptr() { eq_fn := g.gen_struct_equality_fn(elem.typ) - fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(${left}[i], ${right}[i])) {') + fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(${left_item}[i], ${right_item}[i])) {') } else if elem.sym.kind == .interface && !elem.typ.is_ptr() { eq_fn := g.gen_interface_equality_fn(elem.typ) - fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(${left}[i], ${right}[i])) {') + fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(${left_item}[i], ${right_item}[i])) {') } else if elem.sym.kind == .array && !elem.typ.is_ptr() { eq_fn := g.gen_array_equality_fn(elem.typ) - fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left}[i], ${right}[i])) {') + fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left_item}[i], ${right_item}[i])) {') } else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() { eq_fn := g.gen_fixed_array_equality_fn(elem.typ) - fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left}[i], ${right}[i])) {') + fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left_item}[i], ${right_item}[i])) {') } else if elem.sym.kind == .map && !elem.typ.is_ptr() { eq_fn := g.gen_map_equality_fn(elem.typ) - fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(${left}[i], ${right}[i])) {') + fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(${left_item}[i], ${right_item}[i])) {') } else if elem.sym.kind == .alias && !elem.typ.is_ptr() { eq_fn := g.gen_alias_equality_fn(elem.typ) - fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(${left}[i], ${right}[i])) {') + fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(${left_item}[i], ${right_item}[i])) {') } else if elem.sym.kind == .function { - fn_builder.writeln('\t\tif (${left}[i] != ${right}[i]) {') + fn_builder.writeln('\t\tif (${left_item}[i] != ${right_item}[i]) {') } else { - fn_builder.writeln('\t\tif (${left}[i] != ${right}[i]) {') + fn_builder.writeln('\t\tif (${left_item}[i] != ${right_item}[i]) {') } fn_builder.writeln('\t\t\treturn false;') fn_builder.writeln('\t\t}') diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index f138546a1..3d2dd3ff3 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -364,6 +364,12 @@ fn (mut g Gen) struct_init(node ast.StructInit) { sfield.expected_type = tt } } + if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 { + resolved_sfield_typ := g.resolved_expr_type(ast.Expr(sfield.expr), sfield.typ) + if resolved_sfield_typ != 0 { + sfield.typ = g.unwrap_generic(g.recheck_concrete_type(resolved_sfield_typ)) + } + } if node.no_keys && sym.kind == .struct { sym_info := sym.info as ast.Struct if sym_info.fields.len == node.init_fields.len { @@ -561,6 +567,13 @@ fn (mut g Gen) direct_heap_struct_init(node ast.StructInit, styp string, info as g.checker_bug('struct init, field.typ is 0', resolved_field.pos) } } + if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 { + resolved_field_typ := g.resolved_expr_type(ast.Expr(resolved_field.expr), + resolved_field.typ) + if resolved_field_typ != 0 { + resolved_field.typ = g.unwrap_generic(g.recheck_concrete_type(resolved_field_typ)) + } + } g.struct_init_ptr_field(tmp_var, resolved_field, language) g.writeln(';') } -- 2.39.5