mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	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:
		
				
					committed by
					
						 Christian Brabandt
						Christian Brabandt
					
				
			
			
				
	
			
			
			
						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\"")); | ||||
| EXTERN char e_abstract_method_in_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")); | ||||
| EXTERN char e_class_variable_str_accessible_only_inside_class_str[] | ||||
| 	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) | ||||
| 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 | ||||
|   | ||||
| @@ -704,6 +704,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     1094, | ||||
| /**/ | ||||
|     1093, | ||||
| /**/ | ||||
|   | ||||
| @@ -561,20 +561,34 @@ validate_abstract_class_methods( | ||||
| 	    if (!IS_ABSTRACT_METHOD(uf)) | ||||
| 		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) | ||||
| 		{ | ||||
| 		    method_found = TRUE; | ||||
| 		    concrete_method_found = TRUE; | ||||
| 		    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; | ||||
| 	    } | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user