checker, cgen: fix for in iterator of generic struct (#12441)

pull/12447/head
yuyi 2021-11-12 20:29:01 +08:00 committed by GitHub
parent 50a608aab3
commit 3bb1c3f930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 3 deletions

View File

@ -4816,7 +4816,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
sym := c.table.get_final_type_symbol(typ) sym := c.table.get_final_type_symbol(typ)
if sym.kind == .struct_ { if sym.kind == .struct_ {
// iterators // 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()) c.error('a struct must have a `next()` method to be an iterator', node.cond.position())
return return
} }

View File

@ -2145,7 +2145,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
} }
} else if node.kind == .struct_ { } else if node.kind == .struct_ {
cond_type_sym := g.table.get_type_symbol(node.cond_type) 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') verror('`next` method not found')
return return
} }
@ -2162,7 +2162,14 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
t_var := g.new_tmp_var() t_var := g.new_tmp_var()
receiver_typ := next_fn.params[0].typ receiver_typ := next_fn.params[0].typ
receiver_styp := g.typ(receiver_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}(') g.write('\t${g.typ(ret_typ)} $t_var = ${fn_name}(')
if !node.cond_type.is_ptr() && receiver_typ.is_ptr() { if !node.cond_type.is_ptr() && receiver_typ.is_ptr() {
g.write('&') g.write('&')

View File

@ -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]
}