Mercurial > vim
changeset 33540:86dbcbb94fdb v9.0.2019
patch 9.0.2019: Vim9: no support for funcrefs
Commit: https://github.com/vim/vim/commit/29bb67f1beefc7fd393dbfd9ee77d92f1db3a3c0
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sat Oct 14 11:18:50 2023 +0200
patch 9.0.2019: Vim9: no support for funcrefs
Problem: Vim9: no support for funcrefs
Solution: Add support for object/class funcref members
closes: #11981 #12417 #12960 #12324 #13333
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 14 Oct 2023 11:30:07 +0200 |
parents | 98e6eaaf8458 |
children | 281c18121b19 |
files | src/eval.c src/evalfunc.c src/proto/vim9class.pro src/proto/vim9instr.pro src/structs.h src/testdir/test_vim9_class.vim src/testdir/test_vim9_func.vim src/version.c src/vim9.h src/vim9class.c src/vim9compile.c src/vim9execute.c src/vim9expr.c src/vim9instr.c src/vim9type.c |
diffstat | 15 files changed, 731 insertions(+), 51 deletions(-) [+] |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -5256,6 +5256,7 @@ partial_free(partial_T *pt) } else func_ptr_unref(pt->pt_func); + object_unref(pt->pt_obj); // "out_up" is no longer used, decrement refcount on partial that owns it. partial_unref(pt->pt_outer.out_up_partial); @@ -5578,6 +5579,7 @@ free_unref_items(int copyID) /* * PASS 2: free the items themselves. */ + object_free_items(copyID); dict_free_items(copyID); list_free_items(copyID); @@ -5818,6 +5820,15 @@ set_ref_in_item_partial( set_ref_in_item(&dtv, copyID, ht_stack, list_stack); } + if (pt->pt_obj != NULL) + { + typval_T objtv; + + objtv.v_type = VAR_OBJECT; + objtv.vval.v_object = pt->pt_obj; + set_ref_in_item(&objtv, copyID, ht_stack, list_stack); + } + for (int i = 0; i < pt->pt_argc; ++i) abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, ht_stack, list_stack);
--- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -4801,6 +4801,9 @@ common_function(typval_T *argvars, typva pt->pt_auto = arg_pt->pt_auto; if (pt->pt_dict != NULL) ++pt->pt_dict->dv_refcount; + pt->pt_obj = arg_pt->pt_obj; + if (pt->pt_obj != NULL) + ++pt->pt_obj->obj_refcount; } pt->pt_refcount = 1;
--- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -17,13 +17,14 @@ void emsg_var_cl_define(char *msg, char_ ufunc_T *method_lookup(class_T *cl, vartype_T v_type, char_u *name, size_t namelen, int *idx); int inside_class(cctx_T *cctx_arg, class_T *cl); void copy_object(typval_T *from, typval_T *to); -void object_unref(object_T *obj); void copy_class(typval_T *from, typval_T *to); void class_unref(class_T *cl); int class_free_nonref(int copyID); int set_ref_in_classes(int copyID); void object_created(object_T *obj); +void object_unref(object_T *obj); int object_free_nonref(int copyID); +void object_free_items(int copyID); void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len); void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len); void f_instanceof(typval_T *argvars, typval_T *rettv);
--- a/src/proto/vim9instr.pro +++ b/src/proto/vim9instr.pro @@ -45,7 +45,7 @@ int generate_OLDSCRIPT(cctx_T *cctx, isn int generate_VIM9SCRIPT(cctx_T *cctx, isntype_T isn_type, int sid, int idx, type_T *type); int generate_NEWLIST(cctx_T *cctx, int count, int use_null); int generate_NEWDICT(cctx_T *cctx, int count, int use_null); -int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, class_T *cl, int fi, int *isn_idx); +int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, class_T *cl, int object_method, int fi, int *isn_idx); int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name); int generate_DEF(cctx_T *cctx, char_u *name, size_t len); int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where);
--- a/src/structs.h +++ b/src/structs.h @@ -2316,6 +2316,7 @@ struct partial_S int pt_copyID; // funcstack may contain pointer to partial dict_T *pt_dict; // dict for "self" + object_T *pt_obj; // object method }; typedef struct {
--- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -7477,4 +7477,480 @@ def Test_op_and_assignment() v9.CheckSourceSuccess(lines) enddef +" Test for using an object method as a funcref +def Test_object_funcref() + # Using object method funcref from a def function + var lines =<< trim END + vim9script + class A + def Foo(): list<number> + return [3, 2, 1] + enddef + endclass + def Bar() + var a = A.new() + var Fn = a.Foo + assert_equal([3, 2, 1], Fn()) + enddef + Bar() + END + v9.CheckSourceSuccess(lines) + + # Using object method funcref at the script level + lines =<< trim END + vim9script + class A + def Foo(): dict<number> + return {a: 1, b: 2} + enddef + endclass + var a = A.new() + var Fn = a.Foo + assert_equal({a: 1, b: 2}, Fn()) + END + v9.CheckSourceSuccess(lines) + + # Using object method funcref from another object method + lines =<< trim END + vim9script + class A + def Foo(): list<number> + return [3, 2, 1] + enddef + def Bar() + var Fn = this.Foo + assert_equal([3, 2, 1], Fn()) + enddef + endclass + var a = A.new() + a.Bar() + END + v9.CheckSourceSuccess(lines) + + # Using function() to get a object method funcref + lines =<< trim END + vim9script + class A + def Foo(l: list<any>): list<any> + return l + enddef + endclass + var a = A.new() + var Fn = function(a.Foo, [[{a: 1, b: 2}, [3, 4]]]) + assert_equal([{a: 1, b: 2}, [3, 4]], Fn()) + END + v9.CheckSourceSuccess(lines) + + # Use an object method with a function returning a funcref and then call the + # funcref. + lines =<< trim END + vim9script + + def Map(F: func(number): number): func(number): number + return (n: number) => F(n) + enddef + + class Math + def Double(n: number): number + return 2 * n + enddef + endclass + + const math = Math.new() + assert_equal(48, Map(math.Double)(24)) + END + v9.CheckSourceSuccess(lines) + + # Try using a private object method funcref from a def function + lines =<< trim END + vim9script + class A + def _Foo() + enddef + endclass + def Bar() + var a = A.new() + var Fn = a._Foo + enddef + Bar() + END + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 2) + + # Try using a private object method funcref at the script level + lines =<< trim END + vim9script + class A + def _Foo() + enddef + endclass + var a = A.new() + var Fn = a._Foo + END + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 7) + + # Using a private object method funcref from another object method + lines =<< trim END + vim9script + class A + def _Foo(): list<number> + return [3, 2, 1] + enddef + def Bar() + var Fn = this._Foo + assert_equal([3, 2, 1], Fn()) + enddef + endclass + var a = A.new() + a.Bar() + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for using a class method as a funcref +def Test_class_funcref() + # Using class method funcref in a def function + var lines =<< trim END + vim9script + class A + static def Foo(): list<number> + return [3, 2, 1] + enddef + endclass + def Bar() + var Fn = A.Foo + assert_equal([3, 2, 1], Fn()) + enddef + Bar() + END + v9.CheckSourceSuccess(lines) + + # Using class method funcref at script level + lines =<< trim END + vim9script + class A + static def Foo(): dict<number> + return {a: 1, b: 2} + enddef + endclass + var Fn = A.Foo + assert_equal({a: 1, b: 2}, Fn()) + END + v9.CheckSourceSuccess(lines) + + # Using function() to get a class method funcref + lines =<< trim END + vim9script + class A + static def Foo(l: list<any>): list<any> + return l + enddef + endclass + var Fn = function(A.Foo, [[{a: 1, b: 2}, [3, 4]]]) + assert_equal([{a: 1, b: 2}, [3, 4]], Fn()) + END + v9.CheckSourceSuccess(lines) + + # Using a class method funcref from another class method + lines =<< trim END + vim9script + class A + static def Foo(): list<number> + return [3, 2, 1] + enddef + static def Bar() + var Fn = Foo + assert_equal([3, 2, 1], Fn()) + enddef + endclass + A.Bar() + END + v9.CheckSourceSuccess(lines) + + # Use a class method with a function returning a funcref and then call the + # funcref. + lines =<< trim END + vim9script + + def Map(F: func(number): number): func(number): number + return (n: number) => F(n) + enddef + + class Math + static def StaticDouble(n: number): number + return 2 * n + enddef + endclass + + assert_equal(48, Map(Math.StaticDouble)(24)) + END + v9.CheckSourceSuccess(lines) + + # Try using a private class method funcref in a def function + lines =<< trim END + vim9script + class A + static def _Foo() + enddef + endclass + def Bar() + var Fn = A._Foo + enddef + Bar() + END + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 1) + + # Try using a private class method funcref at script level + lines =<< trim END + vim9script + class A + static def _Foo() + enddef + endclass + var Fn = A._Foo + END + v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo', 6) + + # Using a private class method funcref from another class method + lines =<< trim END + vim9script + class A + static def _Foo(): list<number> + return [3, 2, 1] + enddef + static def Bar() + var Fn = _Foo + assert_equal([3, 2, 1], Fn()) + enddef + endclass + A.Bar() + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for using an object member as a funcref +def Test_object_member_funcref() + # Using a funcref object variable in an object method + var lines =<< trim END + vim9script + def Foo(n: number): number + return n * 10 + enddef + + class A + this.Cb: func(number): number = Foo + def Bar() + assert_equal(200, this.Cb(20)) + enddef + endclass + + var a = A.new() + a.Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref object variable in a def method + lines =<< trim END + vim9script + def Foo(n: number): number + return n * 10 + enddef + + class A + this.Cb: func(number): number = Foo + endclass + + def Bar() + var a = A.new() + assert_equal(200, a.Cb(20)) + enddef + Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref object variable at script level + lines =<< trim END + vim9script + def Foo(n: number): number + return n * 10 + enddef + + class A + this.Cb: func(number): number = Foo + endclass + + var a = A.new() + assert_equal(200, a.Cb(20)) + END + v9.CheckSourceSuccess(lines) + + # Using a funcref object variable pointing to an object method in an object + # method. + lines =<< trim END + vim9script + class A + this.Cb: func(number): number = this.Foo + def Foo(n: number): number + return n * 10 + enddef + def Bar() + assert_equal(200, this.Cb(20)) + enddef + endclass + + var a = A.new() + a.Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref object variable pointing to an object method in a def + # method. + lines =<< trim END + vim9script + class A + this.Cb: func(number): number = this.Foo + def Foo(n: number): number + return n * 10 + enddef + endclass + + def Bar() + var a = A.new() + assert_equal(200, a.Cb(20)) + enddef + Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref object variable pointing to an object method at script + # level. + lines =<< trim END + vim9script + class A + this.Cb = this.Foo + def Foo(n: number): number + return n * 10 + enddef + endclass + + var a = A.new() + assert_equal(200, a.Cb(20)) + END + v9.CheckSourceSuccess(lines) +enddef + +" Test for using a class member as a funcref +def Test_class_member_funcref() + # Using a funcref class variable in a class method + var lines =<< trim END + vim9script + def Foo(n: number): number + return n * 10 + enddef + + class A + static Cb = Foo + static def Bar() + assert_equal(200, Cb(20)) + enddef + endclass + + A.Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref class variable in a def method + lines =<< trim END + vim9script + def Foo(n: number): number + return n * 10 + enddef + + class A + public static Cb = Foo + endclass + + def Bar() + assert_equal(200, A.Cb(20)) + enddef + Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref class variable at script level + lines =<< trim END + vim9script + def Foo(n: number): number + return n * 10 + enddef + + class A + public static Cb = Foo + endclass + + assert_equal(200, A.Cb(20)) + END + v9.CheckSourceSuccess(lines) + + # Using a funcref class variable pointing to a class method in a class + # method. + lines =<< trim END + vim9script + class A + static Cb: func(number): number + static def Foo(n: number): number + return n * 10 + enddef + static def Init() + Cb = Foo + enddef + static def Bar() + assert_equal(200, Cb(20)) + enddef + endclass + + A.Init() + A.Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref class variable pointing to a class method in a def method. + lines =<< trim END + vim9script + class A + static Cb: func(number): number + static def Foo(n: number): number + return n * 10 + enddef + static def Init() + Cb = Foo + enddef + endclass + + def Bar() + A.Init() + assert_equal(200, A.Cb(20)) + enddef + Bar() + END + v9.CheckSourceSuccess(lines) + + # Using a funcref class variable pointing to a class method at script level. + lines =<< trim END + vim9script + class A + static Cb: func(number): number + static def Foo(n: number): number + return n * 10 + enddef + static def Init() + Cb = Foo + enddef + endclass + + A.Init() + assert_equal(200, A.Cb(20)) + END + v9.CheckSourceSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index 852f3a7edec49b7277bb5141ef7481cfcbeb7875..597a10c581882c180a1f96a5ae1000680c2edeb0 GIT binary patch literal 106605 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 N>HOI|%r4<L`#&Q~csc+8
--- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2019, +/**/ 2018, /**/ 2017,
--- a/src/vim9.h +++ b/src/vim9.h @@ -383,6 +383,7 @@ typedef struct { char_u *fre_func_name; // function name for legacy function loopvarinfo_T fre_loopvar_info; // info about variables inside loops class_T *fre_class; // class for a method + int fre_object_method; // class or object method int fre_method_idx; // method index on "fre_class" } funcref_extra_T;
--- a/src/vim9class.c +++ b/src/vim9class.c @@ -2167,15 +2167,35 @@ call_oc_method( ufunc_T *fp; typval_T argvars[MAX_FUNC_ARGS + 1]; int argcount = 0; + ocmember_T *ocm = NULL; + int m_idx; fp = method_lookup(cl, rettv->v_type, name, len, NULL); if (fp == NULL) { - method_not_found_msg(cl, rettv->v_type, name, len); - return FAIL; + // could be an object or class funcref variable + ocm = member_lookup(cl, rettv->v_type, name, len, &m_idx); + if (ocm == NULL || ocm->ocm_type->tt_type != VAR_FUNC) + { + method_not_found_msg(cl, rettv->v_type, name, len); + return FAIL; + } + + if (rettv->v_type == VAR_OBJECT) + { + // funcref object variable + object_T *obj = rettv->vval.v_object; + typval_T *tv = (typval_T *)(obj + 1) + m_idx; + copy_tv(tv, rettv); + } + else + // funcref class variable + copy_tv(&cl->class_members_tv[m_idx], rettv); + *arg = name_end; + return OK; } - if (*fp->uf_name == '_') + if (ocm == NULL && *fp->uf_name == '_') { // Cannot access a private method outside of a class semsg(_(e_cannot_access_private_method_str), fp->uf_name); @@ -2288,6 +2308,37 @@ class_object_index( return OK; } + // could be a class method or an object method + int fidx; + ufunc_T *fp = method_lookup(cl, rettv->v_type, name, len, &fidx); + if (fp != NULL) + { + // Private methods are not accessible outside the class + if (*name == '_') + { + semsg(_(e_cannot_access_private_method_str), fp->uf_name); + return FAIL; + } + + partial_T *pt = ALLOC_CLEAR_ONE(partial_T); + if (pt == NULL) + return FAIL; + + pt->pt_refcount = 1; + if (is_object) + { + pt->pt_obj = rettv->vval.v_object; + ++pt->pt_obj->obj_refcount; + } + pt->pt_auto = TRUE; + pt->pt_func = fp; + func_ptr_ref(pt->pt_func); + rettv->v_type = VAR_PARTIAL; + rettv->vval.v_partial = pt; + *arg = name_end; + return OK; + } + if (did_emsg == did_emsg_save) member_not_found_msg(cl, is_object, name, len); } @@ -2774,8 +2825,6 @@ object_created(object_T *obj) first_object = obj; } -static object_T *next_nonref_obj = NULL; - /* * Call this function when an object has been cleared and is about to be freed. * It is removed from the list headed by "first_object". @@ -2789,30 +2838,35 @@ object_cleared(object_T *obj) obj->obj_prev_used->obj_next_used = obj->obj_next_used; else if (first_object == obj) first_object = obj->obj_next_used; - - // update the next object to check if needed - if (obj == next_nonref_obj) - next_nonref_obj = obj->obj_next_used; } /* - * Free an object. + * Free the contents of an object ignoring the reference count. */ static void -object_clear(object_T *obj) +object_free_contents(object_T *obj) { - // Avoid a recursive call, it can happen if "obj" has a circular reference. - obj->obj_refcount = INT_MAX; - class_T *cl = obj->obj_class; if (!cl) return; + // Avoid a recursive call, it can happen if "obj" has a circular reference. + obj->obj_refcount = INT_MAX; + // the member values are just after the object structure typval_T *tv = (typval_T *)(obj + 1); for (int i = 0; i < cl->class_obj_member_count; ++i) clear_tv(tv + i); +} + + static void +object_free_object(object_T *obj) +{ + class_T *cl = obj->obj_class; + + if (!cl) + return; // Remove from the list headed by "first_object". object_cleared(obj); @@ -2821,6 +2875,16 @@ object_clear(object_T *obj) class_unref(cl); } + static void +object_free(object_T *obj) +{ + if (in_free_unref_items) + return; + + object_free_contents(obj); + object_free_object(obj); +} + /* * Unreference an object. */ @@ -2828,7 +2892,7 @@ object_clear(object_T *obj) object_unref(object_T *obj) { if (obj != NULL && --obj->obj_refcount <= 0) - object_clear(obj); + object_free(obj); } /* @@ -2839,21 +2903,32 @@ object_free_nonref(int copyID) { int did_free = FALSE; - for (object_T *obj = first_object; obj != NULL; obj = next_nonref_obj) + for (object_T *obj = first_object; obj != NULL; obj = obj->obj_next_used) { - next_nonref_obj = obj->obj_next_used; if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) { - // Free the object and items it contains. - object_clear(obj); + // Free the object contents. Object itself will be freed later. + object_free_contents(obj); did_free = TRUE; } } - next_nonref_obj = NULL; return did_free; } + void +object_free_items(int copyID) +{ + object_T *obj_next; + + for (object_T *obj = first_object; obj != NULL; obj = obj_next) + { + obj_next = obj->obj_next_used; + if ((obj->obj_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) + object_free_object(obj); + } +} + /* * Output message which takes a variable name and the class that defines it. * "cl" is that class where the name was found. Search "cl"'s hierarchy to
--- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1148,7 +1148,7 @@ compile_nested_function(exarg_T *eap, cc ASSIGN_CONST, ufunc->uf_func_type); if (lvar == NULL) goto theend; - if (generate_FUNCREF(cctx, ufunc, NULL, 0, &funcref_isn_idx) == FAIL) + if (generate_FUNCREF(cctx, ufunc, NULL, FALSE, 0, &funcref_isn_idx) == FAIL) goto theend; r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); }
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -616,6 +616,12 @@ call_dfunc( // the first local variable. if (IS_OBJECT_METHOD(ufunc)) { + if (obj->v_type != VAR_OBJECT) + { + semsg(_(e_internal_error_str), "type in stack is not an object"); + return FAIL; + } + *STACK_TV_VAR(0) = *obj; obj->v_type = VAR_UNKNOWN; } @@ -1497,6 +1503,23 @@ call_partial( partial_T *pt = tv->vval.v_partial; int i; + if (pt->pt_obj != NULL) + { + // partial with an object method. Push the object before the + // function arguments. + if (GA_GROW_FAILS(&ectx->ec_stack, 1)) + return FAIL; + for (i = 1; i <= argcount; ++i) + *STACK_TV_BOT(-i + 1) = *STACK_TV_BOT(-i); + + typval_T *obj_tv = STACK_TV_BOT(-argcount); + obj_tv->v_type = VAR_OBJECT; + obj_tv->v_lock = 0; + obj_tv->vval.v_object = pt->pt_obj; + ++pt->pt_obj->obj_refcount; + ++ectx->ec_stack.ga_len; + } + if (pt->pt_argc > 0) { // Make space for arguments from the partial, shift the "argcount" @@ -4447,20 +4470,44 @@ exec_instructions(ectx_T *ectx) } if (extra != NULL && extra->fre_class != NULL) { - tv = STACK_TV_BOT(-1); - if (tv->v_type != VAR_OBJECT) + class_T *cl; + if (extra->fre_object_method) { - object_required_error(tv); - vim_free(pt); - goto on_error; + tv = STACK_TV_BOT(-1); + if (tv->v_type != VAR_OBJECT) + { + object_required_error(tv); + vim_free(pt); + goto on_error; + } + + object_T *obj = tv->vval.v_object; + cl = obj->obj_class; + // drop the value from the stack + clear_tv(tv); + --ectx->ec_stack.ga_len; + + pt->pt_obj = obj; + ++obj->obj_refcount; } - object_T *obj = tv->vval.v_object; - class_T *cl = obj->obj_class; - - // convert the interface index to the object index - int idx = object_index_from_itf_index(extra->fre_class, - TRUE, extra->fre_method_idx, cl); - ufunc = cl->class_obj_methods[idx]; + else + cl = extra->fre_class; + + if (extra->fre_object_method) + { + // object method + // convert the interface index to the object index + int idx = + object_index_from_itf_index(extra->fre_class, + TRUE, extra->fre_method_idx, cl); + ufunc = cl->class_obj_methods[idx]; + } + else + { + // class method + ufunc = + cl->class_class_functions[extra->fre_method_idx]; + } } else if (extra == NULL || extra->fre_func_name == NULL) {
--- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -281,6 +281,8 @@ inside_class_hierarchy(cctx_T *cctx_arg, static int compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) { + int m_idx; + if (VIM_ISWHITE((*arg)[1])) { semsg(_(e_no_white_space_allowed_after_str_str), ".", *arg); @@ -365,17 +367,34 @@ compile_class_object_index(cctx_T *cctx, break; } } + ocmember_T *ocm = NULL; if (ufunc == NULL) { - method_not_found_msg(cl, type->tt_type, name, len); - return FAIL; + // could be a funcref in a member variable + ocm = member_lookup(cl, type->tt_type, name, len, &m_idx); + if (ocm == NULL || ocm->ocm_type->tt_type != VAR_FUNC) + { + method_not_found_msg(cl, type->tt_type, name, len); + return FAIL; + } + if (type->tt_type == VAR_CLASS) + { + if (generate_CLASSMEMBER(cctx, TRUE, cl, m_idx) == FAIL) + return FAIL; + } + else + { + if (generate_GET_OBJ_MEMBER(cctx, m_idx, ocm->ocm_type) == + FAIL) + return FAIL; + } } // A private object method can be used only inside the class where it // is defined or in one of the child classes. // A private class method can be used only in the class where it is // defined. - if (*ufunc->uf_name == '_' && + if (ocm == NULL && *ufunc->uf_name == '_' && ((type->tt_type == VAR_OBJECT && !inside_class_hierarchy(cctx, cl)) || (type->tt_type == VAR_CLASS @@ -393,6 +412,8 @@ compile_class_object_index(cctx_T *cctx, if (compile_arguments(arg, cctx, &argcount, CA_NOT_SPECIAL) == FAIL) return FAIL; + if (ocm != NULL) + return generate_PCALL(cctx, argcount, name, ocm->ocm_type, TRUE); if (type->tt_type == VAR_OBJECT && (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))) return generate_CALL(cctx, ufunc, cl, fi, argcount); @@ -401,7 +422,6 @@ compile_class_object_index(cctx_T *cctx, if (type->tt_type == VAR_OBJECT) { - int m_idx; ocmember_T *m = object_member_lookup(cl, name, len, &m_idx); if (m_idx >= 0) { @@ -418,15 +438,21 @@ compile_class_object_index(cctx_T *cctx, return generate_GET_OBJ_MEMBER(cctx, m_idx, m->ocm_type); } - // Could be a function reference: "obj.Func". + // Could be an object method reference: "obj.Func". m_idx = object_method_idx(cl, name, len); if (m_idx >= 0) { ufunc_T *fp = cl->class_obj_methods[m_idx]; - if (type->tt_type == VAR_OBJECT - && (cl->class_flags & (CLASS_INTERFACE | CLASS_EXTENDED))) - return generate_FUNCREF(cctx, fp, cl, m_idx, NULL); - return generate_FUNCREF(cctx, fp, NULL, 0, NULL); + // Private methods are not accessible outside the class + if (*name == '_' && !inside_class(cctx, cl)) + { + semsg(_(e_cannot_access_private_method_str), fp->uf_name); + return FAIL; + } + *arg = name_end; + if (type->tt_type == VAR_OBJECT) + return generate_FUNCREF(cctx, fp, cl, TRUE, m_idx, NULL); + return generate_FUNCREF(cctx, fp, NULL, FALSE, 0, NULL); } member_not_found_msg(cl, VAR_OBJECT, name, len); @@ -451,6 +477,24 @@ compile_class_object_index(cctx_T *cctx, *arg = name_end; return generate_CLASSMEMBER(cctx, TRUE, cl, idx); } + + // Could be a class method reference: "class.Func". + m_idx = class_method_idx(cl, name, len); + if (m_idx >= 0) + { + ufunc_T *fp = cl->class_class_functions[m_idx]; + // Private methods are not accessible outside the class + if (*name == '_' && !inside_class(cctx, cl)) + { + semsg(_(e_cannot_access_private_method_str), fp->uf_name); + return FAIL; + } + *arg = name_end; + if (type->tt_type == VAR_CLASS) + return generate_FUNCREF(cctx, fp, cl, FALSE, m_idx, NULL); + return generate_FUNCREF(cctx, fp, NULL, FALSE, 0, NULL); + } + member_not_found_msg(cl, VAR_CLASS, name, len); } @@ -716,6 +760,7 @@ compile_load( { size_t len = end - *arg; int idx; + int method_idx; int gen_load = FALSE; int gen_load_outer = 0; int outer_loop_depth = -1; @@ -764,13 +809,27 @@ compile_load( else gen_load = TRUE; } - else if ((idx = cctx_class_member_idx(cctx, *arg, len, &cl)) >= 0) + else if (cctx->ctx_ufunc->uf_defclass != NULL && + (((idx = + cctx_class_member_idx(cctx, *arg, len, &cl)) >= 0) + || ((method_idx = + cctx_class_method_idx(cctx, *arg, len, &cl)) >= 0))) { - // Referencing a class variable without the class name. - // A class variable can be referenced without the class name - // only in the class where the function is defined. + // Referencing a class variable or method without the class + // name. A class variable or method can be referenced without + // the class name only in the class where the function is + // defined. if (cctx->ctx_ufunc->uf_defclass == cl) - res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); + { + if (idx >= 0) + res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); + else + { + ufunc_T *fp = cl->class_class_functions[method_idx]; + res = generate_FUNCREF(cctx, fp, cl, FALSE, method_idx, + NULL); + } + } else { semsg(_(e_class_variable_str_accessible_only_inside_class_str), @@ -1387,7 +1446,7 @@ compile_lambda(char_u **arg, cctx_T *cct // The function reference count will be 1. When the ISN_FUNCREF // instruction is deleted the reference count is decremented and the // function is freed. - return generate_FUNCREF(cctx, ufunc, NULL, 0, NULL); + return generate_FUNCREF(cctx, ufunc, NULL, FALSE, 0, NULL); } func_ptr_unref(ufunc);
--- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -1384,6 +1384,7 @@ generate_FUNCREF( cctx_T *cctx, ufunc_T *ufunc, class_T *cl, + int object_method, int fi, int *isn_idx) { @@ -1412,6 +1413,7 @@ generate_FUNCREF( { extra->fre_class = cl; ++cl->class_refcount; + extra->fre_object_method = object_method; extra->fre_method_idx = fi; } }
--- a/src/vim9type.c +++ b/src/vim9type.c @@ -144,7 +144,7 @@ alloc_type(type_T *type) if (ret->tt_member != NULL) ret->tt_member = alloc_type(ret->tt_member); - if (type->tt_args != NULL) + if (type->tt_argcount > 0 && type->tt_args != NULL) { int i; @@ -153,6 +153,8 @@ alloc_type(type_T *type) for (i = 0; i < type->tt_argcount; ++i) ret->tt_args[i] = alloc_type(type->tt_args[i]); } + else + ret->tt_args = NULL; return ret; }