checker: verify interface is not used as receiver

pull/4770/head
Enzo Baldisserri 2020-05-07 10:14:51 +02:00 committed by GitHub
parent 7d32476841
commit 0f8ed84333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 7 deletions

View File

@ -206,6 +206,7 @@ pub:
is_variadic bool
is_anon bool
receiver Field
receiver_pos token.Position
is_method bool
rec_mut bool // is receiver mutable
is_c bool

View File

@ -1385,12 +1385,15 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.check_expr_opt_call(it.expr, etype, false)
}
ast.FnDecl {
// if it.is_method {
// sym := c.table.get_type_symbol(it.receiver.typ)
// if sym.has_method(it.name) {
// c.warn('duplicate method `$it.name`', it.pos)
// }
// }
if it.is_method {
sym := c.table.get_type_symbol(it.receiver.typ)
if sym.kind == .interface_ {
c.error('interaces cannot be used as method receiver', it.receiver_pos)
}
// if sym.has_method(it.name) {
// c.warn('duplicate method `$it.name`', it.pos)
// }
}
if !it.is_c {
// Make sure all types are valid
for arg in it.args {
@ -1748,7 +1751,8 @@ pub fn (mut c Checker) ident(ident mut ast.Ident) table.Type {
if sym.info is table.FnType {
// anon/local fn assigned to new variable uses this
info := sym.info as table.FnType
fn_type := table.new_type(c.table.find_or_register_fn_type(info.func, true, true))
fn_type := table.new_type(c.table.find_or_register_fn_type(info.func,
true, true))
ident.kind = .function
ident.info = ast.IdentFn{
typ: fn_type

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/no_interface_receiver.v:5:5: error: interaces cannot be used as method receiver
3 | }
4 |
5 | fn (a Animal) str() {}
| ~~~~~~~~

View File

@ -0,0 +1,5 @@
interface Animal {
speak()
}
fn (a Animal) str() {}

View File

@ -109,6 +109,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
// Receiver?
mut rec_name := ''
mut is_method := false
mut receiver_pos := token.Position{}
mut rec_type := table.void_type
mut rec_mut := false
mut args := []table.Arg{}
@ -119,11 +120,13 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
if rec_mut {
p.next() // `mut`
}
rec_start_pos := p.tok.position()
rec_name = p.check_name()
if !rec_mut {
rec_mut = p.tok.kind == .key_mut
}
is_amp := p.tok.kind == .amp
receiver_pos = rec_start_pos.extend(p.tok.position())
// if rec_mut {
// p.check(.key_mut)
// }
@ -256,6 +259,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
name: rec_name
typ: rec_type
}
receiver_pos: receiver_pos
is_method: is_method
rec_mut: rec_mut
is_c: is_c