// Failable closure literals (ERR E5.1): a `closure(...)` literal may declare a
// failable return type — `-> (T, !)` / `-> !Named` — in both block and arrow
// body forms, and `raise` inside. Called directly through the bound local, the
// error channel is consumed by `catch` / `or`; passed as a `Closure(...)`
// parameter, it composes through the callee (here absorbed with `catch`).
// (A capturing closure into a bare `(T)->U` slot, and a failable closure into a
// non-failable slot, are rejected — see issue 0060 / the FFI-boundary rule.)

#import "modules/std.sx";

E :: error { Neg }

runwith :: (cb: Closure(i64) -> (i64, !E), n: i64) -> i64 { return cb(n) catch (e) -1; }

main :: () -> i32 {
    // block-body and arrow-body failable closures, called directly
    m := closure((x: i64) -> (i64, !E) { if x < 0 { raise error.Neg; } return x * 2; });
    n := closure((x: i64) -> (i64, !E) => x + 1);
    print("{} {} {} {}\n", m(5) catch (e) 0, m(-1) catch (e) 99, m(-1) or 7, n(40) catch (e) 0); // 10 99 7 41

    // failable closure passed as a Closure(...) parameter
    print("param ok={} err={}\n", runwith(m, 5), runwith(m, -1));   // 10  -1
    return 0;
}
