summaryrefslogtreecommitdiff
path: root/src/vim9execute.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2023-01-27 20:14:02 +0000
committerBram Moolenaar <Bram@vim.org>2023-01-27 20:14:02 +0000
commit8dbab1d8ceb82a0fb693a1b7fcb57a2dfb4de068 (patch)
treed4e6d32b34dcfbd00784c297ff1139079eb47f44 /src/vim9execute.c
parent657aea7fc47fb919ce76fad64ba0ec55a1af80f1 (diff)
downloadvim-git-8dbab1d8ceb82a0fb693a1b7fcb57a2dfb4de068.tar.gz
patch 9.0.1250: cannot use an object method with :deferv9.0.1250
Problem: Cannot use an object method with :defer. (Ernie Rael) Solution: Find the object method and generate code to call it. (closes #11886)
Diffstat (limited to 'src/vim9execute.c')
-rw-r--r--src/vim9execute.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 22e1e58eb..726b2d65f 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -973,9 +973,10 @@ add_defer_item(int var_idx, int argcount, ectx_T *ectx)
* Returns OK or FAIL.
*/
static int
-defer_command(int var_idx, int argcount, ectx_T *ectx)
+defer_command(int var_idx, int has_obj, int argcount, ectx_T *ectx)
{
- list_T *l = add_defer_item(var_idx, argcount, ectx);
+ int obj_off = has_obj ? 1 : 0;
+ list_T *l = add_defer_item(var_idx, argcount + obj_off, ectx);
int i;
typval_T *func_tv;
@@ -983,23 +984,25 @@ defer_command(int var_idx, int argcount, ectx_T *ectx)
return FAIL;
func_tv = STACK_TV_BOT(-argcount - 1);
- if (func_tv->v_type != VAR_FUNC && func_tv->v_type != VAR_PARTIAL)
+ if (has_obj ? func_tv->v_type != VAR_PARTIAL : func_tv->v_type != VAR_FUNC)
{
semsg(_(e_expected_str_but_got_str),
- "function or partial",
+ has_obj ? "partial" : "function",
vartype_name(func_tv->v_type));
return FAIL;
}
list_set_item(l, 0, func_tv);
+ if (has_obj)
+ list_set_item(l, 1, STACK_TV_BOT(-argcount - 2));
for (i = 0; i < argcount; ++i)
- list_set_item(l, i + 1, STACK_TV_BOT(-argcount + i));
- ectx->ec_stack.ga_len -= argcount + 1;
+ list_set_item(l, i + 1 + obj_off, STACK_TV_BOT(-argcount + i));
+ ectx->ec_stack.ga_len -= argcount + 1 + obj_off;
return OK;
}
/*
- * Add a deferred function "name" with one argument "arg_tv".
+ * Add a deferred call for "name" with arguments "argvars[argcount]".
* Consumes "name", also on failure.
* Only to be called when in_def_function() returns TRUE.
*/
@@ -1056,19 +1059,31 @@ invoke_defer_funcs(ectx_T *ectx)
typval_T argvars[MAX_FUNC_ARGS];
int i;
listitem_T *arg_li = l->lv_first;
- funcexe_T funcexe;
+ typval_T *functv = &l->lv_first->li_tv;
+ int obj_off = functv->v_type == VAR_PARTIAL ? 1 : 0;
+ int argcount = l->lv_len - 1 - obj_off;
- for (i = 0; i < l->lv_len - 1; ++i)
+ if (obj_off == 1)
+ arg_li = arg_li->li_next; // second list item is the object
+ for (i = 0; i < argcount; ++i)
{
arg_li = arg_li->li_next;
argvars[i] = arg_li->li_tv;
}
+ funcexe_T funcexe;
CLEAR_FIELD(funcexe);
funcexe.fe_evaluate = TRUE;
rettv.v_type = VAR_UNKNOWN;
- (void)call_func(l->lv_first->li_tv.vval.v_string, -1,
- &rettv, l->lv_len - 1, argvars, &funcexe);
+ if (functv->v_type == VAR_PARTIAL)
+ {
+ funcexe.fe_partial = functv->vval.v_partial;
+ funcexe.fe_object = l->lv_first->li_next->li_tv.vval.v_object;
+ if (funcexe.fe_object != NULL)
+ ++funcexe.fe_object->obj_refcount;
+ }
+ (void)call_func(functv->vval.v_string, -1,
+ &rettv, argcount, argvars, &funcexe);
clear_tv(&rettv);
}
}
@@ -4170,7 +4185,9 @@ exec_instructions(ectx_T *ectx)
// :defer func(arg)
case ISN_DEFER:
+ case ISN_DEFEROBJ:
if (defer_command(iptr->isn_arg.defer.defer_var_idx,
+ iptr->isn_type == ISN_DEFEROBJ,
iptr->isn_arg.defer.defer_argcount, ectx) == FAIL)
goto on_error;
break;
@@ -6640,7 +6657,9 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
smsg("%s%4d PCALL end", pfx, current);
break;
case ISN_DEFER:
- smsg("%s%4d DEFER %d args", pfx, current,
+ case ISN_DEFEROBJ:
+ smsg("%s%4d %s %d args", pfx, current,
+ iptr->isn_type == ISN_DEFER ? "DEFER" : "DEFEROBJ",
(int)iptr->isn_arg.defer.defer_argcount);
break;
case ISN_RETURN: