checker: check the count of generics in fn arguments (#13855)
parent
4f551d76c0
commit
fd34ebd84e
|
@ -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 {
|
||||
|
|
|
@ -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<int>(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<int, int, string>(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<int>(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<int, int, string>(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, B>(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, B>(a A, b B) string {
|
||||
8 | return '$a, $b'
|
||||
| ^
|
||||
9 | }
|
||||
10 |
|
|
@ -0,0 +1,24 @@
|
|||
fn get_name<A, B>(a A, b B) string {
|
||||
return '$a, $b'
|
||||
}
|
||||
|
||||
struct Foo {}
|
||||
|
||||
fn (f Foo) get_name<A, B>(a A, b B) string {
|
||||
return '$a, $b'
|
||||
}
|
||||
|
||||
fn main() {
|
||||
ret1 := get_name<int>(11, 22)
|
||||
println(ret1)
|
||||
|
||||
ret2 := get_name<int, int, string>(11, 22, 'hello')
|
||||
println(ret2)
|
||||
|
||||
foo := Foo{}
|
||||
ret3 := foo.get_name<int>(11, 22)
|
||||
println(ret3)
|
||||
|
||||
ret4 := foo.get_name<int, int, string>(11, 22, 'hello')
|
||||
println(ret4)
|
||||
}
|
Loading…
Reference in New Issue