mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
generics: add more checks (#9539)
This commit is contained in:
parent
e438b158a6
commit
9ba8d02a5a
@ -437,41 +437,63 @@ pub fn (mut c Checker) infer_fn_types(f ast.Fn, mut call_expr ast.CallExpr) {
|
||||
}
|
||||
mut typ := ast.void_type
|
||||
for i, param in f.params {
|
||||
mut to_set := ast.void_type
|
||||
arg_i := if i != 0 && call_expr.is_method { i - 1 } else { i }
|
||||
if call_expr.args.len <= arg_i {
|
||||
break
|
||||
}
|
||||
arg := call_expr.args[arg_i]
|
||||
param_type_sym := c.table.get_type_symbol(param.typ)
|
||||
|
||||
if param.typ.has_flag(.generic) && param_type_sym.name == gt_name {
|
||||
typ = c.table.mktyp(arg.typ)
|
||||
to_set = c.table.mktyp(arg.typ)
|
||||
if arg.expr.is_auto_deref_var() {
|
||||
typ = typ.deref()
|
||||
to_set = to_set.deref()
|
||||
}
|
||||
// If the parent fn param is a generic too
|
||||
if to_set.has_flag(.generic) {
|
||||
to_set = c.unwrap_generic(to_set)
|
||||
}
|
||||
} else {
|
||||
arg_sym := c.table.get_type_symbol(arg.typ)
|
||||
if arg_sym.kind == .array && param_type_sym.kind == .array {
|
||||
mut arg_elem_info := arg_sym.info as ast.Array
|
||||
mut param_elem_info := param_type_sym.info as ast.Array
|
||||
mut arg_elem_sym := c.table.get_type_symbol(arg_elem_info.elem_type)
|
||||
mut param_elem_sym := c.table.get_type_symbol(param_elem_info.elem_type)
|
||||
for {
|
||||
if arg_elem_sym.kind == .array && param_elem_sym.kind == .array
|
||||
&& c.cur_fn.generic_params.filter(it.name == param_elem_sym.name).len == 0 {
|
||||
arg_elem_info = arg_elem_sym.info as ast.Array
|
||||
arg_elem_sym = c.table.get_type_symbol(arg_elem_info.elem_type)
|
||||
param_elem_info = param_elem_sym.info as ast.Array
|
||||
param_elem_sym = c.table.get_type_symbol(param_elem_info.elem_type)
|
||||
} else {
|
||||
to_set = arg_elem_info.elem_type
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if param.typ.has_flag(.variadic) {
|
||||
to_set = c.table.mktyp(arg.typ)
|
||||
}
|
||||
break
|
||||
}
|
||||
arg_sym := c.table.get_type_symbol(arg.typ)
|
||||
if arg_sym.kind == .array && param_type_sym.kind == .array {
|
||||
mut arg_elem_info := arg_sym.info as ast.Array
|
||||
mut param_elem_info := param_type_sym.info as ast.Array
|
||||
mut arg_elem_sym := c.table.get_type_symbol(arg_elem_info.elem_type)
|
||||
mut param_elem_sym := c.table.get_type_symbol(param_elem_info.elem_type)
|
||||
for {
|
||||
if arg_elem_sym.kind == .array && param_elem_sym.kind == .array
|
||||
&& c.cur_fn.generic_params.filter(it.name == param_elem_sym.name).len == 0 {
|
||||
arg_elem_info = arg_elem_sym.info as ast.Array
|
||||
arg_elem_sym = c.table.get_type_symbol(arg_elem_info.elem_type)
|
||||
param_elem_info = param_elem_sym.info as ast.Array
|
||||
param_elem_sym = c.table.get_type_symbol(param_elem_info.elem_type)
|
||||
} else {
|
||||
typ = arg_elem_info.elem_type
|
||||
break
|
||||
|
||||
if to_set != ast.void_type {
|
||||
if typ != ast.void_type {
|
||||
// try to promote
|
||||
// only numbers so we don't promote pointers
|
||||
if typ.is_number() && to_set.is_number() {
|
||||
promoted := c.promote_num(typ, to_set)
|
||||
if promoted != ast.void_type {
|
||||
to_set = promoted
|
||||
}
|
||||
}
|
||||
if !c.check_types(typ, to_set) {
|
||||
c.error('inferred generic type `$gt_name` is ambigous got `${c.table.get_type_symbol(to_set).name}`, expected `${c.table.get_type_symbol(typ).name}`',
|
||||
arg.pos)
|
||||
}
|
||||
}
|
||||
break
|
||||
} else if param.typ.has_flag(.variadic) {
|
||||
typ = c.table.mktyp(arg.typ)
|
||||
break
|
||||
typ = to_set
|
||||
}
|
||||
}
|
||||
if typ == ast.void_type {
|
||||
|
@ -1560,6 +1560,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) ast.Type {
|
||||
c.error('expected $nr_args arguments, but got $call_expr.args.len', unexpected_arguments_pos)
|
||||
return method.return_type
|
||||
}
|
||||
|
||||
// if method_name == 'clone' {
|
||||
// println('CLONE nr args=$method.args.len')
|
||||
// }
|
||||
@ -1672,6 +1673,10 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) ast.Type {
|
||||
if call_expr.generic_types.len > 0 && method.generic_names.len == 0 {
|
||||
c.error('a non generic function called like a generic one', call_expr.generic_list_pos)
|
||||
}
|
||||
if call_expr.generic_types.len > method.generic_names.len {
|
||||
c.error('too many generic parameters got $call_expr.generic_types.len, expected $method.generic_names.len',
|
||||
call_expr.generic_list_pos)
|
||||
}
|
||||
if method.generic_names.len > 0 {
|
||||
return call_expr.return_type
|
||||
}
|
||||
@ -2209,6 +2214,11 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) ast.Type {
|
||||
if call_expr.generic_types.len > 0 && f.generic_names.len == 0 {
|
||||
c.error('a non generic function called like a generic one', call_expr.generic_list_pos)
|
||||
}
|
||||
|
||||
if call_expr.generic_types.len > f.generic_names.len {
|
||||
c.error('too many generic parameters got $call_expr.generic_types.len, expected $f.generic_names.len',
|
||||
call_expr.generic_list_pos)
|
||||
}
|
||||
if f.generic_names.len > 0 {
|
||||
return call_expr.return_type
|
||||
}
|
||||
|
6
vlib/v/checker/tests/generics_too_many_parameters.out
Normal file
6
vlib/v/checker/tests/generics_too_many_parameters.out
Normal file
@ -0,0 +1,6 @@
|
||||
vlib/v/checker/tests/generics_too_many_parameters.vv:6:8: error: too many generic parameters got 5, expected 1
|
||||
4 |
|
||||
5 | fn main() {
|
||||
6 | foo<bool, int, bool, bool, int>(1)
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
7 | }
|
7
vlib/v/checker/tests/generics_too_many_parameters.vv
Normal file
7
vlib/v/checker/tests/generics_too_many_parameters.vv
Normal file
@ -0,0 +1,7 @@
|
||||
fn foo<T>(b T) {
|
||||
println(b)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo<bool, int, bool, bool, int>(1)
|
||||
}
|
6
vlib/v/checker/tests/generics_type_ambigous.out
Normal file
6
vlib/v/checker/tests/generics_type_ambigous.out
Normal file
@ -0,0 +1,6 @@
|
||||
vlib/v/checker/tests/generics_type_ambigous.vv:7:19: error: inferred generic type `B` is ambigous got `int`, expected `string`
|
||||
5 |
|
||||
6 | fn main() {
|
||||
7 | test(2, 2, "2", 2)
|
||||
| ^
|
||||
8 | }
|
8
vlib/v/checker/tests/generics_type_ambigous.vv
Normal file
8
vlib/v/checker/tests/generics_type_ambigous.vv
Normal file
@ -0,0 +1,8 @@
|
||||
fn test<T, B> (a T, b T, c B, d B) {
|
||||
println("$a $b $c $d")
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
test(2, 2, "2", 2)
|
||||
}
|
Loading…
Reference in New Issue
Block a user