Skip to content

Commit

Permalink
checker, cgen: fix for in iterator of generic struct (#12441)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 committed Nov 12, 2021
1 parent 50a608a commit 3bb1c3f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
2 changes: 1 addition & 1 deletion vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
11 changes: 9 additions & 2 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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('&')
Expand Down
39 changes: 39 additions & 0 deletions vlib/v/tests/for_in_iterator_of_generic_struct_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
struct Split<T> {
arr []T
pred fn (T) bool
mut:
idx int
}

fn (mut iter Split<T>) 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<T>(arr []T, pred fn (T) bool) Split<T> {
return Split<T>{arr, pred, 0}
}

fn test_for_in_iterator_of_generic_struct() {
items := [0, 1, 2, 3, 4, 5, 6, 7, 8]
mut iter := split<int>(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]
}

0 comments on commit 3bb1c3f

Please sign in to comment.