iter remove-mut-var-assign.1: atomic removal of mut/var/assign

mut/var/assign removed from AILang entirely and atomically. Deleted:
Term::Mut/Term::Assign/struct MutVar; the three Form-A keywords +
parse_mut/parse_assign + grammar EBNF; the 4 mut CheckError variants;
the mut_scope_stack synth threading (param dropped from synth + every
internal/external/test caller); the two lower_term arms; and every
exhaustive no-_ Term::Mut/Term::Assign match arm across 17 source
files — cut in lockstep with DESIGN.md, fixtures, the drift trio,
carve-out and roadmap so the schema is honest at every commit. No
catch-all wildcard introduced (verified). loop/recur + let/if are
the surviving forms.

The shared codegen alloca machinery survives (loop reuses it):
mut_var_allocas renamed binder_allocas (representation-only, loop
codegen byte-identical) and the shared Term::Lam escape guard
simplified to !loop_stack.is_empty() with the loop half
(LoopBinderCapturedByLambda) byte-equivalent. Feature-acceptance
applied inverted: the removed feature fails clause 2 (redundant)
and clause 3 (IS the iterated-mutable-state bug class).

Behaviour preservation is executable: mut_counter/mut_sum_floats
still print 55 after the faithful let/if rewrite. The removal is
made executable by the new mut_removed_pin.rs (4 must-fail pins).
Independent verification: cargo test --workspace 605/0, zero
residual mut symbols in any crate source, loop/recur non-regression
all green (55 / 500000500000 / infinite-compiles / the
lambda_capturing_loop_binder pin), roundtrip_cli PASS.

One DONE_WITH_CONCERNS: a 4th recurrence of the recon-undercount
class (in-source mod tests + a drift-pin fn + 5 orphaned mut
.ail.json carve-outs + a non-enumerated E0599); all resolved within
implementer remit, no behaviour change. Milestone-close audit then
fieldtest remain.

spec docs/specs/2026-05-18-remove-mut-var-assign.md (grounding PASS)
plan docs/plans/remove-mut-var-assign.1.md
This commit is contained in:
2026-05-18 11:06:17 +02:00
parent f355899fdf
commit 07f080256c
48 changed files with 331 additions and 2523 deletions
@@ -1,17 +1,5 @@
; Fieldtest mut-local #4 — Bool mut-var "found-a-factor" flag.
;
; Task: probe whether n has a small prime factor (2, 3, 5, or 7) by
; running four straight-line checks; if any check matches, set a Bool
; mut-var to true. Print the flag at the end.
;
; The straight-line form here is the natural shape: an LLM-author asked
; to "test these four conditions and OR the results" would otherwise
; write a chain of `||` operators (no such operator in AILang surface)
; or a nested chain of `(if ... (if ... ))`. The mut form replaces both
; with a flat sequence whose intent ("set this flag if any of these
; matches") reads top-to-bottom.
;
; Test against n = 91 = 7 * 13 — only the divisible-by-7 check fires.
; Probe whether n has a small prime factor (2, 3, 5, 7) via a
; let-threaded Bool flag. has_small_factor 91 = true (91 = 7 * 13).
; Expected stdout: true
(module mut-local_4_has_small_factor
@@ -19,14 +7,7 @@
(fn has_small_factor
(type (fn-type (params (con Int)) (ret (con Bool))))
(params n)
(body
(mut
(var found (con Bool) false)
(if (app == (app % n 2) 0) (assign found true) (lit-unit))
(if (app == (app % n 3) 0) (assign found true) (lit-unit))
(if (app == (app % n 5) 0) (assign found true) (lit-unit))
(if (app == (app % n 7) 0) (assign found true) (lit-unit))
found)))
(body (let found false (let found (if (app == (app % n 2) 0) true found) (let found (if (app == (app % n 3) 0) true found) (let found (if (app == (app % n 5) 0) true found) (let found (if (app == (app % n 7) 0) true found) found)))))))
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))