From 3bb1c3f9305535611cbdca0bf7444a4e0ffa4708 Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 12 Nov 2021 20:29:01 +0800 Subject: [PATCH] checker, cgen: fix for in iterator of generic struct (#12441) --- vlib/v/checker/checker.v | 2 +- vlib/v/gen/c/cgen.v | 11 +++++- .../for_in_iterator_of_generic_struct_test.v | 39 +++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/for_in_iterator_of_generic_struct_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 7cd6b6680c..25f778e1f5 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4816,7 +4816,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { sym := c.table.get_final_type_symbol(typ) if sym.kind == .struct_ { // iterators - next_fn := sym.find_method('next') or { + next_fn := sym.find_method_with_generic_parent('next') or { c.error('a struct must have a `next()` method to be an iterator', node.cond.position()) return } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index a4bbaa909a..9f22cb465a 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2145,7 +2145,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { } } else if node.kind == .struct_ { cond_type_sym := g.table.get_type_symbol(node.cond_type) - next_fn := cond_type_sym.find_method('next') or { + next_fn := cond_type_sym.find_method_with_generic_parent('next') or { verror('`next` method not found') return } @@ -2162,7 +2162,14 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { t_var := g.new_tmp_var() receiver_typ := next_fn.params[0].typ receiver_styp := g.typ(receiver_typ) - fn_name := receiver_styp.replace_each(['*', '', '.', '__']) + '_next' + mut fn_name := receiver_styp.replace_each(['*', '', '.', '__']) + '_next' + receiver_sym := g.table.get_type_symbol(receiver_typ) + if receiver_sym.info is ast.Struct { + if receiver_sym.info.concrete_types.len > 0 { + fn_name = g.generic_fn_name(receiver_sym.info.concrete_types, fn_name, + false) + } + } g.write('\t${g.typ(ret_typ)} $t_var = ${fn_name}(') if !node.cond_type.is_ptr() && receiver_typ.is_ptr() { g.write('&') diff --git a/vlib/v/tests/for_in_iterator_of_generic_struct_test.v b/vlib/v/tests/for_in_iterator_of_generic_struct_test.v new file mode 100644 index 0000000000..c605370ec1 --- /dev/null +++ b/vlib/v/tests/for_in_iterator_of_generic_struct_test.v @@ -0,0 +1,39 @@ +struct Split { + arr []T + pred fn (T) bool +mut: + idx int +} + +fn (mut iter Split) next() ?[]T { + start := iter.idx + for iter.idx < iter.arr.len { + if iter.pred(iter.arr[iter.idx]) { + iter.idx++ + return iter.arr[start..iter.idx] + } + iter.idx++ + } + return none +} + +fn split(arr []T, pred fn (T) bool) Split { + return Split{arr, pred, 0} +} + +fn test_for_in_iterator_of_generic_struct() { + items := [0, 1, 2, 3, 4, 5, 6, 7, 8] + mut iter := split(items, fn (item int) bool { + return item % 3 == 0 + }) + iter.next() or {} + mut ret_list := [][]int{} + for item in iter { + dump(item) + ret_list << item + } + println(ret_list) + assert ret_list.len == 2 + assert ret_list[0] == [1, 2, 3] + assert ret_list[1] == [4, 5, 6] +}