From 8ad14cab12458eaa40afb8ec6698b2e47d66c117 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 15 Apr 2026 05:26:24 +0300 Subject: [PATCH] checker: fix anonymous generic struct shadow variable (fixes #15535) --- vlib/v/checker/assign.v | 3 ++- vlib/v/checker/fn.v | 11 +++++++++++ .../tests/assign_generic_closure_fn_err.out | 7 +++++++ .../tests/assign_generic_closure_fn_err.vv | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 vlib/v/checker/tests/assign_generic_closure_fn_err.out create mode 100644 vlib/v/checker/tests/assign_generic_closure_fn_err.vv diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index b5a5e9781..9c027cd41 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -151,7 +151,8 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { c.error('cannot use `none` in `unsafe` blocks', right.expr.pos) } if mut right is ast.AnonFn { - if right.decl.generic_names.len > 0 && right.inherited_vars.len == 0 { + if right.decl.generic_names.len > 0 && (right.inherited_vars.len == 0 + || !c.generic_anon_fn_can_use_current_context(right.decl.generic_names)) { c.error('cannot assign generic function to a variable', right.decl.pos) } } diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 1a98be1de..2e74afa37 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -143,6 +143,17 @@ fn (mut c Checker) effective_fn_generic_names(node &ast.FnDecl) []string { return c.table.generic_type_names(node.receiver.typ) } +fn (mut c Checker) generic_anon_fn_can_use_current_context(generic_names []string) bool { + if generic_names.len == 0 || c.table.cur_fn == unsafe { nil } { + return false + } + current_generic_names := c.effective_fn_generic_names(c.table.cur_fn) + if current_generic_names.len == 0 { + return false + } + return generic_names.all(it in current_generic_names) +} + fn (mut c Checker) receiver_requires_generic_names(node &ast.FnDecl) bool { if !node.is_method { return false diff --git a/vlib/v/checker/tests/assign_generic_closure_fn_err.out b/vlib/v/checker/tests/assign_generic_closure_fn_err.out new file mode 100644 index 000000000..f6d9e3bf6 --- /dev/null +++ b/vlib/v/checker/tests/assign_generic_closure_fn_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/assign_generic_closure_fn_err.vv:12:10: error: cannot assign generic function to a variable + 10 | fn main() { + 11 | mut cmd := Cmd[string]{} + 12 | anon := fn [mut cmd] [T]() { + | ~~~~~~~~~~~~~~~~~~~~ + 13 | use_cmd(mut cmd) + 14 | } diff --git a/vlib/v/checker/tests/assign_generic_closure_fn_err.vv b/vlib/v/checker/tests/assign_generic_closure_fn_err.vv new file mode 100644 index 000000000..97c7ecd7f --- /dev/null +++ b/vlib/v/checker/tests/assign_generic_closure_fn_err.vv @@ -0,0 +1,16 @@ +struct Cmd[T] { +mut: + val T +} + +fn use_cmd[T](mut cmd Cmd[T]) { + _ = cmd +} + +fn main() { + mut cmd := Cmd[string]{} + anon := fn [mut cmd] [T]() { + use_cmd(mut cmd) + } + anon() +} -- 2.39.5