diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2023-09-08 19:12:03 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2023-09-08 19:12:03 +0200 |
commit | cc0bcf4c9f4133750f5ee99c685ba995a1b840fd (patch) | |
tree | 838c9185d9184bcb249b10275883e7a89f8fc639 | |
parent | 11d2aeeca4cf191b3f25b36603dcd32167eac8a0 (diff) |
patch 9.0.1883: Vim9: Calling an interface method using a child object failsv9.0.1883
Problem: Vim9: Calling an interface method using a child object fails
Solution: Search methods of parent class
When a class implementing an interface is extended by another class and
a child class instance is passed to a function that accepts the
interface, calling an interface method doesn't work properly.
closes: #13053
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
-rw-r--r-- | src/testdir/test_vim9_class.vim | 77 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9class.c | 20 |
3 files changed, 96 insertions, 3 deletions
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index a6dd66bcc9..a8c95a74da 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -4396,4 +4396,81 @@ def Test_class_member_access_using_object() v9.CheckScriptSuccess(lines) enddef +" Test for using a interface method using a child object +def Test_interface_method_from_child() + var lines =<< trim END + vim9script + + interface A + def Foo(): string + endinterface + + class B implements A + def Foo(): string + return 'foo' + enddef + endclass + + class C extends B + def Bar(): string + return 'bar' + enddef + endclass + + def T1(a: A) + assert_equal('foo', a.Foo()) + enddef + + def T2(b: B) + assert_equal('foo', b.Foo()) + enddef + + var c = C.new() + T1(c) + T2(c) + END + v9.CheckScriptSuccess(lines) +enddef + +" Test for using an interface method using a child object when it is overridden +" by the child class. +" FIXME: This test fails. +" def Test_interface_overridden_method_from_child() +" var lines =<< trim END +" vim9script +" +" interface A +" def Foo(): string +" endinterface +" +" class B implements A +" def Foo(): string +" return 'b-foo' +" enddef +" endclass +" +" class C extends B +" def Bar(): string +" return 'bar' +" enddef +" def Foo(): string +" return 'c-foo' +" enddef +" endclass +" +" def T1(a: A) +" assert_equal('c-foo', a.Foo()) +" enddef +" +" def T2(b: B) +" assert_equal('c-foo', b.Foo()) +" enddef +" +" var c = C.new() +" T1(c) +" T2(c) +" END +" v9.CheckScriptSuccess(lines) +" enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index e525ff657b..da48158d3d 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 */ /**/ + 1883, +/**/ 1882, /**/ 1881, diff --git a/src/vim9class.c b/src/vim9class.c index a65173d61d..9328ee713c 100644 --- a/src/vim9class.c +++ b/src/vim9class.c @@ -237,16 +237,28 @@ object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl, if (cl == itf) return idx; - itf2class_T *i2c = NULL; - int searching = TRUE; + itf2class_T *i2c = NULL; + int searching = TRUE; + int method_offset = 0; + for (class_T *super = cl; super != NULL && searching; super = super->class_extends) + { for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next) + { if (i2c->i2c_class == super && i2c->i2c_is_method == is_method) { searching = FALSE; break; } + } + if (searching && is_method) + // The parent class methods are stored after the current class + // methods. + method_offset += is_static + ? super->class_class_function_count_child + : super->class_obj_method_count_child; + } if (i2c == NULL) { siemsg("class %s not found on interface %s", @@ -273,7 +285,9 @@ object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl, { // A table follows the i2c for the class int *table = (int *)(i2c + 1); - return table[idx]; + // "method_offset" is 0, if method is in the current class. If method + // is in a parent class, then it is non-zero. + return table[idx] + method_offset; } } |