Patch 9.0.0405
Problem:    Arguments in a partial not used by a :def function.
Solution:   Put the partial arguments on the stack.
Files:      src/vim9execute.c, src/proto/vim9execute.pro, src/eval.c,
            src/vim9.h, src/userfunc.c, src/testdir/test_user_func.vim


*** ../vim-9.0.0404/src/vim9execute.c   2022-09-06 21:02:31.232361110 +0100
--- src/vim9execute.c   2022-09-07 16:30:21.087008722 +0100
***************
*** 5272,5287 ****
      ufunc_T   *ufunc,
      int               argc_arg,       // nr of arguments
      typval_T  *argv,          // arguments
      partial_T *partial,       // optional partial for context
      funccall_T        *funccal,
      typval_T  *rettv)         // return value
  {
      ectx_T    ectx;           // execution context
      int               argc = argc_arg;
      typval_T  *tv;
      int               idx;
      int               ret = FAIL;
!     int               defcount = ufunc->uf_args.ga_len - argc;
      sctx_T    save_current_sctx = current_sctx;
      int               did_emsg_before = did_emsg_cumul + did_emsg;
      int               save_suppress_errthrow = suppress_errthrow;
--- 5272,5292 ----
      ufunc_T   *ufunc,
      int               argc_arg,       // nr of arguments
      typval_T  *argv,          // arguments
+     int               flags,          // DEF_ flags
      partial_T *partial,       // optional partial for context
      funccall_T        *funccal,
      typval_T  *rettv)         // return value
  {
      ectx_T    ectx;           // execution context
      int               argc = argc_arg;
+     int               partial_argc = partial == NULL
+                                 || (flags & DEF_USE_PT_ARGV) == 0
+                                                       ? 0 : partial->pt_argc;
+     int               total_argc = argc + partial_argc;
      typval_T  *tv;
      int               idx;
      int               ret = FAIL;
!     int               defcount = ufunc->uf_args.ga_len - total_argc;
      sctx_T    save_current_sctx = current_sctx;
      int               did_emsg_before = did_emsg_cumul + did_emsg;
      int               save_suppress_errthrow = suppress_errthrow;
***************
*** 5345,5358 ****
      ectx.ec_did_emsg_before = did_emsg_before;
      ++ex_nesting_level;
  
!     idx = argc - ufunc->uf_args.ga_len;
      if (idx > 0 && ufunc->uf_va_name == NULL)
      {
        semsg(NGETTEXT(e_one_argument_too_many, e_nr_arguments_too_many,
!                       idx), idx);
        goto failed_early;
      }
!     idx = argc - ufunc->uf_args.ga_len + ufunc->uf_def_args.ga_len;
      if (idx < 0)
      {
        semsg(NGETTEXT(e_one_argument_too_few, e_nr_arguments_too_few,
--- 5350,5363 ----
      ectx.ec_did_emsg_before = did_emsg_before;
      ++ex_nesting_level;
  
!     idx = total_argc - ufunc->uf_args.ga_len;
      if (idx > 0 && ufunc->uf_va_name == NULL)
      {
        semsg(NGETTEXT(e_one_argument_too_many, e_nr_arguments_too_many,
!                                                                   idx), idx);
        goto failed_early;
      }
!     idx = total_argc - ufunc->uf_args.ga_len + ufunc->uf_def_args.ga_len;
      if (idx < 0)
      {
        semsg(NGETTEXT(e_one_argument_too_few, e_nr_arguments_too_few,
***************
*** 5360,5374 ****
        goto failed_early;
      }
  
!     // Put arguments on the stack, but no more than what the function expects.
!     // A lambda can be called with more arguments than it uses.
!     for (idx = 0; idx < argc
            && (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
                                                                         ++idx)
      {
        if (idx >= ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len
!               && argv[idx].v_type == VAR_SPECIAL
!               && argv[idx].vval.v_number == VVAL_NONE)
        {
            // Use the default value.
            STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
--- 5365,5383 ----
        goto failed_early;
      }
  
!     // Put values from the partial and arguments on the stack, but no more 
than
!     // what the function expects.  A lambda can be called with more arguments
!     // than it uses.
!     for (idx = 0; idx < total_argc
            && (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
                                                                         ++idx)
      {
+       int argv_idx = idx - partial_argc;
+ 
+       tv = idx < partial_argc ? partial->pt_argv + idx : argv + argv_idx;
        if (idx >= ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len
!               && tv->v_type == VAR_SPECIAL
!               && tv->vval.v_number == VVAL_NONE)
        {
            // Use the default value.
            STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
***************
*** 5377,5386 ****
        {
            if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
                    && check_typval_arg_type(
!                       ufunc->uf_arg_types[idx], &argv[idx],
!                                                       NULL, idx + 1) == FAIL)
                goto failed_early;
!           copy_tv(&argv[idx], STACK_TV_BOT(0));
        }
        ++ectx.ec_stack.ga_len;
      }
--- 5386,5395 ----
        {
            if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
                    && check_typval_arg_type(
!                       ufunc->uf_arg_types[idx], tv,
!                                                  NULL, argv_idx + 1) == FAIL)
                goto failed_early;
!           copy_tv(tv, STACK_TV_BOT(0));
        }
        ++ectx.ec_stack.ga_len;
      }
*** ../vim-9.0.0404/src/proto/vim9execute.pro   2022-09-06 21:02:31.232361110 
+0100
--- src/proto/vim9execute.pro   2022-09-07 16:30:46.222943186 +0100
***************
*** 15,21 ****
  int may_break_in_function(ufunc_T *ufunc);
  int exe_typval_instr(typval_T *tv, typval_T *rettv);
  char_u *exe_substitute_instr(void);
! int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T 
*partial, funccall_T *funccal, typval_T *rettv);
  void unwind_def_callstack(ectx_T *ectx);
  void may_invoke_defer_funcs(ectx_T *ectx);
  void set_context_in_disassemble_cmd(expand_T *xp, char_u *arg);
--- 15,21 ----
  int may_break_in_function(ufunc_T *ufunc);
  int exe_typval_instr(typval_T *tv, typval_T *rettv);
  char_u *exe_substitute_instr(void);
! int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, int 
flags, partial_T *partial, funccall_T *funccal, typval_T *rettv);
  void unwind_def_callstack(ectx_T *ectx);
  void may_invoke_defer_funcs(ectx_T *ectx);
  void set_context_in_disassemble_cmd(expand_T *xp, char_u *arg);
*** ../vim-9.0.0404/src/eval.c  2022-09-06 18:31:09.074310277 +0100
--- src/eval.c  2022-09-07 16:27:44.367422361 +0100
***************
*** 263,271 ****
        if (partial->pt_func != NULL
                          && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
        {
            // FIXME: should create a funccal and link it in current_funccal.
            if (call_def_function(partial->pt_func, argc, argv,
!                                                partial, NULL, rettv) == FAIL)
                return FAIL;
        }
        else
--- 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
*** ../vim-9.0.0404/src/vim9.h  2022-09-03 21:35:50.184158219 +0100
--- src/vim9.h  2022-09-07 16:27:20.539486123 +0100
***************
*** 759,761 ****
--- 759,763 ----
  #define TVTT_DO_MEMBER            1
  #define TVTT_MORE_SPECIFIC  2 // get most specific type for member
  
+ // flags for call_def_function()
+ #define DEF_USE_PT_ARGV           1   // use the partial arguments
*** ../vim-9.0.0404/src/userfunc.c      2022-09-06 21:02:31.232361110 +0100
--- src/userfunc.c      2022-09-07 16:28:29.135303233 +0100
***************
*** 2653,2659 ****
            profile_may_start_func(&profile_info, fp, caller);
  #endif
        sticky_cmdmod_flags = 0;
!       call_def_function(fp, argcount, argvars, funcexe->fe_partial,
                                                                    fc, rettv);
        funcdepth_decrement();
  #ifdef FEAT_PROFILE
--- 2653,2659 ----
            profile_may_start_func(&profile_info, fp, caller);
  #endif
        sticky_cmdmod_flags = 0;
!       call_def_function(fp, argcount, argvars, 0, funcexe->fe_partial,
                                                                    fc, rettv);
        funcdepth_decrement();
  #ifdef FEAT_PROFILE
*** ../vim-9.0.0404/src/testdir/test_user_func.vim      2022-09-06 
21:02:31.232361110 +0100
--- src/testdir/test_user_func.vim      2022-09-07 16:41:18.625201191 +0100
***************
*** 635,640 ****
--- 635,645 ----
    return val == 'c'
  enddef
  
+ def DefIndexXtra(xtra: string, idx: number, val: string): bool
+   call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
+   return val == 'c'
+ enddef
+ 
  def Test_defer_in_funcref()
    assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
    assert_false(filereadable('Xentry0'))
***************
*** 655,660 ****
--- 660,675 ----
    assert_false(filereadable('Xentry0'))
    assert_false(filereadable('Xentry1'))
    assert_false(filereadable('Xentry2'))
+ 
+   assert_equal(2, indexof(['a', 'b', 'c'], function(g:DefIndexXtra, 
['xtra'])))
+   assert_false(filereadable('Xentry0'))
+   assert_false(filereadable('Xentry1'))
+   assert_false(filereadable('Xentry2'))
+ 
+   assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndexXtra, ['xtra'])))
+   assert_false(filereadable('Xentry0'))
+   assert_false(filereadable('Xentry1'))
+   assert_false(filereadable('Xentry2'))
  enddef
  
  
*** ../vim-9.0.0404/src/version.c       2022-09-07 15:20:22.198038854 +0100
--- src/version.c       2022-09-07 16:03:53.472307903 +0100
***************
*** 705,706 ****
--- 705,708 ----
  {   /* Add new patch number below this line */
+ /**/
+     405,
  /**/

-- 
Bypasses are devices that allow some people to dash from point A to
point B very fast while other people dash from point B to point A very
fast.  People living at point C, being a point directly in between, are
often given to wonder what's so great about point A that so many people
from point B are so keen to get there and what's so great about point B
that so many people from point A are so keen to get there.  They often
wish that people would just once and for all work out where the hell
they wanted to be.
                -- Douglas Adams, "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/20220907154928.4D1571C0CE4%40moolenaar.net.

Raspunde prin e-mail lui