0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

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().
This commit is contained in:
Bram Moolenaar 2020-05-16 21:20:12 +02:00
parent aa5fc4ec51
commit 6f5b6dfb16
6 changed files with 34 additions and 17 deletions

View File

@ -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

View File

@ -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 : */

View File

@ -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

View File

@ -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)
{

View File

@ -746,6 +746,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
771,
/**/
770,
/**/

View File

@ -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;
}