Iter 14d: remove Term::If as a redundancy
Term::If was semantically a subset of Term::Match on Bool. Per CLAUDE.md the language must contain no redundancies; two AST nodes for the same operation produces an authoring decision with no semantic content and a duplicate codegen path. Removed. Migration shape (applied to sum, sort, max3 fixtures): (if c a b) -> (match c (case (lit-bool true) a) (case _ b)) No schema version bump (per user direction): no third-party consumes ailang/v0, so version ceremony is pure overhead. Edited AST and fixtures in place; pinned hashes in hash.rs updated. Implementer deviation, called out and justified: a tightly-scoped lower_bool_match helper (~95 LOC) was needed in codegen because the existing match path rejects i1 scrutinees and Pattern::Lit. Helper accepts only the canonical two-arm migration shape, errors on anything else, emits the same br/phi IR Term::If used to. No generalisation of the ADT-match codegen. Diff: 13 files, +286/-221 (net +65 LOC). AST got smaller (one variant gone), form-(A) got smaller (one production gone), typecheck got smaller (one branch gone). Codegen got slightly larger by the bool-match helper. Hash deltas: sum.sum, sort.insert, max3.max, max3.max3 changed. All other defs (e.g. sum.main, sort.IntList, sort.sort, sort.print_list, max3.main) kept bit-identical hashes — confirms canonical-JSON byte format intact. Verification: 76/76 tests green; sum->55, max3->17, sort->[1,1,2, 3,3,4,5,5,5,6,9] (identical to pre-migration). cargo doc 0 warnings. Tail-call survey by implementer (informs 14e): print_list recursions are already in tail position (rhs of seq inside match arm); map/sort/insert recursions are NOT (constructor-blocked inside Cons applications). 14e annotation will benefit terminal recursions; ctor-blocked ones need accumulator-form rewrites in source, not a compiler-side transform. Decision 7 added to DESIGN.md. JOURNAL entry has the language- completion sequence (14d done, 14e tail-calls, 14f GC, 15a stdlib). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -878,11 +878,6 @@ fn walk_term(
|
||||
scope.remove(name);
|
||||
}
|
||||
}
|
||||
Term::If { cond, then, else_ } => {
|
||||
walk_term(cond, out, builtins, scope);
|
||||
walk_term(then, out, builtins, scope);
|
||||
walk_term(else_, out, builtins, scope);
|
||||
}
|
||||
Term::Do { op, args } => {
|
||||
// Mark effect ops as `effect:io/print_int` so they can be
|
||||
// separated from normal function calls.
|
||||
|
||||
@@ -174,8 +174,11 @@ fn diff_detects_changed_def() {
|
||||
let workspace = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
|
||||
let src_a = workspace.join("examples").join("sum.ail.json");
|
||||
|
||||
// Variant: load sum.ail.json, mutate the `then` branch (1 instead of 0)
|
||||
// in the `sum` definition. `main` stays bit-identical.
|
||||
// Variant: load sum.ail.json, mutate the true-arm body of the
|
||||
// top-level `match` in `sum` (literal 0 → literal 1). `main` stays
|
||||
// bit-identical. After Iter 14d the body is `Match` (not `If`); the
|
||||
// first arm is the `(lit-bool true)` arm, formerly the `then`
|
||||
// branch.
|
||||
let raw = std::fs::read(&src_a).expect("read sum.ail.json");
|
||||
let mut module: serde_json::Value = serde_json::from_slice(&raw).expect("parse sum.ail.json");
|
||||
{
|
||||
@@ -185,12 +188,11 @@ fn diff_detects_changed_def() {
|
||||
.expect("defs array");
|
||||
for def in defs.iter_mut() {
|
||||
if def.get("name").and_then(|n| n.as_str()) == Some("sum") {
|
||||
// Replace the then branch literal 0 → literal 1.
|
||||
let new_then = serde_json::json!({
|
||||
let new_body = serde_json::json!({
|
||||
"t": "lit",
|
||||
"lit": { "kind": "int", "value": 1 }
|
||||
});
|
||||
def["body"]["then"] = new_then;
|
||||
def["body"]["arms"][0]["body"] = new_body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user