diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 41031be223..0a3ab0070b 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -860,6 +860,8 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, typ_str string, } fn_body.writeln('\tstring res = str_intp( ${(info.fields.len - field_skips.len) * 4 + 3}, _MOV((StrIntpData[]){') fn_body.writeln('\t\t{_SLIT("${clean_struct_v_type_name}{\\n"), 0, {.d_c=0}},') + + allow_circular := info.attrs.any(it.name == 'autostr' && it.arg == 'allowrecurse') mut is_first := true for i, field in info.fields { // Skip `str:skip` fields @@ -937,7 +939,7 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, typ_str string, } } // handle circular ref type of struct to the struct itself - if styp == field_styp { + if styp == field_styp && !allow_circular { fn_body.write_string('${funcprefix}_SLIT("")') } else { // manage C charptr diff --git a/vlib/v/gen/js/auto_str_methods.v b/vlib/v/gen/js/auto_str_methods.v index eb558b118e..7479e620b9 100644 --- a/vlib/v/gen/js/auto_str_methods.v +++ b/vlib/v/gen/js/auto_str_methods.v @@ -712,6 +712,7 @@ fn (mut g JsGen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name st fn_builder.writeln('\tlet res = /*struct name*/new string("${clean_struct_v_type_name}{\\n")') + allow_circular := info.attrs.any(it.name == 'autostr' && it.arg == 'allowrecurse') for i, field in info.fields { mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' } mut prefix := '' @@ -758,7 +759,7 @@ fn (mut g JsGen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name st } } // handle circular ref type of struct to the struct itself - if styp == field_styp { + if styp == field_styp && !allow_circular { fn_builder.write_string('res.str += new string("")') } else { // manage C charptr diff --git a/vlib/v/tests/tag_autostr_allowrecurse_test.v b/vlib/v/tests/tag_autostr_allowrecurse_test.v new file mode 100644 index 0000000000..5a06265d9a --- /dev/null +++ b/vlib/v/tests/tag_autostr_allowrecurse_test.v @@ -0,0 +1,23 @@ +[autostr: allowrecurse] +struct Node { + a &Node = unsafe { nil } + b &Node = unsafe { nil } +} + +fn test_stringifying_a_value_of_a_struct_tagged_with_autostr_allowrecurse() { + abc := &Node{ + a: &Node{ + b: &Node{} + } + b: &Node{ + a: &Node{} + } + } + // println(abc) + s := abc.str() + assert !s.contains('&') + assert s.contains('a: &Node{') + assert s.contains('a: &nil') + assert s.contains('b: &Node{') + assert s.contains('b: &nil') +}