diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-09-06 21:02:35 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-09-06 21:02:35 +0100 |
commit | 98aff658d5f97629d7c3a9fccac6c79fc9c6029d (patch) | |
tree | 373e25478552ba5098d844e6bce825629190222a | |
parent | ca16c60f337ed33d5dd66a6e90aaf95b619c5e47 (diff) | |
download | vim-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.pro | 2 | ||||
-rw-r--r-- | src/testdir/test_user_func.vim | 32 | ||||
-rw-r--r-- | src/userfunc.c | 14 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9execute.c | 23 |
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; } |