# HG changeset patch # User Bram Moolenaar # Date 1589657410 -7200 # Node ID 5950284a517fc35fc62eedcc8a4211e5518ede56 # Parent 05b26264315a07a08784336983b3f6bee6dfdbfb patch 8.2.0771: Vim9: cannot call a compiled closure from not compiled code Commit: https://github.com/vim/vim/commit/6f5b6dfb16228c0ce1e4379b7bafed02eaddbab2 Author: Bram Moolenaar Date: Sat May 16 21:20:12 2020 +0200 patch 8.2.0771: Vim9: cannot call a compiled closure from not compiled code Problem: Vim9: cannot call a compiled closure from not compiled code. Solution: Pass funcexe to call_user_func(). diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -246,7 +246,8 @@ eval_expr_typval(typval_T *expr, typval_ if (partial->pt_func != NULL && partial->pt_func->uf_dfunc_idx >= 0) { - if (call_def_function(partial->pt_func, argc, argv, rettv) == FAIL) + if (call_def_function(partial->pt_func, argc, argv, + partial, rettv) == FAIL) return FAIL; } else diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro --- a/src/proto/vim9execute.pro +++ b/src/proto/vim9execute.pro @@ -1,7 +1,6 @@ /* vim9execute.c */ -int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, typval_T *rettv); +int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv); void ex_disassemble(exarg_T *eap); int tv2bool(typval_T *tv); int check_not_string(typval_T *tv); -int set_ref_in_dfunc(ufunc_T *ufunc, int copyID); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -792,5 +792,15 @@ def Test_nested_closure() assert_equal('text!!!', Closure('!!!')) enddef +func GetResult(Ref) + return a:Ref('some') +endfunc + +def Test_call_closure_not_compiled() + let text = 'text' + g:Ref = {s -> s .. text} + assert_equal('sometext', GetResult(g:Ref)) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1062,8 +1062,7 @@ call_user_func( int argcount, // nr of args typval_T *argvars, // arguments typval_T *rettv, // return value - linenr_T firstline, // first line of range - linenr_T lastline, // last line of range + funcexe_T *funcexe, // context dict_T *selfdict) // Dictionary for "self" { sctx_T save_current_sctx; @@ -1120,7 +1119,7 @@ call_user_func( current_sctx = fp->uf_script_ctx; // Execute the compiled function. - call_def_function(fp, argcount, argvars, rettv); + call_def_function(fp, argcount, argvars, funcexe->partial, rettv); --depth; current_funccal = fc->caller; @@ -1194,9 +1193,9 @@ call_user_func( if ((fp->uf_flags & FC_NOARGS) == 0) { add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline", - (varnumber_T)firstline); + (varnumber_T)funcexe->firstline); add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", - (varnumber_T)lastline); + (varnumber_T)funcexe->lastline); } for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i) { @@ -1515,9 +1514,8 @@ call_user_func_check( did_save_redo = TRUE; } ++fp->uf_calls; - call_user_func(fp, argcount, argvars, rettv, - funcexe->firstline, funcexe->lastline, - (fp->uf_flags & FC_DICT) ? selfdict : NULL); + call_user_func(fp, argcount, argvars, rettv, funcexe, + (fp->uf_flags & FC_DICT) ? selfdict : NULL); if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) // Function was unreferenced while being used, free it now. func_clear_free(fp, FALSE); @@ -4293,7 +4291,7 @@ find_hi_in_scoped_ht(char_u *name, hasht if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) return NULL; - // Search in parent scope which is possible to reference from lambda + // Search in parent scope, which can be referenced from a lambda. current_funccal = current_funccal->func->uf_scoped; while (current_funccal != NULL) { diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 771, +/**/ 770, /**/ 769, diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -641,6 +641,7 @@ call_def_function( ufunc_T *ufunc, int argc_arg, // nr of arguments typval_T *argv, // arguments + partial_T *partial, // optional partial for context typval_T *rettv) // return value { ectx_T ectx; // execution context @@ -720,6 +721,12 @@ call_def_function( ectx.ec_frame_idx = ectx.ec_stack.ga_len; initial_frame_idx = ectx.ec_frame_idx; + if (partial != NULL) + { + ectx.ec_outer_stack = partial->pt_ectx_stack; + ectx.ec_outer_frame = partial->pt_ectx_frame; + } + // dummy frame entries for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) { @@ -1468,7 +1475,7 @@ call_def_function( { cpfunc_T *pfunc = &iptr->isn_arg.pfunc; int r; - typval_T partial; + typval_T partial_tv; SOURCING_LNUM = iptr->isn_lnum; if (pfunc->cpf_top) @@ -1480,12 +1487,12 @@ call_def_function( { // Get the funcref from the stack. --ectx.ec_stack.ga_len; - partial = *STACK_TV_BOT(0); - tv = &partial; + partial_tv = *STACK_TV_BOT(0); + tv = &partial_tv; } r = call_partial(tv, pfunc->cpf_argcount, &ectx); - if (tv == &partial) - clear_tv(&partial); + if (tv == &partial_tv) + clear_tv(&partial_tv); if (r == FAIL) goto failed; }