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:
@@ -0,0 +1,31 @@
|
||||
//! Pins the mut/var/assign removal: the keyword no longer parses and
|
||||
//! the canonical JSON tag is an unknown serde variant. RED until the
|
||||
//! Task-2 atomic cut lands.
|
||||
use ailang_surface::parse;
|
||||
|
||||
#[test]
|
||||
fn mut_keyword_is_rejected_by_form_a_parse() {
|
||||
let src = "(module m (fn f (type (fn-type (params) (ret (con Int)))) (params) (body (mut (var x (con Int) 0) (assign x (app + x 1)) x))))";
|
||||
let r = parse(src);
|
||||
assert!(r.is_err(), "mut keyword must no longer parse, got Ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assign_keyword_is_rejected_by_form_a_parse() {
|
||||
let src = "(module m (fn f (type (fn-type (params) (ret (con Int)))) (params) (body (assign x 1))))";
|
||||
assert!(parse(src).is_err(), "assign keyword must no longer parse, got Ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_tag_mut_is_unknown_serde_variant() {
|
||||
let j = r#"{"t":"mut","vars":[],"body":{"t":"lit","lit":{"kind":"int","value":0}}}"#;
|
||||
let r: Result<ailang_core::ast::Term, _> = serde_json::from_str(j);
|
||||
assert!(r.is_err(), "{{\"t\":\"mut\"}} must be an unknown variant, got Ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_tag_assign_is_unknown_serde_variant() {
|
||||
let j = r#"{"t":"assign","name":"x","value":{"t":"lit","lit":{"kind":"int","value":1}}}"#;
|
||||
let r: Result<ailang_core::ast::Term, _> = serde_json::from_str(j);
|
||||
assert!(r.is_err(), "{{\"t\":\"assign\"}} must be an unknown variant, got Ok");
|
||||
}
|
||||
Reference in New Issue
Block a user