From 38ff6472504764a80058f15f3da00bccc2a534cb Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Mon, 21 Apr 2025 13:02:28 -0300 Subject: [PATCH] checker: add check for recursive array init on struct (fix #21195) (#24278) --- vlib/v/checker/struct.v | 9 ++++++++- .../tests/invalid_recursive_struct_err.out | 5 +++-- .../recursive_struct_inited_array_err.out | 19 +++++++++++++++++++ .../recursive_struct_inited_array_err.vv | 12 ++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 vlib/v/checker/tests/recursive_struct_inited_array_err.out create mode 100644 vlib/v/checker/tests/recursive_struct_inited_array_err.vv diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 225bcdd7f6..88e5b3f150 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -96,7 +96,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { symfield.is_recursive = true } else { c.error('recursive struct is only possible with optional pointer (e.g. ?&${c.table.type_to_str(field.typ.clear_flag(.option))})', - node.pos) + field.pos) } } } @@ -249,6 +249,13 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { } } } + if field.default_expr is ast.ArrayInit { + if c.table.final_sym(field.default_expr_typ).kind in [.array, .array_fixed] + && c.table.value_type(field.default_expr_typ) == struct_typ_idx { + c.error('cannot initialize array of same struct type that is being defined (recursion detected)', + field.pos) + } + } interface_implemented := sym.kind == .interface && c.type_implements(field.default_expr_typ, field.typ, field.pos) c.check_expected(field.default_expr_typ, field.typ) or { diff --git a/vlib/v/checker/tests/invalid_recursive_struct_err.out b/vlib/v/checker/tests/invalid_recursive_struct_err.out index f21dc843f5..fad43d2189 100644 --- a/vlib/v/checker/tests/invalid_recursive_struct_err.out +++ b/vlib/v/checker/tests/invalid_recursive_struct_err.out @@ -1,5 +1,6 @@ -vlib/v/checker/tests/invalid_recursive_struct_err.vv:1:1: error: recursive struct is only possible with optional pointer (e.g. ?&Node) +vlib/v/checker/tests/invalid_recursive_struct_err.vv:3:2: error: recursive struct is only possible with optional pointer (e.g. ?&Node) 1 | struct Node { - | ~~~~~~~~~~~ 2 | mut: 3 | next ?Node + | ~~~~~~~~~~ + 4 | } diff --git a/vlib/v/checker/tests/recursive_struct_inited_array_err.out b/vlib/v/checker/tests/recursive_struct_inited_array_err.out new file mode 100644 index 0000000000..d78fd48224 --- /dev/null +++ b/vlib/v/checker/tests/recursive_struct_inited_array_err.out @@ -0,0 +1,19 @@ +vlib/v/checker/tests/recursive_struct_inited_array_err.vv:10:2: warning: unused variable: `buggy` + 8 | + 9 | fn main() { + 10 | buggy := Node{} + | ~~~~~ + 11 | normal := BetterNode{} + 12 | } +vlib/v/checker/tests/recursive_struct_inited_array_err.vv:11:2: warning: unused variable: `normal` + 9 | fn main() { + 10 | buggy := Node{} + 11 | normal := BetterNode{} + | ~~~~~~ + 12 | } +vlib/v/checker/tests/recursive_struct_inited_array_err.vv:2:2: error: cannot initialize array of same struct type that is being defined (recursion detected) + 1 | struct Node { + 2 | next []Node = []Node{len: 1} + | ~~~~~~~~~~~ + 3 | } + 4 | diff --git a/vlib/v/checker/tests/recursive_struct_inited_array_err.vv b/vlib/v/checker/tests/recursive_struct_inited_array_err.vv new file mode 100644 index 0000000000..78cde8ecb9 --- /dev/null +++ b/vlib/v/checker/tests/recursive_struct_inited_array_err.vv @@ -0,0 +1,12 @@ +struct Node { + next []Node = []Node{len: 1} +} + +struct BetterNode { + next []BetterNode +} + +fn main() { + buggy := Node{} + normal := BetterNode{} +}