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 77359dc..dbc10c1 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -246,7 +246,8 @@
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 578fe81..eac8979 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 c74b4a4..100d86a 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -792,5 +792,15 @@
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 b3c4f90..99c45b3 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -1062,8 +1062,7 @@
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 @@
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 @@
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 @@
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 @@
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 2776504..c369a71 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 771,
+/**/
770,
/**/
769,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index c910dbc..fe6adda 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -641,6 +641,7 @@
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 @@
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 @@
{
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 @@
{
// 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;
}