checker: check generics variadic arg mismatch (#9700)
parent
21e52ee003
commit
c3ccb58450
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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 | }
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue