To: vim_dev@googlegroups.com Subject: Patch 9.0.0406 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///