Skip to content

Commit 21ef3c6

Browse files
yegappanchrisbra
authored andcommitted
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 <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 58ab343 commit 21ef3c6

6 files changed

Lines changed: 136 additions & 18 deletions

File tree

runtime/doc/userfunc.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*userfunc.txt* For Vim version 9.1. Last change: 2025 Oct 12
1+
*userfunc.txt* For Vim version 9.1. Last change: 2025 Oct 27
22

33

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

452+
In a |:def| function, a lambda can be used with |:defer|. Example: >
453+
454+
def Fn()
455+
set lazyredraw
456+
defer () => {
457+
set lazyredraw&
458+
}()
459+
enddef
460+
<
452461
==============================================================================
453462

454463
4. Automatically loading functions ~

src/proto/vim9expr.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ int compile_load(char_u **arg, size_t namelen, char_u *end_arg, cctx_T *cctx, in
77
int compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, ca_special_T special_fn);
88
char_u *to_name_end(char_u *arg, int use_namespace);
99
char_u *to_name_const_end(char_u *arg);
10+
int compile_lambda(char_u **arg, cctx_T *cctx);
1011
int get_lambda_tv_and_compile(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg);
1112
exprtype_T get_compare_type(char_u *p, int *len, int *type_is);
1213
void skip_expr_cctx(char_u **arg, cctx_T *cctx);

src/testdir/test_vim9_script.vim

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5249,6 +5249,102 @@ def Test_defer_lambda_funcref()
52495249
v9.CheckSourceSuccess(lines)
52505250
enddef
52515251

5252+
" Test for using defer with a lambda and a command block
5253+
def Test_defer_lambda_func()
5254+
var lines =<< trim END
5255+
vim9script
5256+
var result = ''
5257+
def Foo()
5258+
result = 'xxx'
5259+
defer (a: number, b: string): number => {
5260+
result = $'{a}:{b}'
5261+
return 0
5262+
}(10, 'aaa')
5263+
result = 'yyy'
5264+
enddef
5265+
Foo()
5266+
assert_equal('10:aaa', result)
5267+
END
5268+
v9.CheckScriptSuccess(lines)
5269+
5270+
# Error: argument type mismatch
5271+
lines =<< trim END
5272+
vim9script
5273+
def Foo()
5274+
defer (a: number, b: string): number => {
5275+
return 0
5276+
}(10, 20)
5277+
enddef
5278+
defcompile
5279+
END
5280+
v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number', 1)
5281+
5282+
# Error: not enough arguments
5283+
lines =<< trim END
5284+
vim9script
5285+
def Foo()
5286+
defer (a: number) => {
5287+
}()
5288+
enddef
5289+
defcompile
5290+
END
5291+
v9.CheckScriptFailure(lines, 'E119: Not enough arguments for function: (a: number) => {', 1)
5292+
5293+
# Error: too many arguments
5294+
lines =<< trim END
5295+
vim9script
5296+
def Foo()
5297+
defer () => {
5298+
}(10)
5299+
enddef
5300+
defcompile
5301+
END
5302+
v9.CheckScriptFailure(lines, 'E118: Too many arguments for function: () => {', 1)
5303+
5304+
# Error: invalid command in command-block
5305+
lines =<< trim END
5306+
vim9script
5307+
def Foo()
5308+
defer () => {
5309+
xxx
5310+
}()
5311+
enddef
5312+
defcompile
5313+
END
5314+
v9.CheckScriptFailure(lines, 'E476: Invalid command: xxx', 1)
5315+
5316+
# Error: missing return
5317+
lines =<< trim END
5318+
vim9script
5319+
def Foo()
5320+
defer (): number => {
5321+
}()
5322+
enddef
5323+
defcompile
5324+
END
5325+
v9.CheckScriptFailure(lines, 'E1027: Missing return statement', 1)
5326+
5327+
# Error: missing lambda body
5328+
lines =<< trim END
5329+
vim9script
5330+
def Foo()
5331+
defer (a: number): number
5332+
enddef
5333+
defcompile
5334+
END
5335+
v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1)
5336+
5337+
# Error: invalid lambda syntax
5338+
lines =<< trim END
5339+
vim9script
5340+
def Foo()
5341+
defer (
5342+
enddef
5343+
defcompile
5344+
END
5345+
v9.CheckScriptFailure(lines, 'E1028: Compiling :def function failed', 1)
5346+
enddef
5347+
52525348
" Test for using an non-existing type in a "for" statement.
52535349
def Test_invalid_type_in_for()
52545350
var lines =<< trim END

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,8 @@ static char *(features[]) =
729729

730730
static int included_patches[] =
731731
{ /* Add new patch number below this line */
732+
/**/
733+
1882,
732734
/**/
733735
1881,
734736
/**/

src/vim9cmds.c

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,25 +2040,35 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
20402040
int argcount = 0;
20412041
int defer_var_idx;
20422042
type_T *type = NULL;
2043-
int func_idx;
2043+
int func_idx = -1;
20442044

2045-
// Get a funcref for the function name.
2046-
// TODO: better way to find the "(".
2047-
paren = vim_strchr(arg, '(');
2048-
if (paren == NULL)
2045+
if (*arg == '(')
20492046
{
2050-
semsg(_(e_missing_parenthesis_str), arg);
2051-
return NULL;
2047+
// a lambda function
2048+
if (compile_lambda(&arg, cctx) != OK)
2049+
return NULL;
2050+
paren = arg;
2051+
}
2052+
else
2053+
{
2054+
// Get a funcref for the function name.
2055+
// TODO: better way to find the "(".
2056+
paren = vim_strchr(arg, '(');
2057+
if (paren == NULL)
2058+
{
2059+
semsg(_(e_missing_parenthesis_str), arg);
2060+
return NULL;
2061+
}
2062+
*paren = NUL;
2063+
func_idx = find_internal_func(arg);
2064+
if (func_idx >= 0)
2065+
// TODO: better type
2066+
generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
2067+
&t_func_any, FALSE);
2068+
else if (compile_expr0(&arg, cctx) == FAIL)
2069+
return NULL;
2070+
*paren = '(';
20522071
}
2053-
*paren = NUL;
2054-
func_idx = find_internal_func(arg);
2055-
if (func_idx >= 0)
2056-
// TODO: better type
2057-
generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
2058-
&t_func_any, FALSE);
2059-
else if (compile_expr0(&arg, cctx) == FAIL)
2060-
return NULL;
2061-
*paren = '(';
20622072

20632073
// check for function type
20642074
if (cctx->ctx_skip != SKIP_YES)

src/vim9expr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1747,7 +1747,7 @@ compile_tuple(
17471747
* "*arg" points to the '('.
17481748
* Returns OK/FAIL when a lambda is recognized, NOTDONE if it's not a lambda.
17491749
*/
1750-
static int
1750+
int
17511751
compile_lambda(char_u **arg, cctx_T *cctx)
17521752
{
17531753
int r;

0 commit comments

Comments
 (0)