From: Hirohito Higashi Date: Thu, 30 Jul 2026 18:49:22 +0000 (+0000) Subject: patch 9.2.0878: Vim9: cannot use a script variable of an enclosing block in a lambda X-Git-Tag: v9.2.0878^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ce55a4910dc7a1de95d828ddce916d2d2bd4d6d6;p=thirdparty%2Fvim.git patch 9.2.0878: Vim9: cannot use a script variable of an enclosing block in a lambda Problem: Vim9: E1001 when a lambda inside a :def function uses a script variable that was declared in an enclosing block, while the :def function itself can use it (neoharju) Solution: Copy the block scope IDs to the lambda, like it is done for a nested function (Hirohito Higashi). fixes: #20876 closes: #PR Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 91873845d8..b86acd071e 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -449,6 +449,24 @@ def Test_block_local_vars_with_func() assert_equal(['foo', 'bar'], Func()) END v9.CheckScriptSuccess(lines) + + # also when the variables are used in a lambda inside the function + lines =<< trim END + vim9script + if true + var foo = 'foo' + if true + var bar = 'bar' + def Func(): list + var Lambda = () => [foo, bar] + return Lambda() + enddef + defcompile + endif + endif + assert_equal(['foo', 'bar'], Func()) + END + v9.CheckScriptSuccess(lines) enddef " legacy func for command that's defined later diff --git a/src/version.c b/src/version.c index 3fba5845f9..0e5c697ec9 100644 --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 878, /**/ 877, /**/ diff --git a/src/vim9expr.c b/src/vim9expr.c index f69488d5bd..7f47d82fb6 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -1795,10 +1795,27 @@ compile_lambda(char_u **arg, cctx_T *cctx) clear_tv(&rettv); if (cctx->ctx_ufunc != NULL) + { // This lambda might be defined in a class method. Inherit the class // from the current function. ufunc->uf_defclass = cctx->ctx_ufunc->uf_defclass; + // Copy over the block scope IDs, so that a script variable declared in + // an enclosing block can be found. + int block_depth = cctx->ctx_ufunc->uf_block_depth; + + if (block_depth > 0) + { + ufunc->uf_block_ids = ALLOC_MULT(int, block_depth); + if (ufunc->uf_block_ids != NULL) + { + mch_memmove(ufunc->uf_block_ids, cctx->ctx_ufunc->uf_block_ids, + sizeof(int) * block_depth); + ufunc->uf_block_depth = block_depth; + } + } + } + // Compile it here to get the return type. The return type is optional, // when it's missing use t_unknown. This is recognized in // compile_return().