vim-patch:9.0.0390: cannot use a partial with :defer

Problem:    Cannot use a partial with :defer.
Solution:   Add the partial arguments before the other arguments.  Disallow
            using a dictionary.

86d87256c4

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq
2023-04-16 10:51:27 +08:00
parent 0167649ce4
commit 335bef0c21
3 changed files with 47 additions and 7 deletions

View File

@@ -406,7 +406,8 @@ GetArg()->TheFunc()` does not work, it may work in a later version.
Errors are reported but do not cause aborting execution of deferred functions. Errors are reported but do not cause aborting execution of deferred functions.
No range is accepted. No range is accepted. The function can be a partial with extra arguments, but
not with a dictionary. *E1300*
============================================================================== ==============================================================================

View File

@@ -81,6 +81,8 @@ static const char e_no_white_space_allowed_before_str_str[]
= N_("E1068: No white space allowed before '%s': %s"); = N_("E1068: No white space allowed before '%s': %s");
static const char e_missing_heredoc_end_marker_str[] static const char e_missing_heredoc_end_marker_str[]
= N_("E1145: Missing heredoc end marker: %s"); = N_("E1145: Missing heredoc end marker: %s");
static const char e_cannot_use_partial_with_dictionary_for_defer[]
= N_("E1300: Cannot use a partial with dictionary for :defer");
void func_init(void) void func_init(void)
{ {
@@ -3062,7 +3064,7 @@ void ex_return(exarg_T *eap)
} }
static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg, static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg,
funcexe_T *funcexe_init, evalarg_T *const evalarg) const funcexe_T *const funcexe_init, evalarg_T *const evalarg)
{ {
bool doesrange; bool doesrange;
bool failed = false; bool failed = false;
@@ -3116,16 +3118,32 @@ static int ex_call_inner(exarg_T *eap, char *name, char **arg, char *startarg,
/// Core part of ":defer func(arg)". "arg" points to the "(" and is advanced. /// Core part of ":defer func(arg)". "arg" points to the "(" and is advanced.
/// ///
/// @return FAIL or OK. /// @return FAIL or OK.
static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg) static int ex_defer_inner(char *name, char **arg, const partial_T *const partial,
evalarg_T *const evalarg)
{ {
typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
int partial_argc = 0; // number of partial arguments
int argcount = 0; // number of arguments found int argcount = 0; // number of arguments found
if (current_funccal == NULL) { if (current_funccal == NULL) {
semsg(_(e_str_not_inside_function), "defer"); semsg(_(e_str_not_inside_function), "defer");
return FAIL; return FAIL;
} }
if (get_func_arguments(arg, evalarg, false, argvars, &argcount) == FAIL) { if (partial != NULL) {
if (partial->pt_dict != NULL) {
emsg(_(e_cannot_use_partial_with_dictionary_for_defer));
return FAIL;
}
if (partial->pt_argc > 0) {
partial_argc = partial->pt_argc;
for (int i = 0; i < partial_argc; i++) {
tv_copy(&partial->pt_argv[i], &argvars[i]);
}
}
}
int r = get_func_arguments(arg, evalarg, false, argvars + partial_argc, &argcount);
argcount += partial_argc;
if (r == FAIL) {
while (--argcount >= 0) { while (--argcount >= 0) {
tv_clear(&argvars[argcount]); tv_clear(&argvars[argcount]);
} }
@@ -3236,7 +3254,7 @@ void ex_call(exarg_T *eap)
if (eap->cmdidx == CMD_defer) { if (eap->cmdidx == CMD_defer) {
arg = startarg; arg = startarg;
failed = ex_defer_inner(name, &arg, &evalarg) == FAIL; failed = ex_defer_inner(name, &arg, partial, &evalarg) == FAIL;
} else { } else {
funcexe_T funcexe = FUNCEXE_INIT; funcexe_T funcexe = FUNCEXE_INIT;
funcexe.fe_partial = partial; funcexe.fe_partial = partial;

View File

@@ -532,8 +532,11 @@ func Test_funcdef_alloc_failure()
bw! bw!
endfunc endfunc
func AddDefer(arg) func AddDefer(arg1, ...)
call extend(g:deferred, [a:arg]) call extend(g:deferred, [a:arg1])
if a:0 == 1
call extend(g:deferred, [a:1])
endif
endfunc endfunc
func WithDeferTwo() func WithDeferTwo()
@@ -553,6 +556,13 @@ func WithDeferOne()
call extend(g:deferred, ['end One']) call extend(g:deferred, ['end One'])
endfunc endfunc
func WithPartialDefer()
call extend(g:deferred, ['in Partial'])
let Part = funcref('AddDefer', ['arg1'])
defer Part("arg2")
call extend(g:deferred, ['end Partial'])
endfunc
func Test_defer() func Test_defer()
let g:deferred = [] let g:deferred = []
call WithDeferOne() call WithDeferOne()
@@ -561,6 +571,17 @@ func Test_defer()
unlet g:deferred unlet g:deferred
call assert_equal('', glob('Xfuncdefer')) call assert_equal('', glob('Xfuncdefer'))
call assert_fails('defer delete("Xfuncdefer")->Another()', 'E488:')
call assert_fails('defer delete("Xfuncdefer").member', 'E488:')
let g:deferred = []
call WithPartialDefer()
call assert_equal(['in Partial', 'end Partial', 'arg1', 'arg2'], g:deferred)
unlet g:deferred
let Part = funcref('AddDefer', ['arg1'], {})
call assert_fails('defer Part("arg2")', 'E1300:')
endfunc endfunc