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

checker: fix generics with multi nested generic method call (#15410)

This commit is contained in:
yuyi 2022-08-12 22:25:29 +08:00 committed by GitHub
parent b45da86688
commit 9f2651717a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 15 deletions

View File

@ -621,26 +621,39 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr
mut typ := ast.void_type
for i, param in func.params {
// resolve generic struct receiver
if node.is_method && param.typ.has_flag(.generic) {
sym := c.table.final_sym(node.receiver_type)
match sym.info {
ast.Struct, ast.Interface, ast.SumType {
if !isnil(c.table.cur_fn) && c.table.cur_fn.generic_names.len > 0 { // in generic fn
if gt_name in c.table.cur_fn.generic_names
&& c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
idx := c.table.cur_fn.generic_names.index(gt_name)
typ = c.table.cur_concrete_types[idx]
}
} else { // in non-generic fn
if node.is_method && i == 0 && param.typ.has_flag(.generic) {
sym := c.table.final_sym(node.left_type)
if node.left_type.has_flag(.generic) {
match sym.info {
ast.Struct, ast.Interface, ast.SumType {
receiver_generic_names := sym.info.generic_types.map(c.table.sym(it).name)
if gt_name in receiver_generic_names
&& sym.info.generic_types.len == sym.info.concrete_types.len {
if gt_name in receiver_generic_names {
idx := receiver_generic_names.index(gt_name)
typ = sym.info.concrete_types[idx]
typ = sym.info.generic_types[idx]
}
}
else {}
}
} else {
match sym.info {
ast.Struct, ast.Interface, ast.SumType {
if !isnil(c.table.cur_fn) && c.table.cur_fn.generic_names.len > 0 { // in generic fn
if gt_name in c.table.cur_fn.generic_names
&& c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
idx := c.table.cur_fn.generic_names.index(gt_name)
typ = c.table.cur_concrete_types[idx]
}
} else { // in non-generic fn
receiver_generic_names := sym.info.generic_types.map(c.table.sym(it).name)
if gt_name in receiver_generic_names
&& sym.info.generic_types.len == sym.info.concrete_types.len {
idx := receiver_generic_names.index(gt_name)
typ = sym.info.concrete_types[idx]
}
}
}
else {}
}
else {}
}
}
arg_i := if i != 0 && node.is_method { i - 1 } else { i }

View File

@ -0,0 +1,68 @@
struct Wrapper<S> {
mut:
calc Calc<S>
}
fn (mut w Wrapper<S>) next<T>(input T) f64 {
$if S is TypeA || S is TypeB {
$if T is f64 {
return w.calc.next(input)
} $else {
panic('"$T.name" is not supported')
return -1
}
return -1
} $else {
panic('"$S.name" is not supported')
return -1
}
}
struct Calc<S> {
mut:
typ S
}
struct TypeA {}
struct TypeB {}
fn (mut c Calc<S>) next<T>(input T) f64 {
$if S is TypeA || S is TypeB {
$if T is f64 {
return c.typ.next(input)
} $else {
panic('Unsupported type $T.name')
}
} $else {
panic('Unsupported type $S.name')
}
}
fn (mut t TypeA) next<T>(input T) f64 {
return 10
}
fn (mut t TypeB) next<T>(input T) f64 {
return 11
}
fn test_generics_with_multi_nested_generic_method_call() {
{
mut c := Wrapper<TypeA>{
calc: Calc<TypeA>{
typ: TypeA{}
}
}
assert c.next(100.0) == 10.0
}
{
mut c := Wrapper<TypeB>{
calc: Calc<TypeB>{
typ: TypeB{}
}
}
assert c.next(100.0) == 11.0
}
println('OK!!')
}