← Back to AILP Home

Pass and Fail

Every ordinary body-bearing Nitpick function returns Result<T> implicitly, where T is the declared return type. Source code writes the declared success type; the compiler wraps the function ABI in Result<T>.

func:add = int32(int32:a, int32:b) {
    pass a + b;
};

func:checked_div = int32(int32:a, int32:b) {
    if (b == 0i32) {
        fail 1i32;
    };
    pass a / b;
};

pass value

pass value returns a successful Result<T> from the current function. The expression must match the function's declared success type.

func:forty_two = int32() {
    pass 42i32;
};

fail code

fail code returns a failed Result<T> from the current function. The source-facing error-code path used by .error and contextual catch is currently int32.

func:bad = int32() {
    fail 7i32;
};

Implementation note: the IR layout carries the error through the internal Result error field, but source-level handlers see an integer error code.

Result<NIL>

Functions declared as NIL still return Result<NIL> implicitly. Successful void-shaped functions must pass NIL.

func:log_ready = NIL() {
    println("ready");
    pass NIL;
};

fail code is also valid in a NIL function because the outer shape is still Result<NIL>.

main and failsafe

main and failsafe are special process-boundary functions. They use exit, not pass or fail.

func:main = int32() {
    exit 0;
};

func:failsafe = int32(tbb32:err) {
    exit 1;
};

Nested calls preserve their own Result state

No Result operator in v0.33.x introduces hidden propagation. If a nested call can fail, the caller must choose an explicit handling surface at that call site or at a later bound Result value.

func:leaf = int32() {
    fail 9i32;
};

func:outer = int32() {
    int32:x = leaf() ? 100i32;
    pass x + 1i32;
};

Here leaf() does not jump out of outer; the fallback is explicit.