diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 75bfc75367..f8fdf70791 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -6752,6 +6752,24 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { c.file.generic_fns << node return } + // Check generics fn/method without generic type parameters + mut need_generic_names := false + if node.generic_names.len == 0 { + if node.return_type.has_flag(.generic) { + need_generic_names = true + } else { + for param in node.params { + if param.typ.has_flag(.generic) { + need_generic_names = true + break + } + } + } + if need_generic_names { + c.error('generic function declaration must specify generic type names, e.g. foo', + node.pos) + } + } if node.language == .v && !c.is_builtin_mod { c.check_valid_snake_case(node.name, 'function name', node.pos) } diff --git a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out new file mode 100644 index 0000000000..502f2b816a --- /dev/null +++ b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:26:1: error: generic function declaration must specify generic type names, e.g. foo + 24 | } + 25 | + 26 | fn g_worker(g Generic) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + 27 | t := <-g.ch + 28 | handle(t) +vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:32:1: error: generic function declaration must specify generic type names, e.g. foo + 30 | } + 31 | + 32 | fn handle(t T) { + | ~~~~~~~~~~~~~~ + 33 | println("hi") + 34 | } diff --git a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv new file mode 100644 index 0000000000..cc001e9412 --- /dev/null +++ b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv @@ -0,0 +1,34 @@ +struct Generic { + ch chan T +} + +struct Concrete { + msg string +} + +fn main() { + g := create_generic_t() + g.ch <- Concrete{ + msg: 'hello' + } +} + +fn create_generic_t() Generic { + g := Generic{ + ch: chan T{} + } + + go g_worker(g) + + return g +} + +fn g_worker(g Generic) { + t := <-g.ch + handle(t) + // println("${t.msg}") +} + +fn handle(t T) { + println("hi") +} diff --git a/vlib/v/checker/tests/receiver_unknown_type_single_letter.out b/vlib/v/checker/tests/receiver_unknown_type_single_letter.out index 40e356eff7..bd187d4269 100644 --- a/vlib/v/checker/tests/receiver_unknown_type_single_letter.out +++ b/vlib/v/checker/tests/receiver_unknown_type_single_letter.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/receiver_unknown_type_single_letter.vv:1:5: error: unknown type `A` - 1 | fn (p A) foo() {} - | ~~~ +vlib/v/checker/tests/receiver_unknown_type_single_letter.vv:1:1: error: unknown type `Abc` + 1 | fn (p Abc) foo() {} + | ~~~~~~~~~~~~~~~~ 2 | diff --git a/vlib/v/checker/tests/receiver_unknown_type_single_letter.vv b/vlib/v/checker/tests/receiver_unknown_type_single_letter.vv index 4c00043e35..703cf29c59 100644 --- a/vlib/v/checker/tests/receiver_unknown_type_single_letter.vv +++ b/vlib/v/checker/tests/receiver_unknown_type_single_letter.vv @@ -1,2 +1,2 @@ -fn (p A) foo() {} +fn (p Abc) foo() {} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 77c318a771..5757640792 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -336,6 +336,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { short_fn_name := name is_main := short_fn_name == 'main' && p.mod == 'main' is_test := short_fn_name.starts_with('test_') || short_fn_name.starts_with('testsuite_') + // Register if is_method { mut type_sym := p.table.get_type_symbol(rec.typ)