diff --git a/vlib/v/checker/interface.v b/vlib/v/checker/interface.v index fb7d8822ad..fc09bc6cea 100644 --- a/vlib/v/checker/interface.v +++ b/vlib/v/checker/interface.v @@ -11,6 +11,7 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) { mut decl_sym := c.table.sym(node.typ) is_js := node.language == .js if mut decl_sym.info is ast.Interface { + mut has_generic_types := false if node.embeds.len > 0 { 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') @@ -31,6 +32,9 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) { } for embed in all_embeds { isym := c.table.sym(embed.typ) + if embed.typ.has_flag(.generic) { + has_generic_types = true + } if isym.kind != .interface_ { c.error('interface `$node.name` tries to embed `$isym.name`, but `$isym.name` is not an interface, but `$isym.kind`', 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) } } + if method.return_type.has_flag(.generic) { + has_generic_types = true + } for j, param in method.params { if j == 0 && is_js { 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 } if param.name in reserved_type_names { 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.ensure_type_exists(field.typ, field.pos) or { return } + if field.typ.has_flag(.generic) { + has_generic_types = true + } if is_js { tsym := c.table.sym(field.typ) 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', + node.pos) + } } } diff --git a/vlib/v/checker/tests/generics_interface_declaration_err.out b/vlib/v/checker/tests/generics_interface_declaration_err.out new file mode 100644 index 0000000000..bcf5b5db0c --- /dev/null +++ b/vlib/v/checker/tests/generics_interface_declaration_err.out @@ -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 + 1 | interface Expr { + | ~~~~~~~~~~~~~~~~ + 2 | accept(v Visitor) R + 3 | } diff --git a/vlib/v/checker/tests/generics_interface_declaration_err.vv b/vlib/v/checker/tests/generics_interface_declaration_err.vv new file mode 100644 index 0000000000..a73e949bd6 --- /dev/null +++ b/vlib/v/checker/tests/generics_interface_declaration_err.vv @@ -0,0 +1,9 @@ +interface Expr { + accept(v Visitor) R +} + +interface Visitor { +} + +fn main() { +}