diff --git a/src/proto/vim9expr.pro b/src/proto/vim9expr.pro index f59836e88f..d945a4f4e8 100644 --- a/src/proto/vim9expr.pro +++ b/src/proto/vim9expr.pro @@ -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); diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index d46c69171e..59e3f8948f 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -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() diff --git a/src/version.c b/src/version.c index 37d5701d2e..73375c6a03 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1157, /**/ 1156, /**/ diff --git a/src/vim9cmds.c b/src/vim9cmds.c index a40569ec9c..09f230d997 100644 --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -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) diff --git a/src/vim9expr.c b/src/vim9expr.c index 102554ee4b..532e4fc346 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -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;