From: Bram Moolenaar Date: Sat, 16 May 2020 19:20:12 +0000 (+0200) Subject: patch 8.2.0771: Vim9: cannot call a compiled closure from not compiled code X-Git-Tag: v8.2.0771 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6f5b6dfb16228c0ce1e4379b7bafed02eaddbab2;p=vim 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 index 77359dcca..dbc10c1b6 100644 --- a/src/eval.c +++ b/src/eval.c @@ -246,7 +246,8 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv) 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 index 578fe81e1..eac8979af 100644 --- 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 index c74b4a451..100d86aa6 100644 --- 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 index b3c4f900a..99c45b3e7 100644 --- 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, hashtab_T **pht) 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 index 277650488..c369a7160 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 771, /**/ 770, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index c910dbc96..fe6adda60 100644 --- 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; }