summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2023-09-08 19:12:03 +0200
committerChristian Brabandt <cb@256bit.org>2023-09-08 19:12:03 +0200
commitcc0bcf4c9f4133750f5ee99c685ba995a1b840fd (patch)
tree838c9185d9184bcb249b10275883e7a89f8fc639
parent11d2aeeca4cf191b3f25b36603dcd32167eac8a0 (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.vim77
-rw-r--r--src/version.c2
-rw-r--r--src/vim9class.c20
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;
}
}