From 742895e2290c6c20c135b0b1e571a2920f6d661f Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 15 Apr 2026 04:48:39 +0300 Subject: [PATCH] cgen: fix circular printing not showing item count in array (fixes #21689) --- vlib/builtin/autostr.v | 21 +++++++++++++++++++ vlib/v/gen/c/auto_str_methods.v | 8 +++++-- .../string_interpolation_struct_test.v | 13 ++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/vlib/builtin/autostr.v b/vlib/builtin/autostr.v index 089c90dd7..d6ba55c5f 100644 --- a/vlib/builtin/autostr.v +++ b/vlib/builtin/autostr.v @@ -1,5 +1,7 @@ module builtin +import strings + const autostr_type_stack_max_depth = 64 __global g_autostr_type_stack = [autostr_type_stack_max_depth]int{} @@ -64,3 +66,22 @@ fn autostr_addr_pop() { g_autostr_addr_stack_len-- } } + +@[markused] +fn autostr_array_circular(len int) string { + if len <= 0 { + return '[]' + } + mut sb := strings.new_builder(2 + len * 12) + sb.write_string('[') + for i in 0 .. len { + if i > 0 { + sb.write_string(', ') + } + sb.write_string('') + } + sb.write_string(']') + res := sb.str() + unsafe { sb.free() } + return res +} diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index b53e32d03..17bdc3760 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -1167,12 +1167,16 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin // handle circular ref type of struct to the struct itself if styp == field_styp && !allow_circular { if is_field_array { + tmpvar := g.new_tmp_var() if is_opt_field { arr_styp := g.base_type(field.typ) - fn_body.write_string('${it_field_name}.state != 2 && (*(${arr_styp}*)${it_field_name}.data).len > 0 ? ${funcprefix}_S("[]") : ${funcprefix}_S("[]")') + fn_body_surrounder.add('\tstring ${tmpvar} = ${funcprefix}builtin__autostr_array_circular(${it_field_name}.state != 2 ? (*(${arr_styp}*)${it_field_name}.data).len : 0);', + '\tbuiltin__string_free(&${tmpvar});') } else { - fn_body.write_string('${it_field_name}.len > 0 ? ${funcprefix}_S("[]") : ${funcprefix}_S("[]")') + fn_body_surrounder.add('\tstring ${tmpvar} = ${funcprefix}builtin__autostr_array_circular(${it_field_name}.len);', + '\tbuiltin__string_free(&${tmpvar});') } + fn_body.write_string(tmpvar) } else { fn_body.write_string('${funcprefix}_S("")') } diff --git a/vlib/v/tests/builtin_strings_and_interpolation/string_interpolation_struct_test.v b/vlib/v/tests/builtin_strings_and_interpolation/string_interpolation_struct_test.v index 78f8d69c8..f20265393 100644 --- a/vlib/v/tests/builtin_strings_and_interpolation/string_interpolation_struct_test.v +++ b/vlib/v/tests/builtin_strings_and_interpolation/string_interpolation_struct_test.v @@ -91,3 +91,16 @@ fn test_cross_reference_field_auto_str() { s := '${window}'.replace('\n', '|') assert s == '&CrossRefWindow{| widgets: [CrossRefWidget{| parent: &CrossRefWindow{| widgets: [CrossRefWidget{| parent: &| }]| }| }]|}' } + +struct CircularArray { +mut: + children []CircularArray +} + +fn test_circular_array_field_auto_str_keeps_item_count() { + mut value := CircularArray{} + value.children << CircularArray{} + value.children << CircularArray{} + s := '${value}'.replace('\n', '|') + assert s == 'CircularArray{| children: [, ]|}' +} -- 2.39.5