From 7870c08b9033f6f67bea4097730ef71877530956 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:15 +0300 Subject: [PATCH] builtin: fix strings builder bug with -cg (fixes #13613) --- vlib/builtin/array.v | 3 +- vlib/builtin/array_test.v | 8 ++++ .../strings_builder_issue_13613_cg_test.v | 41 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/builtin_strings_and_interpolation/strings_builder_issue_13613_cg_test.v diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 2245f4c99..71c2c7934 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -789,10 +789,11 @@ pub fn (mut a array) push_many(val voidptr, size int) { // string interpolation also uses <<; avoid it, use a fixed string for the panic panic('array.push_many: new len exceeds max_int') } + is_self_append := a.data == val && a.data != 0 if new_len >= a.cap { a.ensure_cap(int(new_len)) } - if a.data == val && a.data != 0 { + if is_self_append { // handle `arr << arr` copy := a.clone() unsafe { diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index 47fbbafa8..5267b1db2 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -353,6 +353,14 @@ fn test_push_many() { assert a[5] == 6 } +fn test_push_many_self_append_with_growth() { + mut a := [u8(`a`), `b`, `c`] + a << a + assert a.bytestr() == 'abcabc' + a << a + assert a.bytestr() == 'abcabcabcabc' +} + fn test_reverse() { a := [1, 2, 3, 4] b := ['test', 'array', 'reverse'] diff --git a/vlib/v/tests/builtin_strings_and_interpolation/strings_builder_issue_13613_cg_test.v b/vlib/v/tests/builtin_strings_and_interpolation/strings_builder_issue_13613_cg_test.v new file mode 100644 index 000000000..893a9cf3a --- /dev/null +++ b/vlib/v/tests/builtin_strings_and_interpolation/strings_builder_issue_13613_cg_test.v @@ -0,0 +1,41 @@ +// vtest vflags: -cg +module main + +import strings + +struct Issue13613Writer { +mut: + out strings.Builder = strings.new_builder(200) +} + +fn (mut w Issue13613Writer) build() string { + w.out.writeln('module main') + w.out.writeln('') + w.out.writeln('fn main() {') + w.out.writeln('\tprint("You\'re")') + w.out.writeln('\tmatch 27 {') + w.out.writeln('\t\t18 {') + w.out.writeln('\t\t\tmut age := 27') + w.out.writeln("\t\t\tprintln(' of age')") + w.out.writeln('\t\t}') + w.out.writeln('\t\t10 {') + w.out.writeln('\t\t\tmut age := 27') + w.out.writeln("\t\t\tprintln(' a child')") + w.out.writeln('\t\t}') + w.out.writeln('\t\telse {') + w.out.writeln('\t\t\tmut age := 27') + w.out.writeln('\t\t\tprintln(".. I don\'t know my program is pretty dumb :/")') + w.out.writeln('\t\t}') + w.out.writeln('\t}') + w.out.write_string('}') + return w.out.str() +} + +fn test_strings_builder_growth_with_cg_regression() { + expected := 'module main\n\nfn main() {\n\tprint("You\'re")\n\tmatch 27 {\n\t\t18 {\n\t\t\tmut age := 27\n\t\t\tprintln(\' of age\')\n\t\t}\n\t\t10 {\n\t\t\tmut age := 27\n\t\t\tprintln(\' a child\')\n\t\t}\n\t\telse {\n\t\t\tmut age := 27\n\t\t\tprintln(".. I don\'t know my program is pretty dumb :/")\n\t\t}\n\t}\n}' + mut w := Issue13613Writer{} + got := w.build() + assert got.len == expected.len + assert got[0] == `m` + assert got == expected +} -- 2.39.5