← Back to AILP Home

Borrows and async

Nitpick's async model in v0.25.x is synchronous-equivalent: await runs the async body to completion before continuing. From the borrow checker's point of view, this means each async call is a fresh stack frame whose loans live for the duration of the call only.

Borrows inside an async body

async func: read_pair = int32($$i Pair:p) {
    pass p.a + p.b;
};

func:main = int32() {
    Pair:pair = Pair{a: 10, b: 20};
    int32:r = await read_pair(pair);
    exit r;                // 30
};

The $$i p loan exists only while read_pair runs. After await returns, pair is unreserved.

Repeated awaits on the same host

Because the loan is released on each await completion, you can call the same async function multiple times on the same input:

async func: bump = int32(int32:n) { pass n + 1; };

func:main = int32() {
    int32:x = 10;
    int32:a = await bump(x);
    int32:b = await bump(x);
    int32:c = await bump(x);
    int32:d = await bump(x);
    exit a + b + c + d + x;     // 11+11+11+11+10 = 54
};

(K test 145.)

Holding a borrow across an await

This is rejected:

$$m int32:r = pair.a;
int32:v = await bump(pair.a);   // ARIA-023: can't take new borrow while r live

The $$m r loan is still in scope when the call wants its own loan on pair.a. Release r (let it leave scope) before the await, or call bump with a different host.

What does not exist yet

When real concurrency lands (post v0.26.x roadmap), these rules will get strictly tighter rather than looser.