checker: check generics variadic arg mismatch (#9700)

pull/9724/head
yuyi 2021-04-13 08:06:24 +08:00 committed by GitHub
parent 21e52ee003
commit c3ccb58450
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 32 deletions

View File

@ -970,14 +970,14 @@ pub fn (mut t Table) resolve_generic_by_names(generic_type Type, generic_names [
}
if typ := t.resolve_generic_by_names(elem_type, generic_names, generic_types) {
idx := t.find_or_register_array_with_dims(typ, dims)
array_typ := new_type(idx)
array_typ := new_type(idx).derive(generic_type).clear_flag(.generic)
return array_typ
}
} else if sym.kind == .chan {
info := sym.info as Chan
if typ := t.resolve_generic_by_names(info.elem_type, generic_names, generic_types) {
idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
chan_typ := new_type(idx)
chan_typ := new_type(idx).derive(generic_type).clear_flag(.generic)
return chan_typ
}
} else if mut sym.info is MultiReturn {
@ -993,7 +993,7 @@ pub fn (mut t Table) resolve_generic_by_names(generic_type Type, generic_names [
}
if type_changed {
idx := t.find_or_register_multi_return(types)
typ := new_type(idx)
typ := new_type(idx).derive(generic_type).clear_flag(.generic)
return typ
}
} else if mut sym.info is Map {
@ -1010,7 +1010,7 @@ pub fn (mut t Table) resolve_generic_by_names(generic_type Type, generic_names [
}
if type_changed {
idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
return new_type(idx)
return new_type(idx).derive(generic_type).clear_flag(.generic)
}
}
return none
@ -1041,13 +1041,13 @@ pub fn (mut t Table) resolve_generic_by_types(generic_type Type, from_types []Ty
}
if typ := t.resolve_generic_by_types(elem_type, from_types, to_types) {
idx := t.find_or_register_array_with_dims(typ, dims)
return new_type(idx)
return new_type(idx).derive(generic_type).clear_flag(.generic)
}
} else if sym.kind == .chan {
info := sym.info as Chan
if typ := t.resolve_generic_by_types(info.elem_type, from_types, to_types) {
idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
return new_type(idx)
return new_type(idx).derive(generic_type).clear_flag(.generic)
}
} else if mut sym.info is MultiReturn {
mut types := []Type{}
@ -1062,7 +1062,7 @@ pub fn (mut t Table) resolve_generic_by_types(generic_type Type, from_types []Ty
}
if type_changed {
idx := t.find_or_register_multi_return(types)
return new_type(idx)
return new_type(idx).derive(generic_type).clear_flag(.generic)
}
} else if mut sym.info is Map {
mut type_changed := false
@ -1078,7 +1078,7 @@ pub fn (mut t Table) resolve_generic_by_types(generic_type Type, from_types []Ty
}
if type_changed {
idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
return new_type(idx)
return new_type(idx).derive(generic_type).clear_flag(.generic)
}
}
return none

View File

@ -2207,26 +2207,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
continue
}
if func.generic_names.len > 0 {
if param.typ.has_flag(.generic)
&& func.generic_names.len == call_expr.generic_types.len {
if unwrap_typ := c.table.resolve_generic_by_names(param.typ, func.generic_names,
call_expr.generic_types)
{
if (unwrap_typ.idx() == typ.idx())
|| (unwrap_typ.is_int() && typ.is_int())
|| (unwrap_typ.is_float() && typ.is_float()) {
continue
}
expected_sym := c.table.get_type_symbol(unwrap_typ)
got_sym := c.table.get_type_symbol(typ)
c.error('argument ${i + 1} got `$got_sym.name`, expected `$expected_sym.name`',
call_arg.pos)
} else {
continue
}
} else {
continue
}
continue
}
c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos)
}
@ -2243,6 +2224,27 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
// no type arguments given in call, attempt implicit instantiation
c.infer_fn_types(func, mut call_expr)
}
if func.generic_names.len > 0 {
for i, call_arg in call_expr.args {
param := if func.is_variadic && i >= func.params.len - 1 {
func.params[func.params.len - 1]
} else {
func.params[i]
}
c.expected_type = param.typ
typ := c.check_expr_opt_call(call_arg.expr, c.expr(call_arg.expr))
if param.typ.has_flag(.generic) && func.generic_names.len == call_expr.generic_types.len {
if unwrap_typ := c.table.resolve_generic_by_names(param.typ, func.generic_names,
call_expr.generic_types)
{
c.check_expected_call_arg(typ, unwrap_typ, call_expr.language) or {
c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos)
}
}
}
}
}
if call_expr.generic_types.len > 0 && func.return_type != 0 {
if typ := c.table.resolve_generic_by_names(func.return_type, func.generic_names,
call_expr.generic_types)

View File

@ -1,25 +1,25 @@
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:6:15: error: argument 1 got `int literal`, expected `bool`
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:6:15: error: cannot use `int literal` as `bool` in argument 1 to `foo`
4 |
5 | fn main() {
6 | foo<bool>(1)
| ^
7 | foo<bool>(2.2)
8 | foo<string>(true)
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:7:15: error: argument 1 got `float literal`, expected `bool`
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:7:15: error: cannot use `float literal` as `bool` in argument 1 to `foo`
5 | fn main() {
6 | foo<bool>(1)
7 | foo<bool>(2.2)
| ~~~
8 | foo<string>(true)
9 | foo<int>('aaa')
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:8:17: error: argument 1 got `bool`, expected `string`
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:8:17: error: cannot use `bool` as `string` in argument 1 to `foo`
6 | foo<bool>(1)
7 | foo<bool>(2.2)
8 | foo<string>(true)
| ~~~~
9 | foo<int>('aaa')
10 | }
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:9:14: error: argument 1 got `string`, expected `int`
vlib/v/checker/tests/generics_fn_called_arg_mismatch.vv:9:14: error: cannot use `string` as `int` in argument 1 to `foo`
7 | foo<bool>(2.2)
8 | foo<string>(true)
9 | foo<int>('aaa')

View File

@ -0,0 +1,14 @@
vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.vv:12:11: error: cannot use `[]int` as `int` in argument 1 to `max`
10 |
11 | fn main() {
12 | a := max([1, 2, 3, 4])
| ~~~~~~~~~~~~
13 | println(a)
14 |
vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.vv:15:16: error: cannot use `[]int` as `int` in argument 1 to `max`
13 | println(a)
14 |
15 | b := max<int>([1, 2, 3, 4])
| ~~~~~~~~~~~~
16 | println(b)
17 | }

View File

@ -0,0 +1,17 @@
fn max<T>(a ...T) T {
mut max := a[0]
for item in a[1..] {
if max < item {
max = item
}
}
return max
}
fn main() {
a := max([1, 2, 3, 4])
println(a)
b := max<int>([1, 2, 3, 4])
println(b)
}