summaryrefslogtreecommitdiff
path: root/src/vim9execute.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2023-01-28 15:19:40 +0000
committerBram Moolenaar <Bram@vim.org>2023-01-28 15:19:40 +0000
commitd0200c8631582bbb16a9b585e2ca7adccc84ccdd (patch)
tree91de748be127428bb62bbd295c41ad52b4b7336a /src/vim9execute.c
parent192e24d974522852bdca67db6d76ead87f57e677 (diff)
downloadvim-git-d0200c8631582bbb16a9b585e2ca7adccc84ccdd.tar.gz
patch 9.0.1254: calling a method on an interface does not workv9.0.1254
Problem: Calling a method on an interface does not work. Solution: At runtime figure out what method to call. (closes #11901)
Diffstat (limited to 'src/vim9execute.c')
-rw-r--r--src/vim9execute.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 726b2d65f..3498e547e 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2262,7 +2262,8 @@ execute_storeindex(isn_T *iptr, ectx_T *ectx)
class_T *itf = iptr->isn_arg.storeindex.si_class;
if (itf != NULL)
// convert interface member index to class member index
- idx = object_index_from_itf_index(itf, idx, obj->obj_class);
+ idx = object_index_from_itf_index(itf, FALSE,
+ idx, obj->obj_class);
clear_tv(&otv[idx]);
otv[idx] = *tv;
@@ -2950,6 +2951,20 @@ load_namespace_var(ectx_T *ectx, isntype_T isn_type, isn_T *iptr)
return OK;
}
+
+ static void
+object_required_error(typval_T *tv)
+{
+ garray_T type_list;
+ ga_init2(&type_list, sizeof(type_T *), 10);
+ type_T *type = typval2type(tv, get_copyID(), &type_list, TVTT_DO_MEMBER);
+ char *tofree = NULL;
+ char *typename = type_name(type, &tofree);
+ semsg(_(e_object_required_found_str), typename);
+ vim_free(tofree);
+ clear_type_list(&type_list);
+}
+
/*
* Execute instructions in execution context "ectx".
* Return OK or FAIL;
@@ -4125,6 +4140,30 @@ exec_instructions(ectx_T *ectx)
goto on_error;
break;
+ // call a method on an interface
+ case ISN_METHODCALL:
+ {
+ SOURCING_LNUM = iptr->isn_lnum;
+ tv = STACK_TV_BOT(-1);
+ if (tv->v_type != VAR_OBJECT)
+ {
+ object_required_error(tv);
+ goto on_error;
+ }
+ object_T *obj = tv->vval.v_object;
+ class_T *cl = obj->obj_class;
+
+ // convert the interface index to the object index
+ cmfunc_T *mfunc = iptr->isn_arg.mfunc;
+ int idx = object_index_from_itf_index(mfunc->cmf_itf,
+ TRUE, mfunc->cmf_idx, cl);
+
+ if (call_ufunc(cl->class_obj_methods[idx], NULL,
+ mfunc->cmf_argcount, ectx, NULL, NULL) == FAIL)
+ goto on_error;
+ }
+ break;
+
// call a builtin function
case ISN_BCALL:
SOURCING_LNUM = iptr->isn_lnum;
@@ -5213,15 +5252,7 @@ exec_instructions(ectx_T *ectx)
if (tv->v_type != VAR_OBJECT)
{
SOURCING_LNUM = iptr->isn_lnum;
- garray_T type_list;
- ga_init2(&type_list, sizeof(type_T *), 10);
- type_T *type = typval2type(tv, get_copyID(),
- &type_list, TVTT_DO_MEMBER);
- char *tofree = NULL;
- char *typename = type_name(type, &tofree);
- semsg(_(e_object_required_found_str), typename);
- vim_free(tofree);
- clear_type_list(&type_list);
+ object_required_error(tv);
goto on_error;
}
@@ -5234,8 +5265,8 @@ exec_instructions(ectx_T *ectx)
idx = iptr->isn_arg.classmember.cm_idx;
// convert the interface index to the object index
idx = object_index_from_itf_index(
- iptr->isn_arg.classmember.cm_class,
- idx, obj->obj_class);
+ iptr->isn_arg.classmember.cm_class,
+ FALSE, idx, obj->obj_class);
}
// the members are located right after the object struct
@@ -6637,6 +6668,17 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
cdfunc->cdf_argcount);
}
break;
+ case ISN_METHODCALL:
+ {
+ cmfunc_T *mfunc = iptr->isn_arg.mfunc;
+
+ smsg("%s%4d METHODCALL %s.%s(argc %d)", pfx, current,
+ mfunc->cmf_itf->class_name,
+ mfunc->cmf_itf->class_obj_methods[
+ mfunc->cmf_idx]->uf_name,
+ mfunc->cmf_argcount);
+ }
+ break;
case ISN_UCALL:
{
cufunc_T *cufunc = &iptr->isn_arg.ufunc;