mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 9.0.0405: arguments in a partial not used by a :def function
Problem: Arguments in a partial not used by a :def function. Solution: Put the partial arguments on the stack.
This commit is contained in:
@@ -263,9 +263,10 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
|||||||
if (partial->pt_func != NULL
|
if (partial->pt_func != NULL
|
||||||
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED)
|
&& 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.
|
// FIXME: should create a funccal and link it in current_funccal.
|
||||||
if (call_def_function(partial->pt_func, argc, argv,
|
if (call_def_function(partial->pt_func, argc, argv,
|
||||||
partial, NULL, rettv) == FAIL)
|
DEF_USE_PT_ARGV, partial, NULL, rettv) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -15,7 +15,7 @@ typval_T *lookup_debug_var(char_u *name);
|
|||||||
int may_break_in_function(ufunc_T *ufunc);
|
int may_break_in_function(ufunc_T *ufunc);
|
||||||
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
||||||
char_u *exe_substitute_instr(void);
|
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 unwind_def_callstack(ectx_T *ectx);
|
||||||
void may_invoke_defer_funcs(ectx_T *ectx);
|
void may_invoke_defer_funcs(ectx_T *ectx);
|
||||||
void set_context_in_disassemble_cmd(expand_T *xp, char_u *arg);
|
void set_context_in_disassemble_cmd(expand_T *xp, char_u *arg);
|
||||||
|
@@ -635,6 +635,11 @@ def DefIndex(idx: number, val: string): bool
|
|||||||
return val == 'c'
|
return val == 'c'
|
||||||
enddef
|
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()
|
def Test_defer_in_funcref()
|
||||||
assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
|
assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
|
||||||
assert_false(filereadable('Xentry0'))
|
assert_false(filereadable('Xentry0'))
|
||||||
@@ -655,6 +660,16 @@ def Test_defer_in_funcref()
|
|||||||
assert_false(filereadable('Xentry0'))
|
assert_false(filereadable('Xentry0'))
|
||||||
assert_false(filereadable('Xentry1'))
|
assert_false(filereadable('Xentry1'))
|
||||||
assert_false(filereadable('Xentry2'))
|
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
|
enddef
|
||||||
|
|
||||||
|
|
||||||
|
@@ -2653,7 +2653,7 @@ call_user_func(
|
|||||||
profile_may_start_func(&profile_info, fp, caller);
|
profile_may_start_func(&profile_info, fp, caller);
|
||||||
#endif
|
#endif
|
||||||
sticky_cmdmod_flags = 0;
|
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);
|
fc, rettv);
|
||||||
funcdepth_decrement();
|
funcdepth_decrement();
|
||||||
#ifdef FEAT_PROFILE
|
#ifdef FEAT_PROFILE
|
||||||
|
@@ -703,6 +703,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
405,
|
||||||
/**/
|
/**/
|
||||||
404,
|
404,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -759,3 +759,5 @@ typedef enum {
|
|||||||
#define TVTT_DO_MEMBER 1
|
#define TVTT_DO_MEMBER 1
|
||||||
#define TVTT_MORE_SPECIFIC 2 // get most specific type for member
|
#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
|
||||||
|
@@ -5272,16 +5272,21 @@ call_def_function(
|
|||||||
ufunc_T *ufunc,
|
ufunc_T *ufunc,
|
||||||
int argc_arg, // nr of arguments
|
int argc_arg, // nr of arguments
|
||||||
typval_T *argv, // arguments
|
typval_T *argv, // arguments
|
||||||
|
int flags, // DEF_ flags
|
||||||
partial_T *partial, // optional partial for context
|
partial_T *partial, // optional partial for context
|
||||||
funccall_T *funccal,
|
funccall_T *funccal,
|
||||||
typval_T *rettv) // return value
|
typval_T *rettv) // return value
|
||||||
{
|
{
|
||||||
ectx_T ectx; // execution context
|
ectx_T ectx; // execution context
|
||||||
int argc = argc_arg;
|
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;
|
typval_T *tv;
|
||||||
int idx;
|
int idx;
|
||||||
int ret = FAIL;
|
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;
|
sctx_T save_current_sctx = current_sctx;
|
||||||
int did_emsg_before = did_emsg_cumul + did_emsg;
|
int did_emsg_before = did_emsg_cumul + did_emsg;
|
||||||
int save_suppress_errthrow = suppress_errthrow;
|
int save_suppress_errthrow = suppress_errthrow;
|
||||||
@@ -5345,14 +5350,14 @@ call_def_function(
|
|||||||
ectx.ec_did_emsg_before = did_emsg_before;
|
ectx.ec_did_emsg_before = did_emsg_before;
|
||||||
++ex_nesting_level;
|
++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)
|
if (idx > 0 && ufunc->uf_va_name == NULL)
|
||||||
{
|
{
|
||||||
semsg(NGETTEXT(e_one_argument_too_many, e_nr_arguments_too_many,
|
semsg(NGETTEXT(e_one_argument_too_many, e_nr_arguments_too_many,
|
||||||
idx), idx);
|
idx), idx);
|
||||||
goto failed_early;
|
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)
|
if (idx < 0)
|
||||||
{
|
{
|
||||||
semsg(NGETTEXT(e_one_argument_too_few, e_nr_arguments_too_few,
|
semsg(NGETTEXT(e_one_argument_too_few, e_nr_arguments_too_few,
|
||||||
@@ -5360,15 +5365,19 @@ call_def_function(
|
|||||||
goto failed_early;
|
goto failed_early;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put arguments on the stack, but no more than what the function expects.
|
// Put values from the partial and arguments on the stack, but no more than
|
||||||
// A lambda can be called with more arguments than it uses.
|
// what the function expects. A lambda can be called with more arguments
|
||||||
for (idx = 0; idx < argc
|
// than it uses.
|
||||||
|
for (idx = 0; idx < total_argc
|
||||||
&& (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
|
&& (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
|
||||||
++idx)
|
++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
|
if (idx >= ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len
|
||||||
&& argv[idx].v_type == VAR_SPECIAL
|
&& tv->v_type == VAR_SPECIAL
|
||||||
&& argv[idx].vval.v_number == VVAL_NONE)
|
&& tv->vval.v_number == VVAL_NONE)
|
||||||
{
|
{
|
||||||
// Use the default value.
|
// Use the default value.
|
||||||
STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
|
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
|
if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
|
||||||
&& check_typval_arg_type(
|
&& check_typval_arg_type(
|
||||||
ufunc->uf_arg_types[idx], &argv[idx],
|
ufunc->uf_arg_types[idx], tv,
|
||||||
NULL, idx + 1) == FAIL)
|
NULL, argv_idx + 1) == FAIL)
|
||||||
goto failed_early;
|
goto failed_early;
|
||||||
copy_tv(&argv[idx], STACK_TV_BOT(0));
|
copy_tv(tv, STACK_TV_BOT(0));
|
||||||
}
|
}
|
||||||
++ectx.ec_stack.ga_len;
|
++ectx.ec_stack.ga_len;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user