Lyricdev
GitHub

LYR-SEM0162

a second loop over the same iterator

warning · spec 07-statements · lint iterator-reused, group correctness, warn unless said

A for loop walks a local or parameter that an earlier loop in the same or an enclosing block already walked, with no assignment to it between, and the binding's iterator may be shared (a class, or a type parameter a class may answer).

Explanation

An iterator is not reset by a loop. When the binding holds an object that iter() hands back as itself, the second loop goes on where the first stopped, usually at the end, and runs no pass without a word. A struct iterator is copied per loop, and an Iterable that makes a new iterator each time starts fresh; neither warns.

Take a fresh iterator for each loop, or walk it once.

Wrong

class Ticker :: [Iterator] {
    type Item = int;
    var n: int,

    mut fn next(): ?int {
        if (this.n == 0) { return null; }
        this.n = this.n - 1;
        return this.n;
    }
}

fn main(): void {
    let t = Ticker { n = 3 };
    var sum = 0;
    for (x in t) { sum = sum + x; }
    for (x in t) { sum = sum + x; }
    assert(sum == 3);
}
class Ticker :: [Iterator] {
    type Item = int;
    var n: int,

    mut fn next(): ?int {
        if (this.n == 0) { return null; }
        this.n = this.n - 1;
        return this.n;
    }
}

fn main(): void {
    var sum = 0;
    for (x in Ticker { n = 3 }) { sum = sum + x; }
    for (x in Ticker { n = 3 }) { sum = sum + x; }
    assert(sum == 6);
}