]> granicus.if.org Git - vim/commitdiff
patch 9.0.0405: arguments in a partial not used by a :def function v9.0.0405
authorBram Moolenaar <Bram@vim.org>
Wed, 7 Sep 2022 15:48:46 +0000 (16:48 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 7 Sep 2022 15:48:46 +0000 (16:48 +0100)
Problem:    Arguments in a partial not used by a :def function.
Solution:   Put the partial arguments on the stack.

src/eval.c
src/proto/vim9execute.pro
src/testdir/test_user_func.vim
src/userfunc.c
src/version.c
src/vim9.h
src/vim9execute.c

index 5ec5b8ae7b7336301db88452d1492de24a72ed10..c4d3781a2d3e5f4eda14acb86ffdf67da3703f9d 100644 (file)
@@ -263,9 +263,10 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
        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,
-                                                partial, NULL, rettv) == FAIL)
+                               DEF_USE_PT_ARGV, partial, NULL, rettv) == FAIL)
                return FAIL;
        }
        else
index bb3d414e7ae95861584cf5d99c7020c86c746f55..b8360c5e654e81ed7d5023ed8925aedaa05ba62f 100644 (file)
@@ -15,7 +15,7 @@ typval_T *lookup_debug_var(char_u *name);
 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);
+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);
index ecf90b61ab2feb9c0bcb38c9ef1a0f45ef4b9ecb..0a942646f8b78be90a7de778e246fd4bd951f4ae 100644 (file)
@@ -635,6 +635,11 @@ def DefIndex(idx: number, val: string): bool
   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,6 +660,16 @@ def Test_defer_in_funcref()
   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
 
 
index 76ab6b9d8687aeb198f0b9278c65dbdd83e920d3..19027785bdd2eafd74f10509477dc54e9fe5d634 100644 (file)
@@ -2653,7 +2653,7 @@ call_user_func(
            profile_may_start_func(&profile_info, fp, caller);
 #endif
        sticky_cmdmod_flags = 0;
-       call_def_function(fp, argcount, argvars, funcexe->fe_partial,
+       call_def_function(fp, argcount, argvars, 0, funcexe->fe_partial,
                                                                    fc, rettv);
        funcdepth_decrement();
 #ifdef FEAT_PROFILE
index 36ce07ef9cc86d7c1ebbeec45929d470755bf411..ff5fd12b7bcb9f5f4abde8ddef5556dfa1e250b9 100644 (file)
@@ -703,6 +703,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    405,
 /**/
     404,
 /**/
index 22a3f3990e6f56aefe81c73bd23dd09dd7ee086b..9d72b964645cdbcb54809447b1bc3b7f1f355432 100644 (file)
@@ -759,3 +759,5 @@ typedef enum {
 #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
index 46251545ed9497ae297d1ef9125ebcc05e44c4e0..30ff7a7755bc77c9d959b4e4948612b53041ff0d 100644 (file)
@@ -5272,16 +5272,21 @@ call_def_function(
     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 - argc;
+    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,14 +5350,14 @@ call_def_function(
     ectx.ec_did_emsg_before = did_emsg_before;
     ++ex_nesting_level;
 
-    idx = argc - ufunc->uf_args.ga_len;
+    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);
+                                                                   idx), idx);
        goto failed_early;
     }
-    idx = argc - ufunc->uf_args.ga_len + ufunc->uf_def_args.ga_len;
+    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,15 +5365,19 @@ call_def_function(
        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
+    // 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
-               && argv[idx].v_type == VAR_SPECIAL
-               && argv[idx].vval.v_number == VVAL_NONE)
+               && tv->v_type == VAR_SPECIAL
+               && tv->vval.v_number == VVAL_NONE)
        {
            // Use the default value.
            STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
@@ -5377,10 +5386,10 @@ call_def_function(
        {
            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)
+                       ufunc->uf_arg_types[idx], tv,
+                                                  NULL, argv_idx + 1) == FAIL)
                goto failed_early;
-           copy_tv(&argv[idx], STACK_TV_BOT(0));
+           copy_tv(tv, STACK_TV_BOT(0));
        }
        ++ectx.ec_stack.ga_len;
     }