changeset 20433:5950284a517f v8.2.0771

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 <Bram@vim.org> 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().
author Bram Moolenaar <Bram@vim.org>
date Sat, 16 May 2020 21:30:10 +0200
parents 05b26264315a
children e690ca8ee51c
files src/eval.c src/proto/vim9execute.pro src/testdir/test_vim9_func.vim src/userfunc.c src/version.c src/vim9execute.c
diffstat 6 files changed, 34 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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 : */
--- 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
--- 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)
     {
--- 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,
--- 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;
 		}