diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 36a5208502..5b470b8489 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -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 diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 3445ac4163..4b915da5d2 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) diff --git a/vlib/v/checker/tests/generics_fn_called_arg_mismatch.out b/vlib/v/checker/tests/generics_fn_called_arg_mismatch.out index 59fd5de7ca..f6913f5f42 100644 --- a/vlib/v/checker/tests/generics_fn_called_arg_mismatch.out +++ b/vlib/v/checker/tests/generics_fn_called_arg_mismatch.out @@ -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(1) | ^ 7 | foo(2.2) 8 | foo(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(1) 7 | foo(2.2) | ~~~ 8 | foo(true) 9 | foo('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(1) 7 | foo(2.2) 8 | foo(true) | ~~~~ 9 | foo('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(2.2) 8 | foo(true) 9 | foo('aaa') diff --git a/vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.out b/vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.out new file mode 100644 index 0000000000..cf4d3b25af --- /dev/null +++ b/vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.out @@ -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([1, 2, 3, 4]) + | ~~~~~~~~~~~~ + 16 | println(b) + 17 | } diff --git a/vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.vv b/vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.vv new file mode 100644 index 0000000000..e322a641f0 --- /dev/null +++ b/vlib/v/checker/tests/generics_fn_called_variadic_arg_mismatch.vv @@ -0,0 +1,17 @@ +fn max(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([1, 2, 3, 4]) + println(b) +}