language

Multi-Value Returns

Functions return whole structs through WebAssembly’s native multi-value feature — at any size, with no hidden pointer plumbing.

When a function returns a struct, rasc emits a wasm signature whose results are the struct’s fields, flattened in declaration order — its leaves, in the sense of Structs & Refs. A Vec2-returning function is (func (param ...) (result f32 f32)); a Transform-returning function carries four results. The caller receives the leaves directly on the operand stack — no allocation, no scratch memory, no copy through linear memory.

multivalue.as
struct Vec2 {
    x: f32 = 0;
    y: f32 = 0;
    constructor(x: f32, y: f32) { this.x = x; this.y = y; }
}

function polar(r: f32, theta: f32): Vec2 {
    // (result f32 f32) — leaves on the stack, no out-pointer
    return Vec2(r * Mathf.cos(theta), r * Mathf.sin(theta));
}

export function demo(): f32 {
    // Chained value expressions stay on the stack end to end:
    let p = polar(2.0, 0.5);
    let speed = polar(1.0, 0.25).x;   // field of a call result: rvalue spill
    return p.x + speed;
}

No size cap

There is deliberately no leaf-count ceiling. Early designs capped multi-value at four leaves with an out-pointer fallback; the landed representation handles every size uniformly instead, because two conventions means two code paths to verify and a performance cliff to document. Larger structs return more results. Both production engines — WAMR and V8 — execute the fixtures bit-identically.

Toolchain interplay

Multi-value is a wasm feature with uneven toolchain support, so rasc is conservative at the edges:

Under the hood

Flattening runs in the schema’s normative order — declaration order, depth-first, with FixedArray elements expanding in index order — so a Transform is p.x, p.y, q.c, q.s everywhere: params, returns, locals, and the debugger’s locals map. A field access on a bare call result (add(a, b).y) spills the returned leaves to locals and reads the one it needs; assignments to call results are compile errors, since the result is a temporary copy.