1
0
forked from aniani/vim

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>
This commit is contained in:
Yegappan Lakshmanan 2025-02-09 19:39:52 +01:00 committed by Christian Brabandt
parent f30eb4a170
commit 68d0858892
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
4 changed files with 175 additions and 6 deletions

View File

@ -3508,7 +3508,7 @@ EXTERN char e_abstract_must_be_followed_by_def[]
INIT(= N_("E1371: Abstract must be followed by \"def\"")); INIT(= N_("E1371: Abstract must be followed by \"def\""));
EXTERN char e_abstract_method_in_concrete_class[] EXTERN char e_abstract_method_in_concrete_class[]
INIT(= N_("E1372: Abstract method \"%s\" cannot be defined in a concrete class")); INIT(= N_("E1372: Abstract method \"%s\" cannot be defined in a concrete class"));
EXTERN char e_abstract_method_str_not_found[] EXTERN char e_abstract_method_str_not_implemented[]
INIT(= N_("E1373: Abstract method \"%s\" is not implemented")); INIT(= N_("E1373: Abstract method \"%s\" is not implemented"));
EXTERN char e_class_variable_str_accessible_only_inside_class_str[] EXTERN char e_class_variable_str_accessible_only_inside_class_str[]
INIT(= N_("E1374: Class variable \"%s\" accessible only inside class \"%s\"")); INIT(= N_("E1374: Class variable \"%s\" accessible only inside class \"%s\""));

View File

@ -12221,4 +12221,157 @@ def Test_constructor_init_compound_member_var()
v9.CheckSourceSuccess(lines) v9.CheckSourceSuccess(lines)
enddef enddef
" Test for using a concrete method in an abstract extended class which is
" further extended
def Test_abstract_method_across_hierarchy()
var lines =<< trim END
vim9script
abstract class A
abstract def Foo(): string
endclass
abstract class B extends A
abstract def Bar(): string
endclass
class C extends B
def Foo(): string
return 'foo'
enddef
def Bar(): string
return 'bar'
enddef
endclass
def Fn1(a: A): string
return a.Foo()
enddef
def Fn2(b: B): string
return b.Bar()
enddef
var c = C.new()
assert_equal('foo', Fn1(c))
assert_equal('bar', Fn2(c))
END
v9.CheckSourceSuccess(lines)
lines =<< trim END
vim9script
abstract class A
abstract def Foo(): string
endclass
abstract class B extends A
abstract def Bar(): string
endclass
class C extends B
def Bar(): string
return 'bar'
enddef
endclass
defcompile
END
v9.CheckSourceFailure(lines, 'E1373: Abstract method "Foo" is not implemented')
lines =<< trim END
vim9script
abstract class A
abstract def M1(): string
abstract def M2(): string
endclass
abstract class B extends A
def M1(): string
return 'B: M1'
enddef
def M2(): string
return 'B: M2'
enddef
endclass
class C1 extends B
def M1(): string
return 'C1: M1'
enddef
endclass
class C2 extends B
def M2(): string
return 'C2: M2'
enddef
endclass
class D1 extends C1
endclass
class D2 extends C2
endclass
var l: list<string> = []
for Type in ['C1', 'C2', 'D1', 'D2']
l->add(eval($'{Type}.new().M1()'))
l->add(eval($'{Type}.new().M2()'))
endfor
assert_equal(['C1: M1', 'B: M2', 'B: M1', 'C2: M2', 'C1: M1', 'B: M2', 'B: M1', 'C2: M2'], l)
END
v9.CheckSourceSuccess(lines)
lines =<< trim END
vim9script
abstract class A
abstract def M1(): string
abstract def M2(): string
endclass
class B extends A
def M1(): string
return 'B: M1'
enddef
def M2(): string
return 'B: M2'
enddef
endclass
abstract class C extends B
endclass
class D1 extends C
def M1(): string
return 'D1: M1'
enddef
endclass
class D2 extends C
def M2(): string
return 'D2: M2'
enddef
endclass
class E1 extends D1
endclass
class E2 extends D2
endclass
var l: list<string> = []
for Type in ['B', 'D1', 'D2', 'E1', 'E2']
l->add(eval($'{Type}.new().M1()'))
l->add( eval($'{Type}.new().M2()'))
endfor
assert_equal(['B: M1', 'B: M2', 'D1: M1', 'B: M2', 'B: M1', 'D2: M2', 'D1: M1', 'B: M2', 'B: M1', 'D2: M2'], l)
END
v9.CheckSourceSuccess(lines)
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1094,
/**/ /**/
1093, 1093,
/**/ /**/

View File

@ -561,20 +561,34 @@ validate_abstract_class_methods(
if (!IS_ABSTRACT_METHOD(uf)) if (!IS_ABSTRACT_METHOD(uf))
continue; continue;
int method_found = FALSE; int concrete_method_found = FALSE;
int j = 0;
for (int j = 0; j < method_count; j++) // Check if the abstract method is already implemented in one of
// the parent classes.
for (j = 0; !concrete_method_found && j < i; j++)
{
ufunc_T *uf2 = extends_methods[j];
if (!IS_ABSTRACT_METHOD(uf2) &&
STRCMP(uf->uf_name, uf2->uf_name) == 0)
concrete_method_found = TRUE;
}
if (concrete_method_found)
continue;
for (j = 0; j < method_count; j++)
{ {
if (STRCMP(uf->uf_name, cl_fp[j]->uf_name) == 0) if (STRCMP(uf->uf_name, cl_fp[j]->uf_name) == 0)
{ {
method_found = TRUE; concrete_method_found = TRUE;
break; break;
} }
} }
if (!method_found) if (!concrete_method_found)
{ {
semsg(_(e_abstract_method_str_not_found), uf->uf_name); semsg(_(e_abstract_method_str_not_implemented), uf->uf_name);
return FALSE; return FALSE;
} }
} }