Skip to content

Commit 9667b2c

Browse files
committed
patch 9.0.0406: deferred functions not invoked when partial func exits
Problem: Deferred functions not invoked when partial func exits. Solution: Create a funccall_T when calling a :def function.
1 parent c9c967d commit 9667b2c

5 files changed

Lines changed: 73 additions & 11 deletions

File tree

src/eval.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,17 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
263263
if (partial->pt_func != NULL
264264
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED)
265265
{
266+
funccall_T *fc = create_funccal(partial->pt_func, rettv);
267+
int r;
268+
269+
if (fc == NULL)
270+
return FAIL;
271+
266272
// Shortcut to call a compiled function without overhead.
267-
// FIXME: should create a funccal and link it in current_funccal.
268-
if (call_def_function(partial->pt_func, argc, argv,
269-
DEF_USE_PT_ARGV, partial, NULL, rettv) == FAIL)
273+
r = call_def_function(partial->pt_func, argc, argv,
274+
DEF_USE_PT_ARGV, partial, fc, rettv);
275+
remove_funccal();
276+
if (r == FAIL)
270277
return FAIL;
271278
}
272279
else

src/proto/userfunc.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ int funcdepth_increment(void);
2121
void funcdepth_decrement(void);
2222
int funcdepth_get(void);
2323
void funcdepth_restore(int depth);
24+
funccall_T *create_funccal(ufunc_T *fp, typval_T *rettv);
25+
void remove_funccal(void);
2426
int check_user_func_argcount(ufunc_T *fp, int argcount);
2527
int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
2628
void save_funccal(funccal_entry_T *entry);

src/testdir/test_user_func.vim

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

628+
func Test_defer_quitall_in_expr_func()
629+
let lines =<< trim END
630+
def DefIndex(idx: number, val: string): bool
631+
call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
632+
if val == 'b'
633+
qa!
634+
endif
635+
return val == 'c'
636+
enddef
637+
638+
def Test_defer_in_funcref()
639+
assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex')))
640+
enddef
641+
call Test_defer_in_funcref()
642+
END
643+
call writefile(lines, 'XdeferQuitallExpr', 'D')
644+
let res = system(GetVimCommandClean() .. ' -X -S XdeferQuitallExpr')
645+
call assert_equal(0, v:shell_error)
646+
call assert_false(filereadable('Xentry0'))
647+
call assert_false(filereadable('Xentry1'))
648+
call assert_false(filereadable('Xentry2'))
649+
endfunc
650+
628651
func FuncIndex(idx, val)
629652
call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
630653
return a:val == 'c'

src/userfunc.c

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2580,6 +2580,40 @@ funcdepth_restore(int depth)
25802580
funcdepth = depth;
25812581
}
25822582

2583+
/*
2584+
* Allocate a funccall_T, link it in current_funccal and fill in "fp" and
2585+
* "rettv".
2586+
* Must be followed by one call to remove_funccal() or cleanup_function_call().
2587+
* Returns NULL when allocation fails.
2588+
*/
2589+
funccall_T *
2590+
create_funccal(ufunc_T *fp, typval_T *rettv)
2591+
{
2592+
funccall_T *fc = ALLOC_CLEAR_ONE(funccall_T);
2593+
2594+
if (fc == NULL)
2595+
return NULL;
2596+
fc->fc_caller = current_funccal;
2597+
current_funccal = fc;
2598+
fc->fc_func = fp;
2599+
func_ptr_ref(fp);
2600+
fc->fc_rettv = rettv;
2601+
return fc;
2602+
}
2603+
2604+
/*
2605+
* To be called when returning from a compiled function; restores
2606+
* current_funccal.
2607+
*/
2608+
void
2609+
remove_funccal()
2610+
{
2611+
funccall_T *fc = current_funccal;
2612+
2613+
current_funccal = fc->fc_caller;
2614+
free_funccal(fc);
2615+
}
2616+
25832617
/*
25842618
* Call a user function.
25852619
*/
@@ -2627,20 +2661,15 @@ call_user_func(
26272661

26282662
line_breakcheck(); // check for CTRL-C hit
26292663

2630-
fc = ALLOC_CLEAR_ONE(funccall_T);
2664+
fc = create_funccal(fp, rettv);
26312665
if (fc == NULL)
26322666
return;
2633-
fc->fc_caller = current_funccal;
2634-
current_funccal = fc;
2635-
fc->fc_func = fp;
2636-
fc->fc_rettv = rettv;
26372667
fc->fc_level = ex_nesting_level;
26382668
// Check if this function has a breakpoint.
26392669
fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
26402670
fc->fc_dbg_tick = debug_tick;
26412671
// Set up fields for closure.
26422672
ga_init2(&fc->fc_ufuncs, sizeof(ufunc_T *), 1);
2643-
func_ptr_ref(fp);
26442673

26452674
if (fp->uf_def_status != UF_NOT_COMPILED)
26462675
{
@@ -2661,8 +2690,7 @@ call_user_func(
26612690
|| (caller != NULL && caller->uf_profiling)))
26622691
profile_may_end_func(&profile_info, fp, caller);
26632692
#endif
2664-
current_funccal = fc->fc_caller;
2665-
free_funccal(fc);
2693+
remove_funccal();
26662694
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
26672695
return;
26682696
}

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+
406,
706708
/**/
707709
405,
708710
/**/

0 commit comments

Comments
 (0)