diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 355be70ecf..973ee242b5 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -673,6 +673,12 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) && !c.file.is_translated && !func.is_unsafe { c.error('cannot call a function that does not have a body', node.pos) } + if node.concrete_types.len > 0 && func.generic_names.len > 0 + && node.concrete_types.len != func.generic_names.len { + desc := if node.concrete_types.len > func.generic_names.len { 'many' } else { 'little' } + c.error('too $desc generic parameters got $node.concrete_types.len, expected $func.generic_names.len', + node.concrete_list_pos) + } for concrete_type in node.concrete_types { c.ensure_type_exists(concrete_type, node.concrete_list_pos) or {} } @@ -961,10 +967,6 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) c.error('a non generic function called like a generic one', node.concrete_list_pos) } - if node.concrete_types.len > func.generic_names.len { - c.error('too many generic parameters got $node.concrete_types.len, expected $func.generic_names.len', - node.concrete_list_pos) - } if func.generic_names.len > 0 { if has_generic { if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names, @@ -1189,6 +1191,19 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { && method.language == .v && method.no_body { c.error('cannot call a method that does not have a body', node.pos) } + if node.concrete_types.len > 0 && method.generic_names.len > 0 + && node.concrete_types.len != method.generic_names.len { + desc := if node.concrete_types.len > method.generic_names.len { + 'many' + } else { + 'little' + } + c.error('too $desc generic parameters got $node.concrete_types.len, expected $method.generic_names.len', + node.concrete_list_pos) + } + for concrete_type in node.concrete_types { + c.ensure_type_exists(concrete_type, node.concrete_list_pos) or {} + } if method.return_type == ast.void_type && method.is_conditional && method.ctdefine_idx != ast.invalid_type_idx { node.should_be_skipped = c.evaluate_once_comptime_if_attribute(mut method.attrs[method.ctdefine_idx]) @@ -1395,10 +1410,6 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { if node.concrete_types.len > 0 && method.generic_names.len == 0 { c.error('a non generic function called like a generic one', node.concrete_list_pos) } - if node.concrete_types.len > method.generic_names.len { - c.error('too many generic parameters got $node.concrete_types.len, expected $method.generic_names.len', - node.concrete_list_pos) - } if method.generic_names.len > 0 { if !left_type.has_flag(.generic) { if left_sym.info is ast.Struct { diff --git a/vlib/v/checker/tests/generics_fn_arguments_count_err.out b/vlib/v/checker/tests/generics_fn_arguments_count_err.out new file mode 100644 index 0000000000..d1c7c6e438 --- /dev/null +++ b/vlib/v/checker/tests/generics_fn_arguments_count_err.out @@ -0,0 +1,41 @@ +vlib/v/checker/tests/generics_fn_arguments_count_err.vv:12:18: error: too little generic parameters got 1, expected 2 + 10 | + 11 | fn main() { + 12 | ret1 := get_name(11, 22) + | ~~~~~ + 13 | println(ret1) + 14 | +vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:18: error: too many generic parameters got 3, expected 2 + 13 | println(ret1) + 14 | + 15 | ret2 := get_name(11, 22, 'hello') + | ~~~~~~~~~~~~~~~~~~ + 16 | println(ret2) + 17 | +vlib/v/checker/tests/generics_fn_arguments_count_err.vv:19:22: error: too little generic parameters got 1, expected 2 + 17 | + 18 | foo := Foo{} + 19 | ret3 := foo.get_name(11, 22) + | ~~~~~ + 20 | println(ret3) + 21 | +vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:22: error: too many generic parameters got 3, expected 2 + 20 | println(ret3) + 21 | + 22 | ret4 := foo.get_name(11, 22, 'hello') + | ~~~~~~~~~~~~~~~~~~ + 23 | println(ret4) + 24 | } +vlib/v/checker/tests/generics_fn_arguments_count_err.vv:2:15: error: no known default format for type `B` + 1 | fn get_name(a A, b B) string { + 2 | return '$a, $b' + | ^ + 3 | } + 4 | +vlib/v/checker/tests/generics_fn_arguments_count_err.vv:8:15: error: no known default format for type `B` + 6 | + 7 | fn (f Foo) get_name(a A, b B) string { + 8 | return '$a, $b' + | ^ + 9 | } + 10 | diff --git a/vlib/v/checker/tests/generics_fn_arguments_count_err.vv b/vlib/v/checker/tests/generics_fn_arguments_count_err.vv new file mode 100644 index 0000000000..2eeba8ebe5 --- /dev/null +++ b/vlib/v/checker/tests/generics_fn_arguments_count_err.vv @@ -0,0 +1,24 @@ +fn get_name(a A, b B) string { + return '$a, $b' +} + +struct Foo {} + +fn (f Foo) get_name(a A, b B) string { + return '$a, $b' +} + +fn main() { + ret1 := get_name(11, 22) + println(ret1) + + ret2 := get_name(11, 22, 'hello') + println(ret2) + + foo := Foo{} + ret3 := foo.get_name(11, 22) + println(ret3) + + ret4 := foo.get_name(11, 22, 'hello') + println(ret4) +}