diff options
author | Bram Moolenaar <Bram@vim.org> | 2023-01-27 20:14:02 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2023-01-27 20:14:02 +0000 |
commit | 8dbab1d8ceb82a0fb693a1b7fcb57a2dfb4de068 (patch) | |
tree | d4e6d32b34dcfbd00784c297ff1139079eb47f44 /src/vim9execute.c | |
parent | 657aea7fc47fb919ce76fad64ba0ec55a1af80f1 (diff) |
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.c | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c index 22e1e58eb8..726b2d65f6 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: |