← board

Auto stackless/stackful backend selection

Core (stackless-or-error) is buildable now. Only the cost-warning upscale on ESP/32-bit is gated on feature-stackful-coro-port (soft dependency, in body).

Motivation

Today bare ; generator; / ; async; always use the stackful backend; the programmer forces the other with an explicit stackful; / stackless; directive (see dialect/generators.md). That pushes a memory/portability decision onto every call site. The compiler can make it: prefer the RAM-cheap stackless backend, fall back to stackful only when a language feature in the body requires it — and say so.

See the design record in developer/concurrency-memory-model.md.

Rule (target-aware)

  1. Eligible → stackless. Eligible = structured suspension points only (yield/await at top level or inside for/while/if; never in case/repeat/with, a condition, a for bound, or try..except) and no managed local (string / dynamic array / record) live across a suspension.
  2. Ineligible → stackful, but only on a target that has the stackful backend. On a target without it, hard error naming the feature that forced the upscale.
  3. Where stackful exists, the upscale is a cost warning, not silent:
    warning: async Foo upscaled to stackful (managed local 's' lives across await)
             — costs a ~N-byte heap stack per live instance; ESP RAM is tight
    
    Name the trigger + line + the per-instance stack cost.

On a no-stackful target this is effectively "stackless or a clear error" — the correct contract for a no-MMU part (ESP). Explicit stackful; / stackless; always override auto.

Dependencies / sequencing

Acceptance