Section 02: AST/IR Immutability Contract
Status: Not Started
Goal: Make the existing AST/IR immutability invariant an explicit, auditable rule. Research confirmed that the enforcement already exists via Rust’s type system (&ExprArena, &Pool at all downstream boundaries). This section documents what’s true, not changes what exists.
Success Criteria:
-
impl-hygiene.md§Phase Boundaries contains an explicit immutability rule — satisfies mission criterion “AST/IR immutability explicitly documented” -
parse.mdreferences the immutability enforcement mechanism (&ExprArenaat phase boundaries) - No regression —
timeout 150 ./test-all.shgreen
Context: Research confirmed the codebase already enforces immutability correctly:
&ExprArena(immutable) at all downstream boundaries — canonicalization receiveslower(src: &ExprArena, ...)atori_canon/src/lower/mod.rs:42&mut ExprArenaappears only inori_parse/src/incremental/copier/(AST copying for incremental) andori_fmttest files — parser-internal, not cross-phase&Poolat all downstream boundaries — canonicalization, eval, codegen all receive&Pool&mut Poolonly withinori_types(type checker needs it for interning during inference/substitution) — not passed downstream
The gap is documentation, not enforcement. Gemini’s insight was correct: adding debug_assert! on arena-indexed data is impractical and redundant with Rust’s borrow checker. The type system IS the enforcement mechanism.
Reference implementations:
- TypeScript
compiler/types.ts: AST node types usereadonlymodifiers - Lean 4
src/Lean/Compiler/IR/: functional IR transformation — new IR produced, old untouched - Rust
rustc_middle/src/ty/mod.rs:Ty<'tcx>is an interned, structurally immutable handle
Depends on: Section 01 (policy language foundation).
02.1 Document Immutability Rule
File(s): .claude/rules/impl-hygiene.md, .claude/rules/parse.md
-
Add rule text to
impl-hygiene.md§Phase Boundaries (after “Clean ownership transfer” bullet, approximately line 77):- **IR immutability after construction**: after a phase completes, its output IR nodes are deeply immutable. No downstream phase may mutate arena-allocated AST (`ExprArena`), type pool entries (`Pool`), or canonical IR (`CanExpr`) in place. Enforcement: Rust's type system — downstream phases receive `&ExprArena`, `&Pool`, `&CanExpr`, never `&mut`. Transformations produce new IR via arena allocation in the consuming phase's own arena. `&mut Pool` is permitted ONLY within `ori_types` (interning during inference requires append-only mutation per `types.md` §TY-6). `&mut ExprArena` is permitted ONLY within `ori_parse` (construction) and `ori_parse/incremental/copier` (AST copying for incremental reparsing). Violations: introducing `&mut ExprArena` or `&mut Pool` parameters in downstream consumer functions is a LEAK:phase-bleeding finding. -
Add reference in
parse.md§AR-1 or nearby: “After parsing completes, theExprArenais immutable — all downstream phases receive&ExprArena. Seeimpl-hygiene.md§Phase Boundaries for the cross-phase immutability rule.” -
Add reference in
canon.md§5 Phase Purity: add a bullet noting the immutability invariant with cross-reference toimpl-hygiene.md -
Subsection close-out (02.1) — MANDATORY before completing section:
- All tasks above are
[x] - Update this subsection’s
statusin section frontmatter tocomplete - Run
/improve-toolingretrospectively on THIS subsection - Run
/sync-claudeto check if code changes affect CLAUDE.md or rules files
- All tasks above are
02.R Third Party Review Findings
- None.
02.N Completion Checklist
- Subsection 02.1 complete
- Rule text is accurate — verified against actual code (
&ExprArena,&Poolat boundaries) -
timeout 150 ./test-all.shpasses (no regressions from rule-only changes) -
/tpr-review— independent dual-source review clean -
/impl-hygiene-review— implementation hygiene clean -
/improve-tooling— section-close sweep -
/sync-claude— section-close doc sync