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:
13
src/eval.c
13
src/eval.c
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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'
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user