diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index bdfbacb33e..c1d432e252 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -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 } diff --git a/vlib/v/tests/generics_with_multi_nested_generic_method_call_test.v b/vlib/v/tests/generics_with_multi_nested_generic_method_call_test.v new file mode 100644 index 0000000000..0808ee4349 --- /dev/null +++ b/vlib/v/tests/generics_with_multi_nested_generic_method_call_test.v @@ -0,0 +1,68 @@ +struct Wrapper { +mut: + calc Calc +} + +fn (mut w Wrapper) next(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 { +mut: + typ S +} + +struct TypeA {} + +struct TypeB {} + +fn (mut c Calc) next(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(input T) f64 { + return 10 +} + +fn (mut t TypeB) next(input T) f64 { + return 11 +} + +fn test_generics_with_multi_nested_generic_method_call() { + { + mut c := Wrapper{ + calc: Calc{ + typ: TypeA{} + } + } + assert c.next(100.0) == 10.0 + } + { + mut c := Wrapper{ + calc: Calc{ + typ: TypeB{} + } + } + assert c.next(100.0) == 11.0 + } + println('OK!!') +}