feat(joinir): Phase 286 P3.2 - Pattern5 Plan line (loop(true) + early exit)
- Pattern5InfiniteEarlyExitPlan (Return/Break variants)
- extract_pattern5_plan() for loop(true) literal only
- normalize_pattern5_return(): 5 blocks CFG (header→body→found/step)
- normalize_pattern5_break(): 6 blocks CFG with carrier PHI
- NormalizationPlanBox exclusion for Pattern5-style loops
- Fixtures: phase286_pattern5_{return,break}_min.hako
- quick smoke 154/154 PASS
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -52,15 +52,16 @@ impl NormalizationPlanBox {
|
||||
|
||||
// First statement must be a loop with condition `true`
|
||||
// Phase 131-136 ONLY support loop(true), not loop(i < n) etc.
|
||||
let is_loop_true = match &remaining[0] {
|
||||
ASTNode::Loop { condition, .. } => {
|
||||
let (is_loop_true, loop_body) = match &remaining[0] {
|
||||
ASTNode::Loop { condition, body, .. } => {
|
||||
// Only accept loop(true) - literal Bool true
|
||||
matches!(
|
||||
let is_true = matches!(
|
||||
condition.as_ref(),
|
||||
ASTNode::Literal { value: LiteralValue::Bool(true), .. }
|
||||
)
|
||||
);
|
||||
(is_true, Some(body.as_slice()))
|
||||
}
|
||||
_ => false,
|
||||
_ => (false, None),
|
||||
};
|
||||
if !is_loop_true {
|
||||
if debug {
|
||||
@ -73,6 +74,31 @@ impl NormalizationPlanBox {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Phase 286 P3.2: Reject Pattern5-style loops (if with early return/break)
|
||||
// These are handled by the Plan line (Pattern5InfiniteEarlyExit), not StepTree
|
||||
if let Some(body) = loop_body {
|
||||
if !body.is_empty() {
|
||||
if let ASTNode::If { then_body, else_body, .. } = &body[0] {
|
||||
// Check if it's a Pattern5-style if (no else, then contains return or break)
|
||||
if else_body.is_none() {
|
||||
let has_early_exit = then_body.iter().any(|stmt| {
|
||||
matches!(stmt, ASTNode::Return { .. } | ASTNode::Break { .. })
|
||||
});
|
||||
if has_early_exit {
|
||||
if debug {
|
||||
trace.routing(
|
||||
"normalization/plan",
|
||||
func_name,
|
||||
"Loop body has if with early return/break - Pattern5 (Plan line), returning None",
|
||||
);
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 142 P0: Always return loop_only for loop(true), regardless of what follows
|
||||
// Normalization unit is now "statement (loop 1個)" not "block suffix"
|
||||
// Subsequent statements (return, assignments, etc.) handled by normal MIR lowering
|
||||
|
||||
Reference in New Issue
Block a user