feat(joinir): Phase 188-Impl-2 Pattern 2 (Loop with Conditional Break) implementation

Add Pattern 2 lowerer for `loop { if cond { break } body }` pattern.

New files:
- loop_with_break_minimal.rs (291 lines): JoinIR lowerer for Pattern 2
  - Exit PHI receives values from both natural exit and break path
  - Tail-recursive loop_step function design

Modified files:
- loop_pattern_detection.rs: Add is_loop_with_break_pattern() detection
- mod.rs: Router integration (Pattern 1 → Pattern 2 ordering)
- control_flow.rs: Add cf_loop_pattern2_with_break() helper
- loop_patterns.rs: Simplified skeleton (defer until patterns stabilize)

Test results:
- Pattern 1 (loop_min_while.hako):  PASS
- Pattern 2 (joinir_min_loop.hako):  PASS

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-05 15:28:54 +09:00
parent 4e4a56f8c9
commit 87e477b13e
5 changed files with 519 additions and 213 deletions

View File

@ -108,32 +108,40 @@ pub fn is_simple_while_pattern(loop_form: &LoopForm) -> bool {
/// }
/// ```
pub fn is_loop_with_break_pattern(loop_form: &LoopForm) -> bool {
// TODO: Implement detection logic
// Step 1: Check break_targets is NON-EMPTY
// Step 2: Check exactly ONE break target (len() == 1)
// Step 3: Find if statement containing break
// Step 4: Verify break is in then-branch
// Step 5: Verify no nested loops
// Pattern 2 Recognition Criteria (from design.md § Pattern 2):
// 1. break_targets: NON-EMPTY (at least 1 break)
// 2. continue_targets: EMPTY (for simplicity)
// 3. Exactly ONE break target
//
// Reference: design.md § Pattern 2 section
// Recognition Criteria:
// - break_targets: NON-EMPTY (at least 1 break)
// - continue_targets: EMPTY (for simplicity)
// - Exactly one if statement with break
// Phase 188-Impl-2: Minimal implementation
// Advanced checks (nested loops, if-statement structure) are deferred to
// lowering phase where we can fail gracefully if needed.
// Check 1: break_targets is NON-EMPTY (has at least 1 break)
if loop_form.break_targets.is_empty() {
return false;
}
// Check 2: Exactly ONE break target (pattern assumes single break)
if loop_form.break_targets.len() != 1 {
return false;
}
// Check 3: No continue statements (for simplicity in Pattern 2)
if !loop_form.continue_targets.is_empty() {
return false;
}
// Pattern 2 matched
// The LoopForm structure guarantees:
// - Valid loop structure
// - Single break target
// - No continues
//
// Example LoopScopeShape:
// ```rust
// LoopScopeShape {
// preheader: BlockId(1),
// header: BlockId(2),
// body: BlockId(3),
// latch: BlockId(5),
// exit: BlockId(6),
// break_targets: vec![BlockId(4)], // NON-EMPTY - CRITICAL CHECK
// continue_targets: vec![], // EMPTY
// }
// ```
false
// Advanced checks (break is in if-statement, etc.) are deferred to
// lowering phase for graceful failure.
true
}
// ============================================================================