interfaces: error on implemention of own interface method & on duplicate normal methods
							parent
							
								
									0dafdb4cde
								
							
						
					
					
						commit
						a50f2ca5e8
					
				|  | @ -5841,9 +5841,17 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { | |||
| 			c.error('unknown type `$sym.name`', node.receiver_pos) | ||||
| 			return | ||||
| 		} | ||||
| 		// if sym.has_method(node.name) {
 | ||||
| 		// c.warn('duplicate method `$node.name`', node.pos)
 | ||||
| 		// }
 | ||||
| 		// make sure interface does not implement its own interface methods
 | ||||
| 		if sym.kind == .interface_ && sym.has_method(node.name) { | ||||
| 			if sym.info is table.Interface { | ||||
| 				info := sym.info as table.Interface | ||||
| 				// if the method is in info.methods then it is an interface method
 | ||||
| 				if info.has_method(node.name) { | ||||
| 					c.error('interface `$sym.name` cannot implement its own interface method `$node.name`', | ||||
| 						node.pos) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// needed for proper error reporting during vweb route checking
 | ||||
| 		sym.methods[node.method_idx].source_fn = voidptr(node) | ||||
| 	} | ||||
|  |  | |||
|  | @ -0,0 +1,7 @@ | |||
| vlib/v/checker/tests/interface_implementing_own_interface_method.vv:5:1: error: interface `Animal` cannot implement its own interface method `speak` | ||||
|     3 | } | ||||
|     4 |  | ||||
|     5 | fn (a Animal) speak() { | ||||
|       | ~~~~~~~~~~~~~~~~~~~~~ | ||||
|     6 |     println('speaking') | ||||
|     7 | } | ||||
|  | @ -0,0 +1,7 @@ | |||
| interface Animal { | ||||
|     speak() | ||||
| } | ||||
| 
 | ||||
| fn (a Animal) speak() { | ||||
|     println('speaking') | ||||
| } | ||||
|  | @ -221,11 +221,20 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 			} | ||||
| 		} | ||||
| 		type_sym := p.table.get_type_symbol(rec.typ) | ||||
| 		// interfaces are handled in the checker, methods can not be defined on them this way
 | ||||
| 		if is_method && (type_sym.has_method(name) && type_sym.kind != .interface_) { | ||||
| 			p.error_with_pos('duplicate method `$name`', pos) | ||||
| 			return ast.FnDecl{ | ||||
| 				scope: 0 | ||||
| 		if is_method { | ||||
| 			mut is_duplicate := type_sym.has_method(name) | ||||
| 			// make sure this is a normal method and not an interface method
 | ||||
| 			if type_sym.kind == .interface_ && is_duplicate { | ||||
| 				if type_sym.info is table.Interface { | ||||
| 					// if the method is in info then its an interface method
 | ||||
| 					is_duplicate = !type_sym.info.has_method(name) | ||||
| 				} | ||||
| 			} | ||||
| 			if is_duplicate { | ||||
| 				p.error_with_pos('duplicate method `$name`', pos) | ||||
| 				return ast.FnDecl{ | ||||
| 					scope: 0 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// cannot redefine buildin function
 | ||||
|  | @ -276,7 +285,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	mut end_pos := p.prev_tok.position() | ||||
| 	// Return type
 | ||||
| 	mut return_type := table.void_type | ||||
| 	// don't confuse token on the next line: fn decl, [attribute]
 | ||||
|  | @ -287,6 +295,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 	} | ||||
| 	mut type_sym_method_idx := 0 | ||||
| 	no_body := p.tok.kind != .lcbr | ||||
| 	end_pos := p.prev_tok.position() | ||||
| 	// Register
 | ||||
| 	if is_method { | ||||
| 		mut type_sym := p.table.get_type_symbol(rec.typ) | ||||
|  | @ -348,7 +357,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 			language: language | ||||
| 		}) | ||||
| 	} | ||||
| 	end_pos = p.prev_tok.position() | ||||
| 	// Body
 | ||||
| 	p.cur_fn_name = name | ||||
| 	mut stmts := []ast.Stmt{} | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| vlib/v/parser/tests/interface_duplicate_interface_method.vv:4:2: error: duplicate method `fun` | ||||
|     2 | interface Abc { | ||||
|     3 |     fun() | ||||
|     4 |     fun() | ||||
|       |     ~~~ | ||||
|     5 | } | ||||
|  | @ -0,0 +1,5 @@ | |||
| // duplicate interface methods in decleration
 | ||||
| interface Abc { | ||||
| 	fun() | ||||
| 	fun() | ||||
| } | ||||
|  | @ -1,6 +1,5 @@ | |||
| vlib/v/parser/tests/interface_duplicate_method.vv:3:2: error: duplicate method `fun` | ||||
|     1 | interface Abc { | ||||
|     2 |     fun() | ||||
|     3 |     fun() | ||||
|       |     ~~~ | ||||
|     4 | } | ||||
| vlib/v/parser/tests/interface_duplicate_method.vv:5:12: error: duplicate method `foo` | ||||
|     3 | // duplicate normal method definitions on interface | ||||
|     4 | fn (a Abc) foo() {} | ||||
|     5 | fn (a Abc) foo() {} | ||||
|       |            ~~~ | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| interface Abc { | ||||
| 	fun() | ||||
| 	fun() | ||||
| } | ||||
| interface Abc {} | ||||
| 
 | ||||
| // duplicate normal method definitions on interface
 | ||||
| fn (a Abc) foo() {} | ||||
| fn (a Abc) foo() {} | ||||
|  | @ -993,6 +993,22 @@ pub fn (i &Interface) find_field(name string) ?Field { | |||
| 	return none | ||||
| } | ||||
| 
 | ||||
| pub fn (i &Interface) find_method(name string) ?Fn { | ||||
| 	for method in i.methods { | ||||
| 		if method.name == name { | ||||
| 			return method | ||||
| 		} | ||||
| 	} | ||||
| 	return none | ||||
| } | ||||
| 
 | ||||
| pub fn (i &Interface) has_method(name string) bool { | ||||
| 	if _ := i.find_method(name) { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| pub fn (s Struct) find_field(name string) ?Field { | ||||
| 	for field in s.fields { | ||||
| 		if field.name == name { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue