Lyricdev
GitHub

LYR-SEM0163

a loop's head takes 'try?', 'try!' or a catching form

error · spec 07-statements

The source of a for loop is marked try?, try! or with the catching form of try instead of the plain try.

Explanation

A loop's head takes the plain try mark only: it covers the source and every next() the loop makes. try? or try! would take the value of the head, and the pulls at every pass would stand outside it, uncaught.

Write for (x in try source) and let the error propagate, or put the loop in a try { … } catch block to handle what it throws.

Wrong

class Fail :: [Error] {
    at: int,

    fn message(): string {
        return f"failed at {this.at}";
    }
}

struct Lines :: [Iterator] {
    type Item = int;
    type Error = Fail;
    var i: int,
    stop: int,

    mut fn next(): ?int throws Fail {
        if (this.i == this.stop) { throw Fail { at = this.i }; }
        this.i = this.i + 1;
        return this.i;
    }
}

fn main(): void {
    var s = 0;
    for (x in try? Lines { i = 0, stop = 3 }) { s = s + x; }
    assert(s >= 0);
}
class Fail :: [Error] {
    at: int,

    fn message(): string {
        return f"failed at {this.at}";
    }
}

struct Lines :: [Iterator] {
    type Item = int;
    type Error = Fail;
    var i: int,
    stop: int,

    mut fn next(): ?int throws Fail {
        if (this.i == this.stop) { throw Fail { at = this.i }; }
        this.i = this.i + 1;
        return this.i;
    }
}

fn main(): void {
    var s = 0;
    try {
        for (x in Lines { i = 0, stop = 3 }) { s = s + x; }
    } catch (e: Fail) {
        s = 0 - e.at;
    }
    assert(s >= 0);
}