Commit: patch 9.2.0071: Vim9: lambda function deleted on re-sourcing

2 views
Skip to first unread message

Christian Brabandt

unread,
Feb 27, 2026, 2:16:48 PM (5 days ago) Feb 27
to vim...@googlegroups.com
patch 9.2.0071: Vim9: lambda function deleted on re-sourcing

Commit: https://github.com/vim/vim/commit/c598c4de275e9075583bc7fe628bb2a50868acfd
Author: Hirohito Higashi <h.eas...@gmail.com>
Date: Fri Feb 27 19:03:18 2026 +0000

patch 9.2.0071: Vim9: lambda function deleted on re-sourcing

Problem: Vim9: lambda function deleted on re-sourcing
(Mao-Yining)
Solution: Use ISN_UCALL for script-local def calls inside a lambda
(Hirohito Higashi).

fixes: #19509
closes: #19519

Signed-off-by: Hirohito Higashi <h.eas...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 83499999d..759226a41 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -1473,6 +1473,31 @@ def Test_disassemble_lambda()
instr)
enddef

+def s:ScriptLocalDefForLambda()
+enddef
+
+def GlobalDefForLambda()
+enddef
+
+def s:OuterWithLambdaCalls()
+ timer_start(0, (_) => {
+ ScriptLocalDefForLambda()
+ g:GlobalDefForLambda()
+ })
+enddef
+
+def Test_disassemble_lambda_call_types()
+ # Verify that inside a lambda:
+ # - script-local def function call → ISN_UCALL (safe after re-sourcing)
+ # - global def function call → ISN_DCALL (optimal, not deleted on re-source)
+ OuterWithLambdaCalls()
+ var instr = execute('disassemble OuterWithLambdaCalls')
+ var name = substitute(instr, '.*\(<lambda>\d\+\).*', ' ', '')
+ instr = execute('disassemble ' .. name)
+ assert_match('\d UCALL <80><fd>R\d\+_ScriptLocalDefForLambda(argc 0)', instr)
+ assert_match('\d DCALL GlobalDefForLambda(argc 0)', instr)
+enddef
+
def s:LambdaWithType(): number
var Ref = (a: number) => a + 10
return Ref(g:value)
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index ed946d85d..022bdeb12 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -1847,6 +1847,41 @@ def Test_vim9script_reload_delfunc()
g:DoCheck(false)
enddef

+def Test_vim9script_reload_lambda_def_func()
+ CheckFeature timers
+
+ var lines =<< trim END
+ vim9script
+
+ def F()
+ g:call_result += 1
+ enddef
+
+ augroup Xtest933
+ au!
+ au CmdlineLeave : timer_start(0, (_) => F())
+ augroup END
+ END
+
+ g:call_result = 0
+ writefile(lines, 'Xtest933.vim', 'D')
+ source Xtest933.vim
+
+ # Simulate the CmdlineLeave event that fires before the second :so
+ doautocmd CmdlineLeave :
+
+ # Re-source: F is redefined; without the fix this causes E933 when timer fires
+ source Xtest933.vim
+
+ # Allow the 0ms timer to fire
+ sleep 10m
+
+ assert_equal(1, g:call_result)
+
+ augroup Xtest933 | au! | augroup END
+ unlet! g:call_result
+enddef
+
def Test_vim9script_reload_delvar()
# write the script with a script-local variable
var lines =<< trim END
diff --git a/src/version.c b/src/version.c
index 0fde64014..4524be1da 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 71,
/**/
70,
/**/
diff --git a/src/vim9instr.c b/src/vim9instr.c
index c11e913b0..90156bfa0 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -1909,6 +1909,23 @@ generate_BLOBAPPEND(cctx_T *cctx)
return OK;
}

+/*
+ * get the instruction type for a function call: ISN_METHODCALL, ISN_DCALL, or
+ * ISN_UCALL.
+ */
+ static isntype_T
+isn_get_calltype(
+ cctx_T *cctx,
+ ufunc_T *ufunc,
+ class_T *cl)
+{
+ return cl != NULL ? ISN_METHODCALL
+ : (ufunc->uf_def_status != UF_NOT_COMPILED
+ && ((cctx->ctx_ufunc->uf_flags & FC_LAMBDA) == 0
+ || ufunc->uf_name[0] != K_SPECIAL))
+ ? ISN_DCALL : ISN_UCALL;
+}
+
/*
* Generate an ISN_DCALL, ISN_UCALL or ISN_METHODCALL instruction.
* When calling a method on an object, of which we know the interface only,
@@ -1996,9 +2013,7 @@ generate_CALL(
return FAIL;
}

- if ((isn = generate_instr(cctx, cl != NULL ? ISN_METHODCALL
- : ufunc->uf_def_status != UF_NOT_COMPILED
- ? ISN_DCALL : ISN_UCALL)) == NULL)
+ if ((isn = generate_instr(cctx, isn_get_calltype(cctx, ufunc, cl))) == NULL)
return FAIL;
if (cl != NULL /* isn->isn_type == ISN_METHODCALL */)
{
Reply all
Reply to author
Forward
0 new messages