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:
2025-12-26 09:56:34 +09:00
parent ec55cce380
commit 22945c190c
12 changed files with 963 additions and 16 deletions

View File

@ -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