]> granicus.if.org Git - vim/commitdiff
patch 9.0.0399: using :defer in expression funcref not tested v9.0.0399
authorBram Moolenaar <Bram@vim.org>
Tue, 6 Sep 2022 20:02:35 +0000 (21:02 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 6 Sep 2022 20:02:35 +0000 (21:02 +0100)
Problem:    Using :defer in expression funcref not tested.
Solution:   Add a test.  Fix uncovered problems.

src/proto/vim9execute.pro
src/testdir/test_user_func.vim
src/userfunc.c
src/version.c
src/vim9execute.c

index d43b1e2ebd7da3ddf8daff7ad45bd405dde7a78c..bb3d414e7ae95861584cf5d99c7020c86c746f55 100644 (file)
@@ -4,6 +4,8 @@ void update_has_breakpoint(ufunc_T *ufunc);
 void funcstack_check_refcount(funcstack_T *funcstack);
 int set_ref_in_funcstacks(int copyID);
 int in_def_function(void);
+ectx_T *clear_currrent_ectx(void);
+void restore_current_ectx(ectx_T *ectx);
 int add_defer_function(char_u *name, int argcount, typval_T *argvars);
 char_u *char_from_string(char_u *str, varnumber_T index);
 char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
index d7cfae1e9404d6bdc0885b2b4c772bd38ae72dbb..ecf90b61ab2feb9c0bcb38c9ef1a0f45ef4b9ecb 100644 (file)
@@ -625,5 +625,37 @@ func Test_defer_quitall()
   call assert_false(filereadable('XQuitallTwo'))
 endfunc
 
+func FuncIndex(idx, val)
+  call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
+  return a:val == 'c'
+endfunc
+
+def DefIndex(idx: number, val: string): bool
+  call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
+  return val == 'c'
+enddef
+
+def Test_defer_in_funcref()
+  assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
+  assert_false(filereadable('Xentry0'))
+  assert_false(filereadable('Xentry1'))
+  assert_false(filereadable('Xentry2'))
+
+  assert_equal(2, indexof(['a', 'b', 'c'], g:DefIndex))
+  assert_false(filereadable('Xentry0'))
+  assert_false(filereadable('Xentry1'))
+  assert_false(filereadable('Xentry2'))
+
+  assert_equal(2, indexof(['a', 'b', 'c'], function('g:DefIndex')))
+  assert_false(filereadable('Xentry0'))
+  assert_false(filereadable('Xentry1'))
+  assert_false(filereadable('Xentry2'))
+
+  assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndex)))
+  assert_false(filereadable('Xentry0'))
+  assert_false(filereadable('Xentry1'))
+  assert_false(filereadable('Xentry2'))
+enddef
+
 
 " vim: shiftwidth=2 sts=2 expandtab
index 801425df81536e7f080519c55a1d136638ff6f40..76ab6b9d8687aeb198f0b9278c65dbdd83e920d3 100644 (file)
@@ -2593,6 +2593,7 @@ call_user_func(
     dict_T     *selfdict)      // Dictionary for "self"
 {
     sctx_T     save_current_sctx;
+    ectx_T     *save_current_ectx;
     int                using_sandbox = FALSE;
     int                save_sticky_cmdmod_flags = sticky_cmdmod_flags;
     funccall_T *fc;
@@ -2669,9 +2670,9 @@ call_user_func(
     islambda = fp->uf_flags & FC_LAMBDA;
 
     /*
-     * Note about using fc->fc_fixvar[]: This is an array of FIXVAR_CNT variables
-     * with names up to VAR_SHORT_LEN long.  This avoids having to alloc/free
-     * each argument variable and saves a lot of time.
+     * Note about using fc->fc_fixvar[]: This is an array of FIXVAR_CNT
+     * variables with names up to VAR_SHORT_LEN long.  This avoids having to
+     * alloc/free each argument variable and saves a lot of time.
      */
     /*
      * Init l: variables.
@@ -2885,6 +2886,11 @@ call_user_func(
     // "legacy" does not apply to commands in the function
     sticky_cmdmod_flags = 0;
 
+    // If called from a compiled :def function the execution context must be
+    // hidden, any deferred functions need to be added to the function being
+    // executed here.
+    save_current_ectx = clear_currrent_ectx();
+
     save_current_sctx = current_sctx;
     current_sctx = fp->uf_script_ctx;
     save_did_emsg = did_emsg;
@@ -2974,6 +2980,8 @@ call_user_func(
     ESTACK_CHECK_NOW
     estack_pop();
     current_sctx = save_current_sctx;
+    restore_current_ectx(save_current_ectx);
+
 #ifdef FEAT_PROFILE
     if (do_profiling == PROF_YES)
        script_prof_restore(&profile_info.pi_wait_start);
index a734b1578a9971acfe3b030d3678e14779532070..025b5763ac87476cf9733240f9b0daeb0ec714e3 100644 (file)
@@ -703,6 +703,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    399,
 /**/
     398,
 /**/
index 40b23bdd207896e834ae5e9601c8381479d178dd..46251545ed9497ae297d1ef9125ebcc05e44c4e0 100644 (file)
@@ -859,6 +859,27 @@ in_def_function(void)
     return current_ectx != NULL;
 }
 
+/*
+ * Clear "current_ectx" and return the previous value.  To be used when calling
+ * a user function.
+ */
+    ectx_T *
+clear_currrent_ectx(void)
+{
+    ectx_T *r = current_ectx;
+
+    current_ectx = NULL;
+    return r;
+}
+
+    void
+restore_current_ectx(ectx_T *ectx)
+{
+    if (current_ectx != NULL)
+       iemsg("Restoring current_ectx while it is not NULL");
+    current_ectx = ectx;
+}
+
 /*
  * Add an entry for a deferred function call to the currently executing
  * function.
@@ -5335,7 +5356,7 @@ call_def_function(
     if (idx < 0)
     {
        semsg(NGETTEXT(e_one_argument_too_few, e_nr_arguments_too_few,
-                       -idx), -idx);
+                                                                 -idx), -idx);
        goto failed_early;
     }