From 8e99a018dff2c7e7323203681a231e5fe6a9e3b8 Mon Sep 17 00:00:00 2001 From: yuyi Date: Mon, 19 Jul 2021 18:29:46 +0800 Subject: [PATCH] checker, cgen: fix generics interface method (#10858) --- vlib/v/checker/checker.v | 9 ++--- vlib/v/gen/c/fn.v | 18 +++++++++- vlib/v/tests/generics_interface_method_test.v | 35 +++++++++++++++++++ 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 vlib/v/tests/generics_interface_method_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 48a25c9165..13495494a4 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1470,8 +1470,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { // `array << elm` c.check_expr_opt_call(node.right, right_type) node.auto_locked, _ = c.fail_if_immutable(node.left) - left_value_type := c.table.value_type(left_type) - left_value_sym := c.table.get_type_symbol(left_value_type) + left_value_type := c.table.value_type(c.unwrap_generic(left_type)) + left_value_sym := c.table.get_type_symbol(c.unwrap_generic(left_value_type)) if left_value_sym.kind == .interface_ { if right_final.kind != .array { // []Animal << Cat @@ -1489,8 +1489,9 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { return ast.void_type } // []T << T or []T << []T - if c.check_types(right_type, left_value_type) - || c.check_types(right_type, left_type) { + unwrapped_right_type := c.unwrap_generic(right_type) + if c.check_types(unwrapped_right_type, left_value_type) + || c.check_types(unwrapped_right_type, left_type) { return ast.void_type } c.error('cannot append `$right_sym.name` to `$left_sym.name`', right_pos) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 73c509ef51..a4a33714a7 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -548,7 +548,23 @@ fn (mut g Gen) method_call(node ast.CallExpr) { if node.receiver_type == 0 { g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos) } - unwrapped_rec_type := g.unwrap_generic(node.receiver_type) + mut unwrapped_rec_type := node.receiver_type + if g.table.cur_fn.generic_names.len > 0 { // in generic fn + unwrapped_rec_type = g.unwrap_generic(node.receiver_type) + } else { // in non-generic fn + sym := g.table.get_type_symbol(node.receiver_type) + match sym.info { + ast.Struct, ast.Interface, ast.SumType { + generic_names := sym.info.generic_types.map(g.table.get_type_symbol(it).name) + if utyp := g.table.resolve_generic_to_concrete(node.receiver_type, generic_names, + sym.info.concrete_types) + { + unwrapped_rec_type = utyp + } + } + else {} + } + } typ_sym := g.table.get_type_symbol(unwrapped_rec_type) rec_cc_type := g.cc_type(unwrapped_rec_type, false) mut receiver_type_name := util.no_dots(rec_cc_type) diff --git a/vlib/v/tests/generics_interface_method_test.v b/vlib/v/tests/generics_interface_method_test.v new file mode 100644 index 0000000000..bf31883393 --- /dev/null +++ b/vlib/v/tests/generics_interface_method_test.v @@ -0,0 +1,35 @@ +interface Iter { + next() ?T +} + +fn (mut it Iter) collect() []T { + mut data := []T{} + for { + val := it.next() or { break } + data << val + } + return data +} + +struct ArrayIter { + data []T +mut: + index int +} + +fn (mut it ArrayIter) next() ?T { + if it.index >= it.data.len { + return none + } + defer { + it.index++ + } + return it.data[it.index] +} + +fn test_generics_interface_method() { + mut iter := Iter(ArrayIter{ + data: [1, 2, 3] + }) + assert iter.collect() == [1, 2, 3] +}