Patch 9.0.0406
Problem: Deferred functions not invoked when partial func exits.
Solution: Create a funccall_T when calling a :def function.
Files: src/eval.c, src/userfunc.c, src/proto/
userfunc.pro,
src/testdir/test_user_func.vim
*** ../vim-9.0.0405/src/eval.c 2022-09-07 16:48:41.183678514 +0100
--- src/eval.c 2022-09-07 17:26:32.354072267 +0100
***************
*** 263,272 ****
if (partial->pt_func != NULL
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED)
{
// Shortcut to call a compiled function without overhead.
! // FIXME: should create a funccal and link it in current_funccal.
! if (call_def_function(partial->pt_func, argc, argv,
! DEF_USE_PT_ARGV, partial, NULL, rettv) == FAIL)
return FAIL;
}
else
--- 263,279 ----
if (partial->pt_func != NULL
&& 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.
! r = call_def_function(partial->pt_func, argc, argv,
! DEF_USE_PT_ARGV, partial, fc, rettv);
! remove_funccal();
! if (r == FAIL)
return FAIL;
}
else
*** ../vim-9.0.0405/src/userfunc.c 2022-09-07 16:48:41.183678514 +0100
--- src/userfunc.c 2022-09-07 17:23:51.038417559 +0100
***************
*** 2581,2586 ****
--- 2581,2620 ----
}
/*
+ * 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.
*/
static void
***************
*** 2627,2646 ****
line_breakcheck(); // check for CTRL-C hit
! fc = ALLOC_CLEAR_ONE(funccall_T);
if (fc == NULL)
return;
- fc->fc_caller = current_funccal;
- current_funccal = fc;
- fc->fc_func = fp;
- fc->fc_rettv = rettv;
fc->fc_level = ex_nesting_level;
// Check if this function has a breakpoint.
fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
fc->fc_dbg_tick = debug_tick;
// Set up fields for closure.
ga_init2(&fc->fc_ufuncs, sizeof(ufunc_T *), 1);
- func_ptr_ref(fp);
if (fp->uf_def_status != UF_NOT_COMPILED)
{
--- 2661,2675 ----
line_breakcheck(); // check for CTRL-C hit
! fc = create_funccal(fp, rettv);
if (fc == NULL)
return;
fc->fc_level = ex_nesting_level;
// Check if this function has a breakpoint.
fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
fc->fc_dbg_tick = debug_tick;
// Set up fields for closure.
ga_init2(&fc->fc_ufuncs, sizeof(ufunc_T *), 1);
if (fp->uf_def_status != UF_NOT_COMPILED)
{
***************
*** 2661,2668 ****
|| (caller != NULL && caller->uf_profiling)))
profile_may_end_func(&profile_info, fp, caller);
#endif
! current_funccal = fc->fc_caller;
! free_funccal(fc);
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
return;
}
--- 2690,2696 ----
|| (caller != NULL && caller->uf_profiling)))
profile_may_end_func(&profile_info, fp, caller);
#endif
! remove_funccal();
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
return;
}
*** ../vim-9.0.0405/src/proto/
userfunc.pro 2022-09-06 18:31:09.070310282 +0100
--- src/proto/
userfunc.pro 2022-09-07 17:08:30.480315750 +0100
***************
*** 21,26 ****
--- 21,28 ----
void funcdepth_decrement(void);
int funcdepth_get(void);
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 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);
*** ../vim-9.0.0405/src/testdir/test_user_func.vim 2022-09-07 16:48:41.183678514 +0100
--- src/testdir/test_user_func.vim 2022-09-07 17:13:05.747581444 +0100
***************
*** 625,630 ****
--- 625,653 ----
call assert_false(filereadable('XQuitallTwo'))
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)
call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
return a:val == 'c'
*** ../vim-9.0.0405/src/version.c 2022-09-07 16:48:41.187678502 +0100
--- src/version.c 2022-09-07 16:59:38.725760728 +0100
***************
*** 705,706 ****
--- 705,708 ----
{ /* Add new patch number below this line */
+ /**/
+ 406,
/**/
--
Don't Panic!
-- The Hitchhiker's Guide to the Galaxy
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///