diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-09-07 16:48:46 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-09-07 16:48:46 +0100 |
commit | c9c967da09d9faf5ba989c943352274fea365841 (patch) | |
tree | a072dd3a6d159560e012fc16615e4a849a0af8ff | |
parent | 1540d334a04d874c2aa9d26b82dbbcd4bc5a78de (diff) | |
download | vim-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.c | 3 | ||||
-rw-r--r-- | src/proto/vim9execute.pro | 2 | ||||
-rw-r--r-- | src/testdir/test_user_func.vim | 15 | ||||
-rw-r--r-- | src/userfunc.c | 2 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9.h | 2 | ||||
-rw-r--r-- | src/vim9execute.c | 33 |
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; } |