From 72b48047b5ac87de9be9fda619df74d8e4802d55 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Wed, 9 Oct 2024 16:48:28 -0300 Subject: [PATCH] checker: add scope validation for struct (fix #22437) (#22449) --- vlib/v/ast/types.v | 4 +++- vlib/v/checker/struct.v | 5 +++++ vlib/v/checker/tests/struct_scope_err.out | 7 +++++++ vlib/v/checker/tests/struct_scope_err.vv | 18 ++++++++++++++++++ vlib/v/parser/struct.v | 2 ++ 5 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 vlib/v/checker/tests/struct_scope_err.out create mode 100644 vlib/v/checker/tests/struct_scope_err.vv diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index a7381eec8..20e8c3d1b 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -158,7 +158,9 @@ pub mut: @[minify] pub struct Struct { pub: - attrs []Attr + attrs []Attr + scope &Scope = unsafe { nil } + is_local bool pub mut: embeds []Type fields []StructField diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 89e3ebb17..3b03fdfd4 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -441,6 +441,11 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini mut old_cur_struct_generic_types := []ast.Type{} mut old_cur_struct_concrete_types := []ast.Type{} if struct_sym.info is ast.Struct { + if struct_sym.info.is_local && struct_sym.info.scope != unsafe { nil } + && !struct_sym.info.scope.contains(node.pos.pos) { + c.error('struct `${struct_sym.name}` was declared in a local scope outside current scope', + node.pos) + } // check if the generic param types have been defined for ct in struct_sym.info.concrete_types { ct_sym := c.table.sym(ct) diff --git a/vlib/v/checker/tests/struct_scope_err.out b/vlib/v/checker/tests/struct_scope_err.out new file mode 100644 index 000000000..2c80cb349 --- /dev/null +++ b/vlib/v/checker/tests/struct_scope_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/struct_scope_err.vv:16:8: error: struct `Foobar` was declared in a local scope outside current scope + 14 | + 15 | fn x() { + 16 | fb := Foobar{7, 8} + | ~~~~~~~~~~~~ + 17 | println(fb.bar) + 18 | } diff --git a/vlib/v/checker/tests/struct_scope_err.vv b/vlib/v/checker/tests/struct_scope_err.vv new file mode 100644 index 000000000..f5e70858d --- /dev/null +++ b/vlib/v/checker/tests/struct_scope_err.vv @@ -0,0 +1,18 @@ +fn main() { + + struct Foobar { + foo int + bar int + } + + if true { + fb := Foobar{5, 6} + println(fb.foo) + x() + } +} + +fn x() { + fb := Foobar{7, 8} + println(fb.bar) +} diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 7e0050929..4796867ec 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -370,6 +370,8 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { generic_types: generic_types attrs: attrs is_anon: is_anon + is_local: p.inside_fn + scope: p.scope } is_pub: is_pub } -- 2.39.5