0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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.
This commit is contained in:
Bram Moolenaar
2022-09-07 17:28:09 +01:00
parent c9c967da09
commit 9667b2c888
5 changed files with 73 additions and 11 deletions

View File

@@ -263,10 +263,17 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
if (partial->pt_func != NULL if (partial->pt_func != NULL
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED) && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
{ {
funccall_T *fc = create_funccal(partial->pt_func, rettv);
int r;
if (fc == NULL)
return FAIL;
// Shortcut to call a compiled function without overhead. // Shortcut to call a compiled function without overhead.
// FIXME: should create a funccal and link it in current_funccal. r = call_def_function(partial->pt_func, argc, argv,
if (call_def_function(partial->pt_func, argc, argv, DEF_USE_PT_ARGV, partial, fc, rettv);
DEF_USE_PT_ARGV, partial, NULL, rettv) == FAIL) remove_funccal();
if (r == FAIL)
return FAIL; return FAIL;
} }
else else

View File

@@ -21,6 +21,8 @@ int funcdepth_increment(void);
void funcdepth_decrement(void); void funcdepth_decrement(void);
int funcdepth_get(void); int funcdepth_get(void);
void funcdepth_restore(int depth); void funcdepth_restore(int depth);
funccall_T *create_funccal(ufunc_T *fp, typval_T *rettv);
void remove_funccal(void);
int check_user_func_argcount(ufunc_T *fp, int argcount); int check_user_func_argcount(ufunc_T *fp, int argcount);
int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
void save_funccal(funccal_entry_T *entry); void save_funccal(funccal_entry_T *entry);

View File

@@ -625,6 +625,29 @@ func Test_defer_quitall()
call assert_false(filereadable('XQuitallTwo')) call assert_false(filereadable('XQuitallTwo'))
endfunc endfunc
func Test_defer_quitall_in_expr_func()
let lines =<< trim END
def DefIndex(idx: number, val: string): bool
call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
if val == 'b'
qa!
endif
return val == 'c'
enddef
def Test_defer_in_funcref()
assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex')))
enddef
call Test_defer_in_funcref()
END
call writefile(lines, 'XdeferQuitallExpr', 'D')
let res = system(GetVimCommandClean() .. ' -X -S XdeferQuitallExpr')
call assert_equal(0, v:shell_error)
call assert_false(filereadable('Xentry0'))
call assert_false(filereadable('Xentry1'))
call assert_false(filereadable('Xentry2'))
endfunc
func FuncIndex(idx, val) func FuncIndex(idx, val)
call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D') call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
return a:val == 'c' return a:val == 'c'

View File

@@ -2580,6 +2580,40 @@ funcdepth_restore(int depth)
funcdepth = depth; funcdepth = depth;
} }
/*
* Allocate a funccall_T, link it in current_funccal and fill in "fp" and
* "rettv".
* Must be followed by one call to remove_funccal() or cleanup_function_call().
* Returns NULL when allocation fails.
*/
funccall_T *
create_funccal(ufunc_T *fp, typval_T *rettv)
{
funccall_T *fc = ALLOC_CLEAR_ONE(funccall_T);
if (fc == NULL)
return NULL;
fc->fc_caller = current_funccal;
current_funccal = fc;
fc->fc_func = fp;
func_ptr_ref(fp);
fc->fc_rettv = rettv;
return fc;
}
/*
* To be called when returning from a compiled function; restores
* current_funccal.
*/
void
remove_funccal()
{
funccall_T *fc = current_funccal;
current_funccal = fc->fc_caller;
free_funccal(fc);
}
/* /*
* Call a user function. * Call a user function.
*/ */
@@ -2627,20 +2661,15 @@ call_user_func(
line_breakcheck(); // check for CTRL-C hit line_breakcheck(); // check for CTRL-C hit
fc = ALLOC_CLEAR_ONE(funccall_T); fc = create_funccal(fp, rettv);
if (fc == NULL) if (fc == NULL)
return; return;
fc->fc_caller = current_funccal;
current_funccal = fc;
fc->fc_func = fp;
fc->fc_rettv = rettv;
fc->fc_level = ex_nesting_level; fc->fc_level = ex_nesting_level;
// Check if this function has a breakpoint. // Check if this function has a breakpoint.
fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
fc->fc_dbg_tick = debug_tick; fc->fc_dbg_tick = debug_tick;
// Set up fields for closure. // Set up fields for closure.
ga_init2(&fc->fc_ufuncs, sizeof(ufunc_T *), 1); ga_init2(&fc->fc_ufuncs, sizeof(ufunc_T *), 1);
func_ptr_ref(fp);
if (fp->uf_def_status != UF_NOT_COMPILED) if (fp->uf_def_status != UF_NOT_COMPILED)
{ {
@@ -2661,8 +2690,7 @@ call_user_func(
|| (caller != NULL && caller->uf_profiling))) || (caller != NULL && caller->uf_profiling)))
profile_may_end_func(&profile_info, fp, caller); profile_may_end_func(&profile_info, fp, caller);
#endif #endif
current_funccal = fc->fc_caller; remove_funccal();
free_funccal(fc);
sticky_cmdmod_flags = save_sticky_cmdmod_flags; sticky_cmdmod_flags = save_sticky_cmdmod_flags;
return; return;
} }

View File

@@ -703,6 +703,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
406,
/**/ /**/
405, 405,
/**/ /**/