From 87f513fef4ac4eab811f0c1c6967b11ce2238ba3 Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 20 Oct 2023 15:11:22 +0800 Subject: [PATCH 1/2] checker: check struct reference fields uninitialized --- vlib/v/checker/struct.v | 15 +++++---- .../struct_ref_fields_uninitialized_err.out | 33 ------------------- .../struct_ref_fields_uninitialized_err_a.out | 33 +++++++++++++++++++ ... struct_ref_fields_uninitialized_err_a.vv} | 0 .../struct_ref_fields_uninitialized_err_b.out | 26 +++++++++++++++ .../struct_ref_fields_uninitialized_err_b.vv | 14 ++++++++ 6 files changed, 81 insertions(+), 40 deletions(-) delete mode 100644 vlib/v/checker/tests/struct_ref_fields_uninitialized_err.out create mode 100644 vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.out rename vlib/v/checker/tests/{struct_ref_fields_uninitialized_err.vv => struct_ref_fields_uninitialized_err_a.vv} (100%) create mode 100644 vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.out create mode 100644 vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 2018d0b511678d..b3713e56c6e809 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -686,7 +686,7 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', if field.name in inited_fields { continue } - sym := c.table.sym(field.typ) + sym := c.table.final_sym(field.typ) if field.name.len > 0 && field.name[0].is_capital() && sym.info is ast.Struct && sym.language == .v { // struct embeds @@ -712,6 +712,10 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', } } } + if sym.kind == .struct_ { + c.check_ref_fields_initialized(sym, mut checked_types, '${type_sym.name}.${field.name}', + node) + } continue } if field.typ.is_ptr() && !field.typ.has_flag(.shared_f) @@ -724,12 +728,6 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', if sym.kind == .struct_ { c.check_ref_fields_initialized(sym, mut checked_types, '${type_sym.name}.${field.name}', node) - } else if sym.kind == .alias { - parent_sym := c.table.sym((sym.info as ast.Alias).parent_type) - if parent_sym.kind == .struct_ { - c.check_ref_fields_initialized(parent_sym, mut checked_types, - '${type_sym.name}.${field.name}', node) - } } // Do not allow empty uninitialized interfaces mut has_noinit := false @@ -858,6 +856,9 @@ fn (mut c Checker) check_ref_fields_initialized(struct_sym &ast.TypeSymbol, mut } else if sym.kind == .alias { psym := c.table.sym((sym.info as ast.Alias).parent_type) if psym.kind == .struct_ { + if field.typ in checked_types { + continue + } checked_types << field.typ c.check_ref_fields_initialized(psym, mut checked_types, '${linked_name}.${field.name}', node) diff --git a/vlib/v/checker/tests/struct_ref_fields_uninitialized_err.out b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err.out deleted file mode 100644 index 0ce3317fd6d10a..00000000000000 --- a/vlib/v/checker/tests/struct_ref_fields_uninitialized_err.out +++ /dev/null @@ -1,33 +0,0 @@ -vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:25:7: error: reference field `Outer.c1.b` must be initialized (part of struct `ContainsRef`) - 23 | - 24 | fn main() { - 25 | _ := Outer{} - | ~~~~~~~ - 26 | _ := Struct{} - 27 | } -vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:25:7: error: reference field `ContainsRef.b` must be initialized - 23 | - 24 | fn main() { - 25 | _ := Outer{} - | ~~~~~~~ - 26 | _ := Struct{} - 27 | } -vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:25:7: error: reference field `Outer.c2.b` must be initialized (part of struct `ContainsRef`) - 23 | - 24 | fn main() { - 25 | _ := Outer{} - | ~~~~~~~ - 26 | _ := Struct{} - 27 | } -vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:26:7: error: reference field `Struct.ref2` must be initialized - 24 | fn main() { - 25 | _ := Outer{} - 26 | _ := Struct{} - | ~~~~~~~~ - 27 | } -vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:26:7: error: reference field `EmbedStruct.ref2` must be initialized - 24 | fn main() { - 25 | _ := Outer{} - 26 | _ := Struct{} - | ~~~~~~~~ - 27 | } diff --git a/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.out b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.out new file mode 100644 index 00000000000000..1b9bf0fc42885b --- /dev/null +++ b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.out @@ -0,0 +1,33 @@ +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.vv:25:7: error: reference field `Outer.c1.b` must be initialized (part of struct `ContainsRef`) + 23 | + 24 | fn main() { + 25 | _ := Outer{} + | ~~~~~~~ + 26 | _ := Struct{} + 27 | } +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.vv:25:7: error: reference field `ContainsRef.b` must be initialized + 23 | + 24 | fn main() { + 25 | _ := Outer{} + | ~~~~~~~ + 26 | _ := Struct{} + 27 | } +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.vv:25:7: error: reference field `Outer.c2.b` must be initialized (part of struct `ContainsRef`) + 23 | + 24 | fn main() { + 25 | _ := Outer{} + | ~~~~~~~ + 26 | _ := Struct{} + 27 | } +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.vv:26:7: error: reference field `Struct.ref2` must be initialized + 24 | fn main() { + 25 | _ := Outer{} + 26 | _ := Struct{} + | ~~~~~~~~ + 27 | } +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.vv:26:7: error: reference field `EmbedStruct.ref2` must be initialized + 24 | fn main() { + 25 | _ := Outer{} + 26 | _ := Struct{} + | ~~~~~~~~ + 27 | } diff --git a/vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.vv similarity index 100% rename from vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv rename to vlib/v/checker/tests/struct_ref_fields_uninitialized_err_a.vv diff --git a/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.out b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.out new file mode 100644 index 00000000000000..a42675a801c176 --- /dev/null +++ b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.out @@ -0,0 +1,26 @@ +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv:8:32: warning: unnecessary default value of `none`: struct fields are zeroed by default + 6 | pub struct Window { + 7 | mut: + 8 | desktop_viewport ?&Viewport = none + | ~~~~ + 9 | phone_viewport ?&Viewport = none + 10 | } +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv:9:32: warning: unnecessary default value of `none`: struct fields are zeroed by default + 7 | mut: + 8 | desktop_viewport ?&Viewport = none + 9 | phone_viewport ?&Viewport = none + | ~~~~ + 10 | } + 11 | +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv:13:8: error: reference field `Window.desktop_viewport.parent` must be initialized (part of struct `Viewport`) + 11 | + 12 | fn main() { + 13 | _ := &Window{} + | ~~~~~~~~ + 14 | } +vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv:13:8: error: reference field `Window.phone_viewport.parent` must be initialized (part of struct `Viewport`) + 11 | + 12 | fn main() { + 13 | _ := &Window{} + | ~~~~~~~~ + 14 | } diff --git a/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv new file mode 100644 index 00000000000000..6475a81c4dd739 --- /dev/null +++ b/vlib/v/checker/tests/struct_ref_fields_uninitialized_err_b.vv @@ -0,0 +1,14 @@ +struct Viewport { +mut: + parent &Window +} + +pub struct Window { +mut: + desktop_viewport ?&Viewport = none + phone_viewport ?&Viewport = none +} + +fn main() { + _ := &Window{} +} From 7f21a07670e18a76e95d5699873a8b2b5a6c7ecc Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 20 Oct 2023 15:43:36 +0800 Subject: [PATCH 2/2] fix the example in docs.md --- doc/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/docs.md b/doc/docs.md index b51c715cee3b98..1e7d8aa57ed74b 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -5933,7 +5933,7 @@ cause a panic. ```v struct Node { - a &Node + a &Node = unsafe { nil } // Auto-initialized to nil, use with caution! b &Node = unsafe { nil } // Auto-initialized to nil, use with caution! }