iter it.1: loop/recur additive — Term::Loop/Term::Recur/LoopBinder end-to-end
Iteration-discipline milestone, 1 of 3. Adds named loop + recur as strictly-additive first-class AST nodes: parse/print/prose/serde/ round-trip/schema lockstep, typecheck (binder typing + recur arity/type unification via loop_stack threaded as mut.2's mut_scope_stack; recur-tail-position via verify_loop_body), codegen (loop-header + one phi per binder; recur back-edge br with a NEW parallel block_terminated setter; lambda-boundary loop_frames save/restore). Four Recur* CheckError variants. Strictly additive: zero deletions touch tail-app/tail-do or the seven existing block_terminated sites — this is what makes the destructive it.3 safe. recur synth = fresh metavar (resolves the plan's flagged Type::unit() risk). loop_counter->55, loop_in_lambda->49, four negatives fire, tail-app byte-identical, cargo test --workspace green. Specfda9b78, plan7381a42.
This commit is contained in:
@@ -37,6 +37,11 @@ const EXPECTED: &[&str] = &[
|
||||
"test_mut_var_unsupported_type.ail.json",
|
||||
// Iter mut.4-tidy — lambda-capture-of-mut-var rejection
|
||||
"test_mut_var_captured_by_lambda.ail.json",
|
||||
// Iter it.1 — recur negative typecheck fixtures
|
||||
"test_recur_outside_loop.ail.json",
|
||||
"test_recur_arity_mismatch.ail.json",
|
||||
"test_recur_type_mismatch.ail.json",
|
||||
"test_recur_not_in_tail_position.ail.json",
|
||||
];
|
||||
|
||||
fn examples_dir() -> std::path::PathBuf {
|
||||
|
||||
@@ -151,6 +151,17 @@ fn design_md_anchors_every_term_variant() {
|
||||
value: Box::new(Term::Lit { lit: Literal::Unit }),
|
||||
},
|
||||
),
|
||||
(
|
||||
r#""t": "loop""#,
|
||||
Term::Loop {
|
||||
binders: Vec::new(),
|
||||
body: Box::new(Term::Lit { lit: Literal::Unit }),
|
||||
},
|
||||
),
|
||||
(
|
||||
r#""t": "recur""#,
|
||||
Term::Recur { args: Vec::new() },
|
||||
),
|
||||
];
|
||||
|
||||
for (anchor, term) in exemplars {
|
||||
@@ -172,6 +183,8 @@ fn design_md_anchors_every_term_variant() {
|
||||
Term::ReuseAs { .. } => "reuse-as",
|
||||
Term::Mut { .. } => "mut",
|
||||
Term::Assign { .. } => "assign",
|
||||
Term::Loop { .. } => "loop",
|
||||
Term::Recur { .. } => "recur",
|
||||
};
|
||||
assert!(
|
||||
data_model_section().contains(anchor),
|
||||
|
||||
@@ -49,6 +49,8 @@ enum VariantTag {
|
||||
TermReuseAs,
|
||||
TermMut,
|
||||
TermAssign,
|
||||
TermLoop,
|
||||
TermRecur,
|
||||
// Pattern
|
||||
PatternWild,
|
||||
PatternVar,
|
||||
@@ -96,6 +98,8 @@ const EXPECTED_VARIANTS: &[VariantTag] = &[
|
||||
VariantTag::TermReuseAs,
|
||||
VariantTag::TermMut,
|
||||
VariantTag::TermAssign,
|
||||
VariantTag::TermLoop,
|
||||
VariantTag::TermRecur,
|
||||
VariantTag::PatternWild,
|
||||
VariantTag::PatternVar,
|
||||
VariantTag::PatternLit,
|
||||
@@ -244,6 +248,20 @@ fn visit_term(t: &Term, observed: &mut HashSet<VariantTag>) {
|
||||
observed.insert(VariantTag::TermAssign);
|
||||
visit_term(value, observed);
|
||||
}
|
||||
Term::Loop { binders, body } => {
|
||||
observed.insert(VariantTag::TermLoop);
|
||||
for b in binders {
|
||||
visit_type(&b.ty, observed);
|
||||
visit_term(&b.init, observed);
|
||||
}
|
||||
visit_term(body, observed);
|
||||
}
|
||||
Term::Recur { args } => {
|
||||
observed.insert(VariantTag::TermRecur);
|
||||
for a in args {
|
||||
visit_term(a, observed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,17 @@ fn spec_mentions_every_term_variant() {
|
||||
value: Box::new(Term::Lit { lit: Literal::Unit }),
|
||||
},
|
||||
),
|
||||
(
|
||||
"(loop",
|
||||
Term::Loop {
|
||||
binders: Vec::new(),
|
||||
body: Box::new(Term::Lit { lit: Literal::Unit }),
|
||||
},
|
||||
),
|
||||
(
|
||||
"(recur",
|
||||
Term::Recur { args: Vec::new() },
|
||||
),
|
||||
];
|
||||
|
||||
for (anchor, term) in exemplars {
|
||||
@@ -151,6 +162,8 @@ fn spec_mentions_every_term_variant() {
|
||||
Term::ReuseAs { .. } => "reuse-as",
|
||||
Term::Mut { .. } => "mut",
|
||||
Term::Assign { .. } => "assign",
|
||||
Term::Loop { .. } => "loop",
|
||||
Term::Recur { .. } => "recur",
|
||||
};
|
||||
assert!(
|
||||
FORM_A_SPEC.contains(anchor),
|
||||
|
||||
Reference in New Issue
Block a user