1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check generic interface declaration (#15047)

This commit is contained in:
yuyi 2022-07-13 14:43:54 +08:00 committed by GitHub
parent 28fd17654e
commit 7594157deb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 0 deletions

View File

@ -11,6 +11,7 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
mut decl_sym := c.table.sym(node.typ) mut decl_sym := c.table.sym(node.typ)
is_js := node.language == .js is_js := node.language == .js
if mut decl_sym.info is ast.Interface { if mut decl_sym.info is ast.Interface {
mut has_generic_types := false
if node.embeds.len > 0 { if node.embeds.len > 0 {
all_embeds := c.expand_iface_embeds(node, 0, node.embeds) all_embeds := c.expand_iface_embeds(node, 0, node.embeds)
// eprintln('> node.name: $node.name | node.embeds.len: $node.embeds.len | all_embeds: $all_embeds.len') // eprintln('> node.name: $node.name | node.embeds.len: $node.embeds.len | all_embeds: $all_embeds.len')
@ -31,6 +32,9 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
} }
for embed in all_embeds { for embed in all_embeds {
isym := c.table.sym(embed.typ) isym := c.table.sym(embed.typ)
if embed.typ.has_flag(.generic) {
has_generic_types = true
}
if isym.kind != .interface_ { if isym.kind != .interface_ {
c.error('interface `$node.name` tries to embed `$isym.name`, but `$isym.name` is not an interface, but `$isym.kind`', c.error('interface `$node.name` tries to embed `$isym.name`, but `$isym.name` is not an interface, but `$isym.kind`',
embed.pos) embed.pos)
@ -109,10 +113,16 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
c.error('method $method.name returns non JS type', method.pos) c.error('method $method.name returns non JS type', method.pos)
} }
} }
if method.return_type.has_flag(.generic) {
has_generic_types = true
}
for j, param in method.params { for j, param in method.params {
if j == 0 && is_js { if j == 0 && is_js {
continue // no need to check first param continue // no need to check first param
} }
if param.typ.has_flag(.generic) {
has_generic_types = true
}
c.ensure_type_exists(param.typ, param.pos) or { return } c.ensure_type_exists(param.typ, param.pos) or { return }
if param.name in reserved_type_names { if param.name in reserved_type_names {
c.error('invalid use of reserved type `$param.name` as a parameter name', c.error('invalid use of reserved type `$param.name` as a parameter name',
@ -145,6 +155,9 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
c.check_valid_snake_case(field.name, 'field name', field.pos) c.check_valid_snake_case(field.name, 'field name', field.pos)
} }
c.ensure_type_exists(field.typ, field.pos) or { return } c.ensure_type_exists(field.typ, field.pos) or { return }
if field.typ.has_flag(.generic) {
has_generic_types = true
}
if is_js { if is_js {
tsym := c.table.sym(field.typ) tsym := c.table.sym(field.typ)
if !tsym.is_js_compatible() { if !tsym.is_js_compatible() {
@ -161,6 +174,10 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
} }
} }
} }
if node.generic_types.len == 0 && has_generic_types {
c.error('generic interface declaration must specify the generic type names, e.g. Foo<T>',
node.pos)
}
} }
} }

View File

@ -0,0 +1,5 @@
vlib/v/checker/tests/generics_interface_declaration_err.vv:1:1: error: generic interface declaration must specify the generic type names, e.g. Foo<T>
1 | interface Expr {
| ~~~~~~~~~~~~~~~~
2 | accept(v Visitor<R>) R
3 | }

View File

@ -0,0 +1,9 @@
interface Expr {
accept(v Visitor<R>) R
}
interface Visitor<R> {
}
fn main() {
}