diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 3ee1de6922..b8a97be20f 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -108,6 +108,17 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { } else if return_sym.kind == .array_fixed { c.error('fixed array cannot be returned by function', node.return_type_pos) } + // Ensure each generic type of the parameter was declared in the function's definition + if node.return_type.has_flag(.generic) { + generic_names := c.table.generic_type_names(node.return_type) + for name in generic_names { + if name !in node.generic_names { + fn_generic_names := node.generic_names.join(', ') + c.error('generic type name `$name` is not mentioned in fn `$node.name<$fn_generic_names>`', + node.return_type_pos) + } + } + } } else { for mut a in node.attrs { if a.kind == .comptime_define { @@ -207,6 +218,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { } } } + // Ensure each generic type of the parameter was declared in the function's definition if param.typ.has_flag(.generic) { generic_names := c.table.generic_type_names(param.typ) for name in generic_names { diff --git a/vlib/v/checker/tests/generic_fn_decl_err.out b/vlib/v/checker/tests/generic_fn_decl_err.out new file mode 100644 index 0000000000..d5f40c1347 --- /dev/null +++ b/vlib/v/checker/tests/generic_fn_decl_err.out @@ -0,0 +1,35 @@ +vlib/v/checker/tests/generic_fn_decl_err.vv:19:29: error: generic type name `P` is not mentioned in fn `create1` + 17 | } + 18 | + 19 | fn (r Db) create1(u U, p P) { + | ^ + 20 | println('Yo') + 21 | } +vlib/v/checker/tests/generic_fn_decl_err.vv:23:29: error: generic type name `P` is not mentioned in fn `create2` + 21 | } + 22 | + 23 | fn (r Db) create2(u U, p &P) { + | ~~ + 24 | println('Yo') + 25 | } +vlib/v/checker/tests/generic_fn_decl_err.vv:27:29: error: generic type name `P` is not mentioned in fn `create3` + 25 | } + 26 | + 27 | fn (r Db) create3(u U, p []P) { + | ~~~ + 28 | println('Yo') + 29 | } +vlib/v/checker/tests/generic_fn_decl_err.vv:31:27: error: generic type name `P` is not mentioned in fn `create4` + 29 | } + 30 | + 31 | fn (r Db) create4(u U) P { + | ^ + 32 | return P{} + 33 | } +vlib/v/checker/tests/generic_fn_decl_err.vv:35:27: error: generic type name `P` is not mentioned in fn `create5` + 33 | } + 34 | + 35 | fn (r Db) create5(u U) []P { + | ~~~ + 36 | return [P{}] + 37 | } diff --git a/vlib/v/checker/tests/generic_fn_decl_err.vv b/vlib/v/checker/tests/generic_fn_decl_err.vv new file mode 100644 index 0000000000..2d93cca686 --- /dev/null +++ b/vlib/v/checker/tests/generic_fn_decl_err.vv @@ -0,0 +1,37 @@ +module main + +struct Db {} +struct User {} +struct Post {} + +fn main() { + r := Db{} + u := User{} + p := Post{} + + r.create1(u, p) + r.create2(u, &p) + r.create3(u, [p]) + r.create4(u) + r.create5(u) +} + +fn (r Db) create1(u U, p P) { + println('Yo') +} + +fn (r Db) create2(u U, p &P) { + println('Yo') +} + +fn (r Db) create3(u U, p []P) { + println('Yo') +} + +fn (r Db) create4(u U) P { + return P{} +} + +fn (r Db) create5(u U) []P { + return [P{}] +} diff --git a/vlib/v/checker/tests/generic_fn_decl_err_a.out b/vlib/v/checker/tests/generic_fn_decl_err_a.out deleted file mode 100644 index b379de2714..0000000000 --- a/vlib/v/checker/tests/generic_fn_decl_err_a.out +++ /dev/null @@ -1,7 +0,0 @@ -vlib/v/checker/tests/generic_fn_decl_err_a.vv:17:28: error: generic type name `P` is not mentioned in fn `create` - 15 | } - 16 | - 17 | fn (r Db) create(u U, p P) { - | ^ - 18 | println('Yo') - 19 | } diff --git a/vlib/v/checker/tests/generic_fn_decl_err_a.vv b/vlib/v/checker/tests/generic_fn_decl_err_a.vv deleted file mode 100644 index 98be9c4413..0000000000 --- a/vlib/v/checker/tests/generic_fn_decl_err_a.vv +++ /dev/null @@ -1,19 +0,0 @@ -module main - -struct Db {} - -struct User {} - -struct Post {} - -fn main() { - r := Db{} - u := User{} - p := Post{} - - r.create(u, p) -} - -fn (r Db) create(u U, p P) { - println('Yo') -}