summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-07 16:48:46 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-07 16:48:46 +0100
commitc9c967da09d9faf5ba989c943352274fea365841 (patch)
treea072dd3a6d159560e012fc16615e4a849a0af8ff
parent1540d334a04d874c2aa9d26b82dbbcd4bc5a78de (diff)
downloadvim-git-c9c967da09d9faf5ba989c943352274fea365841.tar.gz
patch 9.0.0405: arguments in a partial not used by a :def functionv9.0.0405
Problem: Arguments in a partial not used by a :def function. Solution: Put the partial arguments on the stack.
-rw-r--r--src/eval.c3
-rw-r--r--src/proto/vim9execute.pro2
-rw-r--r--src/testdir/test_user_func.vim15
-rw-r--r--src/userfunc.c2
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h2
-rw-r--r--src/vim9execute.c33
7 files changed, 44 insertions, 15 deletions
diff --git a/src/eval.c b/src/eval.c
index 5ec5b8ae7..c4d3781a2 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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
diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro
index bb3d414e7..b8360c5e6 100644
--- a/src/proto/vim9execute.pro
+++ b/src/proto/vim9execute.pro
@@ -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);
diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim
index ecf90b61a..0a942646f 100644
--- a/src/testdir/test_user_func.vim
+++ b/src/testdir/test_user_func.vim
@@ -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
diff --git a/src/userfunc.c b/src/userfunc.c
index 76ab6b9d8..19027785b 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -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
diff --git a/src/version.c b/src/version.c
index 36ce07ef9..ff5fd12b7 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 405,
+/**/
404,
/**/
403,
diff --git a/src/vim9.h b/src/vim9.h
index 22a3f3990..9d72b9646 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -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
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 46251545e..30ff7a775 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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;
}