diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2023-09-09 11:37:23 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2023-09-09 11:37:23 +0200 |
commit | 342f4f626ed56921b1ef145ccaa05ba0a4b8ac01 (patch) | |
tree | 5441a7bb6c17a6ea0298f1dfde9f6069527d9ecb /src | |
parent | 23c92d93c1b877edf18881b715ad51ec26386c2e (diff) |
patch 9.0.1888: Vim9: Problem trying to invoke class methodv9.0.1888
Problem: Vim9: Problem trying to invoke class method
Solution: Lookup the class method insider other classes
closes: #13055
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/proto/vim9class.pro | 1 | ||||
-rw-r--r-- | src/testdir/test_vim9_class.vim | 63 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9class.c | 27 | ||||
-rw-r--r-- | src/vim9expr.c | 15 |
5 files changed, 106 insertions, 2 deletions
diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro index 0f8aa7f1fe..8413a81dd3 100644 --- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -7,6 +7,7 @@ void ex_type(exarg_T *eap); int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose); ufunc_T *find_class_func(char_u **arg); int class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx); +int class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx); 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); diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index cf6122d858..be4eb2eb8a 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -4248,8 +4248,6 @@ def Test_private_member_access_outside_class() T() END v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val') - - enddef " Test for changing the member access of an interface in a implementation class @@ -4613,4 +4611,65 @@ def Test_abstract_method() v9.CheckScriptSuccess(lines) enddef +" Test for calling a class method using an object in a def function context and +" script context. +def Test_class_method_call_using_object() + # script context + var lines =<< trim END + vim9script + class A + static def Foo(): list<string> + return ['a', 'b'] + enddef + def Bar() + assert_equal(['a', 'b'], A.Foo()) + assert_equal(['a', 'b'], Foo()) + enddef + endclass + + def T() + assert_equal(['a', 'b'], A.Foo()) + var t_a = A.new() + t_a.Bar() + enddef + + assert_equal(['a', 'b'], A.Foo()) + var a = A.new() + a.Bar() + T() + END + v9.CheckScriptSuccess(lines) + + # script context + lines =<< trim END + vim9script + class A + static def Foo(): string + return 'foo' + enddef + endclass + + var a = A.new() + assert_equal('foo', a.Foo()) + END + v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()') + + # def function context + lines =<< trim END + vim9script + class A + static def Foo(): string + return 'foo' + enddef + endclass + + def T() + var a = A.new() + assert_equal('foo', a.Foo()) + enddef + T() + END + v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()') +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index b8e7879c6e..d3be87cb02 100644 --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1888, +/**/ 1887, /**/ 1886, diff --git a/src/vim9class.c b/src/vim9class.c index 14d29c7dac..90cdb8ec12 100644 --- a/src/vim9class.c +++ b/src/vim9class.c @@ -2091,6 +2091,33 @@ class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx) } /* + * If "name[len]" is a class method in cctx->ctx_ufunc->uf_class return the + * index in class.class_class_functions[]. + * If "cl_ret" is not NULL set it to the class. + * Otherwise return -1. + */ + int +class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx) +{ + if (cctx == NULL || cctx->ctx_ufunc == NULL + || cctx->ctx_ufunc->uf_class == NULL) + return -1; + class_T *cl = cctx->ctx_ufunc->uf_class; + + for (int i = 0; i < cl->class_class_function_count; ++i) + { + ufunc_T *fp = cl->class_class_functions[i]; + if (STRNCMP(name, fp->uf_name, len) == 0 && fp->uf_name[len] == NUL) + { + if (cl_ret != NULL) + *cl_ret = cl; + return i; + } + } + return -1; +} + +/* * Return TRUE if current context "cctx_arg" is inside class "cl". * Return FALSE if not. */ diff --git a/src/vim9expr.c b/src/vim9expr.c index 3817e38c56..883219ef58 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -775,6 +775,8 @@ compile_load( } else if ((idx = class_member_index(*arg, len, &cl, cctx)) >= 0) { + // Referencing a class member without the class name. Infer + // the class from the def function context. res = generate_CLASSMEMBER(cctx, TRUE, cl, idx); } else @@ -1118,6 +1120,9 @@ compile_call( if (lookup_local(namebuf, varlen, NULL, cctx) == FAIL && arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK) { + class_T *cl = NULL; + int mi = 0; + // If we can find the function by name generate the right call. // Skip global functions here, a local funcref takes precedence. ufunc = find_func(name, FALSE); @@ -1136,6 +1141,16 @@ compile_call( goto theend; } } + else if ((mi = class_method_index(name, varlen, &cl, cctx)) >= 0) + { + // Class method invocation without the class name. The + // generate_CALL() function expects the class type at the top of + // the stack. So push the class type to the stack. + push_type_stack(cctx, &t_class); + res = generate_CALL(cctx, cl->class_class_functions[mi], NULL, 0, + type, argcount); + goto theend; + } } // If the name is a variable, load it and use PCALL. |