0
0
mirror of https://github.com/vim/vim.git synced 2025-11-14 23:04:02 -05:00

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 <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2025-10-27 18:07:52 +00:00
committed by Christian Brabandt
parent 58ab3438b7
commit 21ef3c6e59
6 changed files with 136 additions and 18 deletions

View File

@@ -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 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 No range is accepted. The function can be a partial with extra arguments, but
not with a dictionary. *E1300* 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 ~ 4. Automatically loading functions ~

View File

@@ -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); 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_end(char_u *arg, int use_namespace);
char_u *to_name_const_end(char_u *arg); 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); 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); exprtype_T get_compare_type(char_u *p, int *len, int *type_is);
void skip_expr_cctx(char_u **arg, cctx_T *cctx); void skip_expr_cctx(char_u **arg, cctx_T *cctx);

View File

@@ -5249,6 +5249,102 @@ def Test_defer_lambda_funcref()
v9.CheckSourceSuccess(lines) v9.CheckSourceSuccess(lines)
enddef 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. " Test for using an non-existing type in a "for" statement.
def Test_invalid_type_in_for() def Test_invalid_type_in_for()
var lines =<< trim END var lines =<< trim END

View File

@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1882,
/**/ /**/
1881, 1881,
/**/ /**/

View File

@@ -2040,25 +2040,35 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
int argcount = 0; int argcount = 0;
int defer_var_idx; int defer_var_idx;
type_T *type = NULL; type_T *type = NULL;
int func_idx; int func_idx = -1;
// Get a funcref for the function name. if (*arg == '(')
// TODO: better way to find the "(".
paren = vim_strchr(arg, '(');
if (paren == NULL)
{ {
semsg(_(e_missing_parenthesis_str), arg); // a lambda function
return NULL; 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 // check for function type
if (cctx->ctx_skip != SKIP_YES) if (cctx->ctx_skip != SKIP_YES)

View File

@@ -1747,7 +1747,7 @@ compile_tuple(
* "*arg" points to the '('. * "*arg" points to the '('.
* Returns OK/FAIL when a lambda is recognized, NOTDONE if it's not a lambda. * 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) compile_lambda(char_u **arg, cctx_T *cctx)
{ {
int r; int r;