summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-06 21:02:35 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-06 21:02:35 +0100
commit98aff658d5f97629d7c3a9fccac6c79fc9c6029d (patch)
tree373e25478552ba5098d844e6bce825629190222a
parentca16c60f337ed33d5dd66a6e90aaf95b619c5e47 (diff)
downloadvim-git-98aff658d5f97629d7c3a9fccac6c79fc9c6029d.tar.gz
patch 9.0.0399: using :defer in expression funcref not testedv9.0.0399
Problem: Using :defer in expression funcref not tested. Solution: Add a test. Fix uncovered problems.
-rw-r--r--src/proto/vim9execute.pro2
-rw-r--r--src/testdir/test_user_func.vim32
-rw-r--r--src/userfunc.c14
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c23
5 files changed, 69 insertions, 4 deletions
diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro
index d43b1e2eb..bb3d414e7 100644
--- a/src/proto/vim9execute.pro
+++ b/src/proto/vim9execute.pro
@@ -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);
diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim
index d7cfae1e9..ecf90b61a 100644
--- a/src/testdir/test_user_func.vim
+++ b/src/testdir/test_user_func.vim
@@ -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
diff --git a/src/userfunc.c b/src/userfunc.c
index 801425df8..76ab6b9d8 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -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);
diff --git a/src/version.c b/src/version.c
index a734b1578..025b5763a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 399,
+/**/
398,
/**/
397,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 40b23bdd2..46251545e 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -860,6 +860,27 @@ in_def_function(void)
}
/*
+ * 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.
* Return the list or NULL when failed.
@@ -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;
}