Skip to content

Commit 68d0858

Browse files
yegappanchrisbra
authored andcommitted
patch 9.1.1094: Vim9: problem finding implemented method in type hierarchy
Problem: Vim9: problem finding implemented method for abstract method in type hierarchy (Aliaksei Budavei) Solution: When checking for abstract methods in an extended class, check whether an abstract method is implemented in one of the parent classes (Yegappan Lakshmanan) fixes: #16495 closes: #16497 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent f30eb4a commit 68d0858

4 files changed

Lines changed: 175 additions & 6 deletions

File tree

src/errors.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3508,7 +3508,7 @@ EXTERN char e_abstract_must_be_followed_by_def[]
35083508
INIT(= N_("E1371: Abstract must be followed by \"def\""));
35093509
EXTERN char e_abstract_method_in_concrete_class[]
35103510
INIT(= N_("E1372: Abstract method \"%s\" cannot be defined in a concrete class"));
3511-
EXTERN char e_abstract_method_str_not_found[]
3511+
EXTERN char e_abstract_method_str_not_implemented[]
35123512
INIT(= N_("E1373: Abstract method \"%s\" is not implemented"));
35133513
EXTERN char e_class_variable_str_accessible_only_inside_class_str[]
35143514
INIT(= N_("E1374: Class variable \"%s\" accessible only inside class \"%s\""));

src/testdir/test_vim9_class.vim

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12221,4 +12221,157 @@ def Test_constructor_init_compound_member_var()
1222112221
v9.CheckSourceSuccess(lines)
1222212222
enddef
1222312223

12224+
" Test for using a concrete method in an abstract extended class which is
12225+
" further extended
12226+
def Test_abstract_method_across_hierarchy()
12227+
var lines =<< trim END
12228+
vim9script
12229+
12230+
abstract class A
12231+
abstract def Foo(): string
12232+
endclass
12233+
12234+
abstract class B extends A
12235+
abstract def Bar(): string
12236+
endclass
12237+
12238+
class C extends B
12239+
def Foo(): string
12240+
return 'foo'
12241+
enddef
12242+
12243+
def Bar(): string
12244+
return 'bar'
12245+
enddef
12246+
endclass
12247+
12248+
def Fn1(a: A): string
12249+
return a.Foo()
12250+
enddef
12251+
12252+
def Fn2(b: B): string
12253+
return b.Bar()
12254+
enddef
12255+
12256+
var c = C.new()
12257+
assert_equal('foo', Fn1(c))
12258+
assert_equal('bar', Fn2(c))
12259+
END
12260+
v9.CheckSourceSuccess(lines)
12261+
12262+
lines =<< trim END
12263+
vim9script
12264+
12265+
abstract class A
12266+
abstract def Foo(): string
12267+
endclass
12268+
12269+
abstract class B extends A
12270+
abstract def Bar(): string
12271+
endclass
12272+
12273+
class C extends B
12274+
def Bar(): string
12275+
return 'bar'
12276+
enddef
12277+
endclass
12278+
12279+
defcompile
12280+
END
12281+
v9.CheckSourceFailure(lines, 'E1373: Abstract method "Foo" is not implemented')
12282+
12283+
lines =<< trim END
12284+
vim9script
12285+
12286+
abstract class A
12287+
abstract def M1(): string
12288+
abstract def M2(): string
12289+
endclass
12290+
12291+
abstract class B extends A
12292+
def M1(): string
12293+
return 'B: M1'
12294+
enddef
12295+
12296+
def M2(): string
12297+
return 'B: M2'
12298+
enddef
12299+
endclass
12300+
12301+
class C1 extends B
12302+
def M1(): string
12303+
return 'C1: M1'
12304+
enddef
12305+
endclass
12306+
12307+
class C2 extends B
12308+
def M2(): string
12309+
return 'C2: M2'
12310+
enddef
12311+
endclass
12312+
12313+
class D1 extends C1
12314+
endclass
12315+
12316+
class D2 extends C2
12317+
endclass
12318+
12319+
var l: list<string> = []
12320+
for Type in ['C1', 'C2', 'D1', 'D2']
12321+
l->add(eval($'{Type}.new().M1()'))
12322+
l->add(eval($'{Type}.new().M2()'))
12323+
endfor
12324+
assert_equal(['C1: M1', 'B: M2', 'B: M1', 'C2: M2', 'C1: M1', 'B: M2', 'B: M1', 'C2: M2'], l)
12325+
END
12326+
v9.CheckSourceSuccess(lines)
12327+
12328+
lines =<< trim END
12329+
vim9script
12330+
12331+
abstract class A
12332+
abstract def M1(): string
12333+
abstract def M2(): string
12334+
endclass
12335+
12336+
class B extends A
12337+
def M1(): string
12338+
return 'B: M1'
12339+
enddef
12340+
12341+
def M2(): string
12342+
return 'B: M2'
12343+
enddef
12344+
endclass
12345+
12346+
abstract class C extends B
12347+
endclass
12348+
12349+
class D1 extends C
12350+
def M1(): string
12351+
return 'D1: M1'
12352+
enddef
12353+
endclass
12354+
12355+
class D2 extends C
12356+
def M2(): string
12357+
return 'D2: M2'
12358+
enddef
12359+
endclass
12360+
12361+
class E1 extends D1
12362+
endclass
12363+
12364+
class E2 extends D2
12365+
endclass
12366+
12367+
var l: list<string> = []
12368+
for Type in ['B', 'D1', 'D2', 'E1', 'E2']
12369+
l->add(eval($'{Type}.new().M1()'))
12370+
l->add( eval($'{Type}.new().M2()'))
12371+
endfor
12372+
assert_equal(['B: M1', 'B: M2', 'D1: M1', 'B: M2', 'B: M1', 'D2: M2', 'D1: M1', 'B: M2', 'B: M1', 'D2: M2'], l)
12373+
END
12374+
v9.CheckSourceSuccess(lines)
12375+
enddef
12376+
1222412377
" 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
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
1094,
707709
/**/
708710
1093,
709711
/**/

src/vim9class.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -561,20 +561,34 @@ validate_abstract_class_methods(
561561
if (!IS_ABSTRACT_METHOD(uf))
562562
continue;
563563

564-
int method_found = FALSE;
564+
int concrete_method_found = FALSE;
565+
int j = 0;
565566

566-
for (int j = 0; j < method_count; j++)
567+
// Check if the abstract method is already implemented in one of
568+
// the parent classes.
569+
for (j = 0; !concrete_method_found && j < i; j++)
570+
{
571+
ufunc_T *uf2 = extends_methods[j];
572+
if (!IS_ABSTRACT_METHOD(uf2) &&
573+
STRCMP(uf->uf_name, uf2->uf_name) == 0)
574+
concrete_method_found = TRUE;
575+
}
576+
577+
if (concrete_method_found)
578+
continue;
579+
580+
for (j = 0; j < method_count; j++)
567581
{
568582
if (STRCMP(uf->uf_name, cl_fp[j]->uf_name) == 0)
569583
{
570-
method_found = TRUE;
584+
concrete_method_found = TRUE;
571585
break;
572586
}
573587
}
574588

575-
if (!method_found)
589+
if (!concrete_method_found)
576590
{
577-
semsg(_(e_abstract_method_str_not_found), uf->uf_name);
591+
semsg(_(e_abstract_method_str_not_implemented), uf->uf_name);
578592
return FALSE;
579593
}
580594
}

0 commit comments

Comments
 (0)