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 -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220907162851.817DB1C0CE4%40moolenaar.net.

Raspunde prin e-mail lui