Experimental Region Escape Analysis
Status: analysis-only North Star slice
Runtime effect: none
naux dev region <file.nx> emits a conservative heap escape plan for direct
text, bytes, list, map, and closure bindings. The analysis model also resolves
lexical captures for the internal anonymous-function AST, follows heap aliases,
and propagates escape lifetimes through captured and container-retained values.
The runtime still uses Rc; this report is evidence for a future
region-lowering pass, not a zero-GC claim.
With the experimental-regions Cargo feature, the report is lowered into
deterministic compiler metadata:
cargo run -p naux --features experimental-regions -- \
dev region naux-lang/examples/hello.nx
The [LOWERING PLAN] assigns only proven local allocations to region-local
storage and emits an inner-before-parent bulk-free schedule. Global,
escaping, and closure allocations carry an explicit Rc fallback reason.
Inference IDs are normalized to report-local ordinals, so identical AST input
produces identical metadata across invocations. The compiler-side
compile_script_with_region_plan API returns unchanged ordinary bytecode plus
the sidecar, and refuses it unless the canonical lowering certificate
revalidates against the escape report.
The feature also exposes observe-only run_vm_with_region_plan and
run_jit_with_region_plan entry points. They execute the unchanged current
backends and attach certificate-backed telemetry for region-local candidates,
Rc fallbacks by reason, free points, and would-be bulk-freed allocations.
VM/JIT value parity is regression-tested for both local and escaping cases.
These counters describe the admitted plan; they do not claim that bulk free is
executed yet.
Current proof boundary
An allocation is counted as bulk-free eligible only when:
- it is in a non-global function,
rite, oreachregion; - it is not returned from its function;
- it is not promoted through a non-lexical
if,loop,while, orunsafeboundary; - it is not reachable from an escaping closure or an escaping direct list/map binding.
A local closure no longer makes every allocation in its region ineligible.
Only its lexically resolved captures are retained. If that closure escapes,
the captured heap bindings are promoted to the closure’s target lifetime.
Propagation runs to a fixpoint, so escaping closure -> captured closure -> captured payload and escaping container -> retained payload receive one
consistent target. Parameter/local shadowing and overwritten aliases do not
retain stale heap bindings.
Assignments inside if, loop, while, and unsafe are conservatively
promoted to the parent region. That matches current Naux scope behavior:
these constructs do not create lexical variable scopes. rite, function
calls, and each iterations do.
Region lifetime comparison follows the parent chain. Creation order is not used, so one sibling region cannot incorrectly be treated as outliving another. Promoted bindings survive the source-region pop and are removed when their resolved target region exits.
Evidence
region::typestests cover parent-chain outlives checks, shadow restoration, and promoted-binding lifetime.region::analyzetests cover local heap eligibility, resolved return targets, nested returns, lexical capture/shadow resolution, heap aliases, container retention, and transitive closure escape fixpoints.region_escape_testsparses real Naux programs and checks escape decisions alongside VM/JIT value parity, including transitiveloop -> function -> callerpromotion.
Deliberately not implemented
- replacing
Rcallocation/reclamation; - user-facing anonymous-function parsing/execution and closure region polymorphism;
- nested anonymous allocation-site planning;
- executing the metadata as region create/free instructions or replacing the allocator;
- claiming runtime speedups.
The next admissible slice is feature-gated execution of region create/free for
the proven direct-allocation subset. It must keep Rc fallback for unsupported
shapes, retain interpreter/VM/JIT parity, and compare executed allocation/free
telemetry with the shadow plan before any runtime claim.