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
|
mut typ := ast.void_type
|
||||||
for i, param in func.params {
|
for i, param in func.params {
|
||||||
// resolve generic struct receiver
|
// resolve generic struct receiver
|
||||||
if node.is_method && param.typ.has_flag(.generic) {
|
if node.is_method && i == 0 && param.typ.has_flag(.generic) {
|
||||||
sym := c.table.final_sym(node.receiver_type)
|
sym := c.table.final_sym(node.left_type)
|
||||||
match sym.info {
|
if node.left_type.has_flag(.generic) {
|
||||||
ast.Struct, ast.Interface, ast.SumType {
|
match sym.info {
|
||||||
if !isnil(c.table.cur_fn) && c.table.cur_fn.generic_names.len > 0 { // in generic fn
|
ast.Struct, ast.Interface, ast.SumType {
|
||||||
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)
|
receiver_generic_names := sym.info.generic_types.map(c.table.sym(it).name)
|
||||||
if gt_name in receiver_generic_names
|
if gt_name in receiver_generic_names {
|
||||||
&& sym.info.generic_types.len == sym.info.concrete_types.len {
|
|
||||||
idx := receiver_generic_names.index(gt_name)
|
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 }
|
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…
x
Reference in New Issue
Block a user