Skip to content

Commit cc0bcf4

Browse files
yegappanchrisbra
authored andcommitted
patch 9.0.1883: Vim9: Calling an interface method using a child object fails
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 <[email protected]> Co-authored-by: Yegappan Lakshmanan <[email protected]>
1 parent 11d2aee commit cc0bcf4

3 files changed

Lines changed: 96 additions & 3 deletions

File tree

src/testdir/test_vim9_class.vim

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4396,4 +4396,81 @@ def Test_class_member_access_using_object()
43964396
v9.CheckScriptSuccess(lines)
43974397
enddef
43984398

4399+
" Test for using a interface method using a child object
4400+
def Test_interface_method_from_child()
4401+
var lines =<< trim END
4402+
vim9script
4403+
4404+
interface A
4405+
def Foo(): string
4406+
endinterface
4407+
4408+
class B implements A
4409+
def Foo(): string
4410+
return 'foo'
4411+
enddef
4412+
endclass
4413+
4414+
class C extends B
4415+
def Bar(): string
4416+
return 'bar'
4417+
enddef
4418+
endclass
4419+
4420+
def T1(a: A)
4421+
assert_equal('foo', a.Foo())
4422+
enddef
4423+
4424+
def T2(b: B)
4425+
assert_equal('foo', b.Foo())
4426+
enddef
4427+
4428+
var c = C.new()
4429+
T1(c)
4430+
T2(c)
4431+
END
4432+
v9.CheckScriptSuccess(lines)
4433+
enddef
4434+
4435+
" Test for using an interface method using a child object when it is overridden
4436+
" by the child class.
4437+
" FIXME: This test fails.
4438+
" def Test_interface_overridden_method_from_child()
4439+
" var lines =<< trim END
4440+
" vim9script
4441+
"
4442+
" interface A
4443+
" def Foo(): string
4444+
" endinterface
4445+
"
4446+
" class B implements A
4447+
" def Foo(): string
4448+
" return 'b-foo'
4449+
" enddef
4450+
" endclass
4451+
"
4452+
" class C extends B
4453+
" def Bar(): string
4454+
" return 'bar'
4455+
" enddef
4456+
" def Foo(): string
4457+
" return 'c-foo'
4458+
" enddef
4459+
" endclass
4460+
"
4461+
" def T1(a: A)
4462+
" assert_equal('c-foo', a.Foo())
4463+
" enddef
4464+
"
4465+
" def T2(b: B)
4466+
" assert_equal('c-foo', b.Foo())
4467+
" enddef
4468+
"
4469+
" var c = C.new()
4470+
" T1(c)
4471+
" T2(c)
4472+
" END
4473+
" v9.CheckScriptSuccess(lines)
4474+
" enddef
4475+
43994476
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ static char *(features[]) =
699699

700700
static int included_patches[] =
701701
{ /* Add new patch number below this line */
702+
/**/
703+
1883,
702704
/**/
703705
1882,
704706
/**/

src/vim9class.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,16 +237,28 @@ object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl,
237237
if (cl == itf)
238238
return idx;
239239

240-
itf2class_T *i2c = NULL;
241-
int searching = TRUE;
240+
itf2class_T *i2c = NULL;
241+
int searching = TRUE;
242+
int method_offset = 0;
243+
242244
for (class_T *super = cl; super != NULL && searching;
243245
super = super->class_extends)
246+
{
244247
for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next)
248+
{
245249
if (i2c->i2c_class == super && i2c->i2c_is_method == is_method)
246250
{
247251
searching = FALSE;
248252
break;
249253
}
254+
}
255+
if (searching && is_method)
256+
// The parent class methods are stored after the current class
257+
// methods.
258+
method_offset += is_static
259+
? super->class_class_function_count_child
260+
: super->class_obj_method_count_child;
261+
}
250262
if (i2c == NULL)
251263
{
252264
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,
273285
{
274286
// A table follows the i2c for the class
275287
int *table = (int *)(i2c + 1);
276-
return table[idx];
288+
// "method_offset" is 0, if method is in the current class. If method
289+
// is in a parent class, then it is non-zero.
290+
return table[idx] + method_offset;
277291
}
278292
}
279293

0 commit comments

Comments
 (0)