Mercurial > vim
diff src/vim9execute.c @ 31843:ffa11e2757e7 v9.0.1254
patch 9.0.1254: calling a method on an interface does not work
Commit: https://github.com/vim/vim/commit/d0200c8631582bbb16a9b585e2ca7adccc84ccdd
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Jan 28 15:19:40 2023 +0000
patch 9.0.1254: calling a method on an interface does not work
Problem: Calling a method on an interface does not work.
Solution: At runtime figure out what method to call. (closes https://github.com/vim/vim/issues/11901)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 28 Jan 2023 16:30:04 +0100 |
parents | 5ce5d78afcc9 |
children | f1a5e67e9a1b |
line wrap: on
line diff
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2262,7 +2262,8 @@ execute_storeindex(isn_T *iptr, ectx_T * 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 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 *inst 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;