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:
1 parent
43725acce6
commit
950f613ae1
5 files changed
+27
-4
No files matched your search
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -763,6 +763,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1157,
|
||||
/**/
|
||||
1156,
|
||||
/**/
|
||||
|
||||
+1
-1
@@ -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
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user