checker: check type mismatch in args of generics method calls (fix #13193) (#13196)

pull/13200/head
yuyi 2022-01-17 22:48:59 +08:00 committed by GitHub
parent 835484a953
commit 39f80840d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 5 deletions

View File

@ -1212,7 +1212,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
exp_arg_sym := c.table.sym(exp_arg_typ)
c.expected_type = exp_arg_typ
got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
mut got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
node.args[i].typ = got_arg_typ
if no_type_promotion {
if got_arg_typ != exp_arg_typ {
@ -1243,10 +1243,29 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
continue
}
if exp_arg_typ.has_flag(.generic) {
continue
if concrete_types.len == 0 {
continue
}
if exp_utyp := c.table.resolve_generic_to_concrete(exp_arg_typ, method.generic_names,
concrete_types)
{
exp_arg_typ = exp_utyp
} else {
continue
}
if got_arg_typ.has_flag(.generic) {
if got_utyp := c.table.resolve_generic_to_concrete(got_arg_typ, method.generic_names,
concrete_types)
{
got_arg_typ = got_utyp
} else {
continue
}
}
}
c.check_expected_call_arg(got_arg_typ, c.unwrap_generic(exp_arg_typ), node.language,
arg) or {
c.check_expected_call_arg(got_arg_typ, exp_arg_typ, node.language, arg) or {
// str method, allow type with str method if fn arg is string
// Passing an int or a string array produces a c error here
// Deleting this condition results in propper V error messages

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/generics_method_called_arg_mismatch.vv:3:15: error: cannot use `Foo` as `Bar` in argument 1 to `Obj.set`
1 | fn main() {
2 | mut obj := Obj{}
3 | obj.set<Bar>(Foo{})
| ~~~~~
4 | }
5 |

View File

@ -0,0 +1,14 @@
fn main() {
mut obj := Obj{}
obj.set<Bar>(Foo{})
}
struct Foo {}
struct Bar {
Foo
}
struct Obj {}
fn (mut o Obj) set<T>(val T) {}

View File

@ -15,7 +15,7 @@ fn (ng NestedGeneric) nested_test<T>(mut app T) {
fn method_test<T>(mut app T) int {
ng := NestedGeneric{}
ng.nested_test<T>(app)
ng.nested_test<T>(mut app)
return 22
}