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:
parent
b45da86688
commit
9f2651717a
@ -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 }
|
||||
|
@ -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!!')
|
||||
}
|
Loading…
Reference in New Issue
Block a user