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:
parent
f30eb4a170
commit
68d0858892
@ -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\""));
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user