patch 9.2.1157: Vim9: a lambda called after a constant operand is not callable

Problem:  In a :def function a lambda in parentheses that is called
          right after a constant operand gives E1085, while it works at
          the script level: the constant is pushed on the stack after
          the lambda.
Solution: Generate the pending constants before the lambda.

closes: #21403

Assisted-by: Claude
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Hirohito Higashi authored and Christian Brabandt committed 2026-09-30 19:48:15 +00:00
1 parent 43725acce6
commit 950f613ae1
5 files changed
+27 -4

No files matched your search

+1 -1
View File
@@ -8,7 +8,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 compile_lambda(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
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);
+12
View File
@@ -2800,6 +2800,18 @@ def Test_expr9_lambda()
eval (name + 2) / 3
END
v9.CheckDefAndScriptSuccess(lines)
# a lambda called after a constant operand
lines =<< trim END
assert_equal('ab', 'a' .. ((x) => x)('b'))
assert_equal('ab', 'a' .. (((x) => x)('b')))
assert_equal(3, 1 + ((x) => x)(2))
assert_equal('ab', 'a' .. ((x) => x)->call(['b']))
assert_equal('/a/x', ((cwdpath: string) => cwdpath
->strpart(0, cwdpath->strridx('/vim')))('/a/vim/b')
.. '/x')
END
v9.CheckDefAndScriptSuccess(lines)
enddef
def Test_expr9_lambda_block()
+2
View File
@@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1157,
/**/
1156,
/**/
+1 -1
View File
@@ -2079,7 +2079,7 @@ compile_defer(char_u *arg_start, cctx_T *cctx)
if (*arg == '(')
{
// a lambda function
if (compile_lambda(&arg, cctx) != OK)
if (compile_lambda(&arg, cctx, NULL) != OK)
return NULL;
paren = vim_strchr(arg, '(');
if (paren == NULL)
+11 -2
View File
@@ -1767,10 +1767,12 @@ restore_cmdline_arg(evalarg_T *evalarg, char_u **arg, cctx_T *cctx)
/*
* Parse a lambda: "(arg, arg) => expr"
* "*arg" points to the '('.
* When "ppconst" is not NULL the constants in it are generated before the
* lambda, which goes on top of them on the stack.
* Returns OK/FAIL when a lambda is recognized, NOTDONE if it's not a lambda.
*/
int
compile_lambda(char_u **arg, cctx_T *cctx)
compile_lambda(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
int r;
typval_T rettv;
@@ -1789,6 +1791,13 @@ compile_lambda(char_u **arg, cctx_T *cctx)
return r;
}
if (ppconst != NULL && generate_ppconst(cctx, ppconst) == FAIL)
{
clear_tv(&rettv);
clear_evalarg(&evalarg, NULL);
return FAIL;
}
// "rettv" will now be a partial referencing the function.
ufunc = rettv.vval.v_partial->pt_func;
++ufunc->uf_refcount;
@@ -3120,7 +3129,7 @@ compile_expr9(
* funcref: (arg, arg) => { statement }
*/
case '(': // if compile_lambda returns NOTDONE then it must be (expr)
ret = compile_lambda(arg, cctx);
ret = compile_lambda(arg, cctx, ppconst);
if (ret == NOTDONE)
ret = compile_parenthesis(arg, cctx, ppconst);
break;