Commit: patch 9.1.1882: Vim9: Not able to use a lambda with :defer

3 views
Skip to first unread message

Christian Brabandt

unread,
Oct 27, 2025, 2:15:15 PMOct 27
to vim...@googlegroups.com
patch 9.1.1882: Vim9: Not able to use a lambda with :defer

Commit: https://github.com/vim/vim/commit/21ef3c6e5972bbe8ab61195f98ccb85048b78985
Author: Yegappan Lakshmanan <yega...@yahoo.com>
Date: Mon Oct 27 18:07:52 2025 +0000

patch 9.1.1882: Vim9: Not able to use a lambda with :defer

Problem: Vim9: Not able to use a lambda with :defer
(Maxim Kim)
Solution: Add support for this (Yegappan Lakshmanan)

fixes: #18626
closes: #18643

Signed-off-by: Yegappan Lakshmanan <yega...@yahoo.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/userfunc.txt b/runtime/doc/userfunc.txt
index 5b3605a14..0f008446e 100644
--- a/runtime/doc/userfunc.txt
+++ b/runtime/doc/userfunc.txt
@@ -1,4 +1,4 @@
-*userfunc.txt* For Vim version 9.1. Last change: 2025 Oct 12
+*userfunc.txt* For Vim version 9.1. Last change: 2025 Oct 27


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -449,6 +449,15 @@ or altering execution outside of deferred functions.
No range is accepted. The function can be a partial with extra arguments, but
not with a dictionary. *E1300*

+In a |:def| function, a lambda can be used with |:defer|. Example: >
+
+ def Fn()
+ set lazyredraw
+ defer () => {
+ set lazyredraw&
+ }()
+ enddef
+<
==============================================================================

4. Automatically loading functions ~
diff --git a/src/proto/vim9expr.pro b/src/proto/vim9expr.pro
index 58c79fc02..4de143917 100644
--- a/src/proto/vim9expr.pro
+++ b/src/proto/vim9expr.pro
@@ -7,6 +7,7 @@ int compile_load(char_u **arg, size_t namelen, char_u *end_arg, cctx_T *cctx, in
int compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, ca_special_T special_fn);
char_u *to_name_end(char_u *arg, int use_namespace);
char_u *to_name_const_end(char_u *arg);
+int compile_lambda(char_u **arg, cctx_T *cctx);
int get_lambda_tv_and_compile(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg);
exprtype_T get_compare_type(char_u *p, int *len, int *type_is);
void skip_expr_cctx(char_u **arg, cctx_T *cctx);
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 40832a606..0134956c3 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -5249,6 +5249,102 @@ def Test_defer_lambda_funcref()
v9.CheckSourceSuccess(lines)
enddef

+" Test for using defer with a lambda and a command block
+def Test_defer_lambda_func()
+ var lines =<< trim END
+ vim9script
+ var result = ''
+ def Foo()
+ result = 'xxx'
+ defer (a: number, b: string): number => {
+ result = $'{a}:{b}'
+ return 0
+ }(10, 'aaa')
+ result = 'yyy'
+ enddef
+ Foo()
+ assert_equal('10:aaa', result)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ # Error: argument type mismatch
+ lines =<< trim END
+ vim9script
+ def Foo()
+ defer (a: number, b: string): number => {
+ return 0
+ }(10, 20)
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number', 1)
+
+ # Error: not enough arguments
+ lines =<< trim END
+ vim9script
+ def Foo()
+ defer (a: number) => {
+ }()
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E119: Not enough arguments for function: (a: number) => {', 1)
+
+ # Error: too many arguments
+ lines =<< trim END
+ vim9script
+ def Foo()
+ defer () => {
+ }(10)
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E118: Too many arguments for function: () => {', 1)
+
+ # Error: invalid command in command-block
+ lines =<< trim END
+ vim9script
+ def Foo()
+ defer () => {
+ xxx
+ }()
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E476: Invalid command: xxx', 1)
+
+ # Error: missing return
+ lines =<< trim END
+ vim9script
+ def Foo()
+ defer (): number => {
+ }()
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E1027: Missing return statement', 1)
+
+ # Error: missing lambda body
+ lines =<< trim END
+ vim9script
+ def Foo()
+ defer (a: number): number
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1)
+
+ # Error: invalid lambda syntax
+ lines =<< trim END
+ vim9script
+ def Foo()
+ defer (
+ enddef
+ defcompile
+ END
+ v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1)
+enddef
+
" Test for using an non-existing type in a "for" statement.
def Test_invalid_type_in_for()
var lines =<< trim END
diff --git a/src/version.c b/src/version.c
index b837e88f7..ed9059da4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1882,
/**/
1881,
/**/
diff --git a/src/vim9cmds.c b/src/vim9cmds.c
index fb9f78137..684d2ee66 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -2040,25 +2040,35 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
int argcount = 0;
int defer_var_idx;
type_T *type = NULL;
- int func_idx;
+ int func_idx = -1;

- // Get a funcref for the function name.
- // TODO: better way to find the "(".
- paren = vim_strchr(arg, '(');
- if (paren == NULL)
+ if (*arg == '(')
{
- semsg(_(e_missing_parenthesis_str), arg);
- return NULL;
+ // a lambda function
+ if (compile_lambda(&arg, cctx) != OK)
+ return NULL;
+ paren = arg;
+ }
+ else
+ {
+ // Get a funcref for the function name.
+ // TODO: better way to find the "(".
+ paren = vim_strchr(arg, '(');
+ if (paren == NULL)
+ {
+ semsg(_(e_missing_parenthesis_str), arg);
+ return NULL;
+ }
+ *paren = NUL;
+ func_idx = find_internal_func(arg);
+ if (func_idx >= 0)
+ // TODO: better type
+ generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
+ &t_func_any, FALSE);
+ else if (compile_expr0(&arg, cctx) == FAIL)
+ return NULL;
+ *paren = '(';
}
- *paren = NUL;
- func_idx = find_internal_func(arg);
- if (func_idx >= 0)
- // TODO: better type
- generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
- &t_func_any, FALSE);
- else if (compile_expr0(&arg, cctx) == FAIL)
- return NULL;
- *paren = '(';

// check for function type
if (cctx->ctx_skip != SKIP_YES)
diff --git a/src/vim9expr.c b/src/vim9expr.c
index ab14afc33..f692eeff3 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -1747,7 +1747,7 @@ compile_tuple(
* "*arg" points to the '('.
* Returns OK/FAIL when a lambda is recognized, NOTDONE if it's not a lambda.
*/
- static int
+ int
compile_lambda(char_u **arg, cctx_T *cctx)
{
int r;
Reply all
Reply to author
Forward
0 new messages