Skip to content

Commit 98aff65

Browse files
committed
patch 9.0.0399: using :defer in expression funcref not tested
Problem: Using :defer in expression funcref not tested. Solution: Add a test. Fix uncovered problems.
1 parent ca16c60 commit 98aff65

5 files changed

Lines changed: 69 additions & 4 deletions

File tree

src/proto/vim9execute.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ void update_has_breakpoint(ufunc_T *ufunc);
44
void funcstack_check_refcount(funcstack_T *funcstack);
55
int set_ref_in_funcstacks(int copyID);
66
int in_def_function(void);
7+
ectx_T *clear_currrent_ectx(void);
8+
void restore_current_ectx(ectx_T *ectx);
79
int add_defer_function(char_u *name, int argcount, typval_T *argvars);
810
char_u *char_from_string(char_u *str, varnumber_T index);
911
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);

src/testdir/test_user_func.vim

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,5 +625,37 @@ func Test_defer_quitall()
625625
call assert_false(filereadable('XQuitallTwo'))
626626
endfunc
627627

628+
func FuncIndex(idx, val)
629+
call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
630+
return a:val == 'c'
631+
endfunc
632+
633+
def DefIndex(idx: number, val: string): bool
634+
call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
635+
return val == 'c'
636+
enddef
637+
638+
def Test_defer_in_funcref()
639+
assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
640+
assert_false(filereadable('Xentry0'))
641+
assert_false(filereadable('Xentry1'))
642+
assert_false(filereadable('Xentry2'))
643+
644+
assert_equal(2, indexof(['a', 'b', 'c'], g:DefIndex))
645+
assert_false(filereadable('Xentry0'))
646+
assert_false(filereadable('Xentry1'))
647+
assert_false(filereadable('Xentry2'))
648+
649+
assert_equal(2, indexof(['a', 'b', 'c'], function('g:DefIndex')))
650+
assert_false(filereadable('Xentry0'))
651+
assert_false(filereadable('Xentry1'))
652+
assert_false(filereadable('Xentry2'))
653+
654+
assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndex)))
655+
assert_false(filereadable('Xentry0'))
656+
assert_false(filereadable('Xentry1'))
657+
assert_false(filereadable('Xentry2'))
658+
enddef
659+
628660

629661
" vim: shiftwidth=2 sts=2 expandtab

src/userfunc.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2593,6 +2593,7 @@ call_user_func(
25932593
dict_T *selfdict) // Dictionary for "self"
25942594
{
25952595
sctx_T save_current_sctx;
2596+
ectx_T *save_current_ectx;
25962597
int using_sandbox = FALSE;
25972598
int save_sticky_cmdmod_flags = sticky_cmdmod_flags;
25982599
funccall_T *fc;
@@ -2669,9 +2670,9 @@ call_user_func(
26692670
islambda = fp->uf_flags & FC_LAMBDA;
26702671

26712672
/*
2672-
* Note about using fc->fc_fixvar[]: This is an array of FIXVAR_CNT variables
2673-
* with names up to VAR_SHORT_LEN long. This avoids having to alloc/free
2674-
* each argument variable and saves a lot of time.
2673+
* Note about using fc->fc_fixvar[]: This is an array of FIXVAR_CNT
2674+
* variables with names up to VAR_SHORT_LEN long. This avoids having to
2675+
* alloc/free each argument variable and saves a lot of time.
26752676
*/
26762677
/*
26772678
* Init l: variables.
@@ -2885,6 +2886,11 @@ call_user_func(
28852886
// "legacy" does not apply to commands in the function
28862887
sticky_cmdmod_flags = 0;
28872888

2889+
// If called from a compiled :def function the execution context must be
2890+
// hidden, any deferred functions need to be added to the function being
2891+
// executed here.
2892+
save_current_ectx = clear_currrent_ectx();
2893+
28882894
save_current_sctx = current_sctx;
28892895
current_sctx = fp->uf_script_ctx;
28902896
save_did_emsg = did_emsg;
@@ -2974,6 +2980,8 @@ call_user_func(
29742980
ESTACK_CHECK_NOW
29752981
estack_pop();
29762982
current_sctx = save_current_sctx;
2983+
restore_current_ectx(save_current_ectx);
2984+
29772985
#ifdef FEAT_PROFILE
29782986
if (do_profiling == PROF_YES)
29792987
script_prof_restore(&profile_info.pi_wait_start);

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ static char *(features[]) =
703703

704704
static int included_patches[] =
705705
{ /* Add new patch number below this line */
706+
/**/
707+
399,
706708
/**/
707709
398,
708710
/**/

src/vim9execute.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,27 @@ in_def_function(void)
859859
return current_ectx != NULL;
860860
}
861861

862+
/*
863+
* Clear "current_ectx" and return the previous value. To be used when calling
864+
* a user function.
865+
*/
866+
ectx_T *
867+
clear_currrent_ectx(void)
868+
{
869+
ectx_T *r = current_ectx;
870+
871+
current_ectx = NULL;
872+
return r;
873+
}
874+
875+
void
876+
restore_current_ectx(ectx_T *ectx)
877+
{
878+
if (current_ectx != NULL)
879+
iemsg("Restoring current_ectx while it is not NULL");
880+
current_ectx = ectx;
881+
}
882+
862883
/*
863884
* Add an entry for a deferred function call to the currently executing
864885
* function.
@@ -5335,7 +5356,7 @@ call_def_function(
53355356
if (idx < 0)
53365357
{
53375358
semsg(NGETTEXT(e_one_argument_too_few, e_nr_arguments_too_few,
5338-
-idx), -idx);
5359+
-idx), -idx);
53395360
goto failed_early;
53405361
}
53415362

0 commit comments

Comments
 (0)