1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check sumtype argument mismatch in generic methods (fix #16340 part2) (#16403)

This commit is contained in:
yuyi 2022-11-13 16:58:53 +08:00 committed by GitHub
parent e8e75251b4
commit f31a3b4250
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 92 additions and 17 deletions

View File

@ -267,7 +267,10 @@ pub fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type,
if got_typ_sym.symbol_name_except_generic() == expected_typ_sym.symbol_name_except_generic() {
// Check if we are making a comparison between two different types of
// the same type like `Type<int> and &Type<>`
if (got.is_ptr() != expected.is_ptr()) || !c.check_same_module(got, expected) {
if (got.is_ptr() != expected.is_ptr())
|| !c.check_same_module(got, expected)
|| (!got.is_ptr() && !expected.is_ptr()
&& got_typ_sym.name != expected_typ_sym.name) {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
return error('cannot use `$got_typ_str` as `$expected_typ_str`')
}

View File

@ -1428,18 +1428,21 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
rec_sym := c.table.final_sym(node.left_type)
rec_is_generic := left_type.has_flag(.generic)
mut rec_concrete_types := []ast.Type{}
if rec_sym.info is ast.Struct {
rec_concrete_types = rec_sym.info.concrete_types.clone()
if rec_is_generic && node.concrete_types.len == 0
&& method.generic_names.len == rec_sym.info.generic_types.len {
node.concrete_types = rec_sym.info.generic_types
} else if !rec_is_generic && rec_sym.info.concrete_types.len > 0
&& node.concrete_types.len > 0
&& rec_sym.info.concrete_types.len + node.concrete_types.len == method.generic_names.len {
t_concrete_types := node.concrete_types.clone()
node.concrete_types = rec_sym.info.concrete_types
node.concrete_types << t_concrete_types
match rec_sym.info {
ast.Struct, ast.SumType, ast.Interface {
rec_concrete_types = rec_sym.info.concrete_types.clone()
if rec_is_generic && node.concrete_types.len == 0
&& method.generic_names.len == rec_sym.info.generic_types.len {
node.concrete_types = rec_sym.info.generic_types
} else if !rec_is_generic && rec_sym.info.concrete_types.len > 0
&& node.concrete_types.len > 0
&& rec_sym.info.concrete_types.len + node.concrete_types.len == method.generic_names.len {
t_concrete_types := node.concrete_types.clone()
node.concrete_types = rec_sym.info.concrete_types
node.concrete_types << t_concrete_types
}
}
else {}
}
mut concrete_types := []ast.Type{}
for concrete_type in node.concrete_types {
@ -1644,12 +1647,16 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
if got_arg_typ.has_flag(.generic) {
if got_utyp := c.table.resolve_generic_to_concrete(got_arg_typ, method.generic_names,
method_concrete_types)
{
got_arg_typ = got_utyp
if c.table.cur_fn != unsafe { nil } && c.table.cur_concrete_types.len > 0 {
got_arg_typ = c.unwrap_generic(got_arg_typ)
} else {
continue
if got_utyp := c.table.resolve_generic_to_concrete(got_arg_typ,
method.generic_names, method_concrete_types)
{
got_arg_typ = got_utyp
} else {
continue
}
}
}
}

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/generics_method_sumtype_arg_mismatch.vv:56:13: error: cannot use `Maybe<string>` as `Maybe<int>` in argument 1 to `Maybe<int>.or`
54 | b := some('abc')
55 |
56 | c := a.@or(b)
| ^
57 | println(c)
58 | }

View File

@ -0,0 +1,58 @@
module main
struct None {}
pub type Maybe<T> = None | T
pub fn (m Maybe<T>) str<T>() string {
return if m is T {
x := m as T
'Some($x)'
} else {
'Noth'
}
}
pub fn some<T>(v T) Maybe<T> {
return Maybe<T>(v)
}
pub fn noth<T>() Maybe<T> {
return Maybe<T>(None{})
}
pub fn (m Maybe<T>) is_some<T>() bool {
return match m {
None { false }
T { true }
}
}
pub fn (m Maybe<T>) is_noth<T>() bool {
return match m {
None { true }
T { false }
}
}
pub fn (m Maybe<T>) @or<T>(m2 Maybe<T>) Maybe<T> {
return match m {
None {
match m2 {
None { None{} }
T { m2 }
}
}
T {
m
}
}
}
fn main() {
a := some(123)
b := some('abc')
c := a.@or(b)
println(c)
}