Files
hakorune/docs/development/current/main/phase131-11-case-c-summary.md
nyash-codex e1d706d2e0 docs(phase131): Case C 調査完了 - InfiniteEarlyExit パターン追加方針
## 根本原因解明
- loop(true) が Pattern4 に誤ルーティング
- Pattern4 は BinaryOp 比較を期待、boolean literal で失敗

## 解決方針
- 新パターン InfiniteEarlyExit 追加(Pattern 2 拡張ではなく)
- classify() の優先度修正
- Shape guard で最小受理(break+continue 各1箇所)

## 作成ドキュメント
- case-c-infinite-loop-analysis.md (13KB詳細分析)
- phase131-11-case-c-summary.md (4KBサマリー)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 09:47:23 +09:00

9.3 KiB
Raw Blame History

Phase 131-11: Case C 本命タスク - 調査完了レポート

Date: 2025-12-14 Status: Root Cause Analysis Complete - Ready for Implementation


🎯 Task Summary

Goal: Make loop(true) { ... break ... continue } compile and run in JoinIR

Test File: apps/tests/llvm_stage3_loop_only.hako


🔍 Root Cause (完全解明済み)

問題の核心

Case C fails because:

  1. Pattern Gap: loop(true) (infinite loop) is NOT recognized by any of Patterns 1-4
  2. Loop Variable Extraction Fails: extract_loop_variable_from_condition() expects binary comparison (i < 3), not boolean literal (true)
  3. Classification Priority Bug: has_continue = true routes to Pattern 4, but Pattern 4 expects a loop variable

Failure Flow (5 Steps)

1. LoopPatternContext::new()
   └─ has_continue=true, has_break=true (✅ detected correctly)

2. classify(features)
   └─ Returns Pattern4Continue (❌ WRONG - should be Pattern2 or new Pattern5)

3. Pattern4::can_lower()
   └─ Tries extract_loop_variable_from_condition(BoolLiteral(true))

4. extract_loop_variable_from_condition()
   └─ ❌ Error: "Unsupported loop condition pattern"
   └─ Expected: BinaryOp comparison (i < 3)
   └─ Actual: BoolLiteral(true)

5. Pattern falls through
   └─ No pattern matches → freeze() error

現在のパターン対応表

Pattern Condition Type Break Continue Supported?
Pattern 1 Comparison (i < 3)
Pattern 2 Comparison (i < 3)
Pattern 3 Comparison (i < 3)
Pattern 4 Comparison (i < 3)
Case C Boolean (true) GAP!

Approach: Add is_infinite_loop feature + fix classification, then add a dedicated JoinIR loop pattern module for loop(true) with early-exit.

Why this approach?

  1. Correctness-first: has_break && has_continue must not route to Pattern 4 (Pattern 4 assumes a loop variable in the condition).
  2. No naming collision: Existing “Trim/P5” already exists; avoid calling this “Pattern 5”.
  3. Minimal + Fail-Fast: Support exactly the Case C skeleton first, reject everything else.
  4. Keeps Pattern2 invariants: Pattern2 is “break but no continue”; extending it to include continue blurs its contract.

Implementation Strategy (3 Phases)

Phase 131-11-A: Feature Detection (30 min)

Add is_infinite_loop field to LoopFeatures

// src/mir/loop_pattern_detection/mod.rs
pub struct LoopFeatures {
    pub has_break: bool,
    pub has_continue: bool,
    pub has_if: bool,
    pub has_if_else_phi: bool,
    pub carrier_count: usize,
    pub break_count: usize,
    pub continue_count: usize,
+   pub is_infinite_loop: bool,  // NEW: true for loop(true)
    pub update_summary: Option<LoopUpdateSummary>,
}

Update extract_features to detect loop(true)

// src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs
pub(crate) fn extract_features(
+   condition: &ASTNode,  // NEW: need condition for infinite loop detection
    body: &[ASTNode],
    has_continue: bool,
    has_break: bool
) -> LoopFeatures {
+   let is_infinite_loop = matches!(condition, ASTNode::BoolLiteral { value: true, .. });
    // ... rest
}

Update callers

// src/mir/builder/control_flow/joinir/patterns/router.rs (LoopPatternContext::new)
- let features = ast_features::extract_features(body, has_continue, has_break);
+ let features = ast_features::extract_features(condition, body, has_continue, has_break);

Phase 131-11-B: Classification Fix (15 min)

Fix classify() so break+continue does not misroute to Pattern 4

// src/mir/loop_pattern_detection/mod.rs
pub fn classify(features: &LoopFeatures) -> LoopPatternKind {
+   // NEW: Case C core: infinite loop + break + continue → dedicated pattern kind
+   if features.is_infinite_loop && features.has_break && features.has_continue {
+       return LoopPatternKind::InfiniteEarlyExit;
+   }

    // Pattern 4: Continue (existing)
    if features.has_continue && !features.has_break {
        return LoopPatternKind::Pattern4Continue;
    }

    // ... rest unchanged
}

Phase 131-11-C: InfiniteEarlyExit lowering (2-3 hours)

Add a dedicated pattern module and keep Pattern2 untouched

// src/mir/builder/control_flow/joinir/patterns/pattern_infinite_early_exit.rs
pub fn can_lower(ctx: &LoopPatternContext) -> bool {
    matches!(ctx.pattern_kind, LoopPatternKind::InfiniteEarlyExit)
}

pub fn lower(builder: &mut MirBuilder, ctx: &LoopPatternContext) -> Result<Option<ValueId>, String> {
    // Shape guard (Fail-Fast):
    // - condition must be `true` literal
    // - exactly one break site and one continue site
    // - no nested loop / nested break/continue
    // Lowering outline:
    // - header: unconditional enter step
    // - step: body core → break-check → continue (tailcall to step) / exit
    unimplemented!()
}

📋 Modified Files Summary

Total: 56 files modified (+1 new pattern module)

  1. src/mir/loop_pattern_detection/mod.rs

    • Add is_infinite_loop: bool field to LoopFeatures struct
    • Add LoopPatternKind::InfiniteEarlyExit
    • Update classify() (infinite+break+continue must not route to Pattern4)
  2. src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs

    • Update extract_features() signature (add condition: &ASTNode param)
    • Detect loop(true) in condition
  3. src/mir/builder/control_flow/joinir/patterns/router.rs

    • Pass condition into extract_features()
    • Ensure LOOP_PATTERNS table routes InfiniteEarlyExit
  4. src/mir/builder/control_flow/joinir/patterns/mod.rs

    • pub(in crate::mir::builder) mod pattern_infinite_early_exit; (new module export)
  5. src/mir/builder/control_flow/joinir/patterns/pattern_infinite_early_exit.rs (NEW)

    • Shape guard + lowering implementation for Case C

🧪 Test Strategy

Unit Tests

File: src/mir/loop_pattern_detection/mod.rs (tests module)

#[test]
fn test_classify_infinite_loop_with_break() {
    let features = LoopFeatures {
        has_break: true,
        has_continue: false,
        is_infinite_loop: true,
        // ... other fields
    };
    assert_eq!(classify(&features), LoopPatternKind::Pattern2Break);
}

#[test]
fn test_classify_infinite_loop_with_continue_unsupported() {
    let features = LoopFeatures {
        has_break: false,
        has_continue: true,
        is_infinite_loop: true,
        // ... other fields
    };
    assert_eq!(classify(&features), LoopPatternKind::Unknown);
}

Integration Tests

Case C Minimal (/tmp/case_c_minimal.hako):

static box Main {
  main() {
    local i = 0
    loop (true) {
      i = i + 1
      if i == 3 { break }
    }
    print(i)
    return 0
  }
}

Expected: Prints 3

Case C Full (apps/tests/llvm_stage3_loop_only.hako):

loop (true) {
  counter = counter + 1
  if counter == 3 { break }
  continue
}

Expected: MIR compile error (Fail-Fast - not supported yet)

End-to-End Test

# VM test
./target/release/hakorune /tmp/case_c_minimal.hako
# Expected output: 3

# LLVM test (after Phase 131-11 complete)
tools/build_llvm.sh /tmp/case_c_minimal.hako -o /tmp/case_c_exe
/tmp/case_c_exe
# Expected output: 3
echo $?
# Expected exit code: 0

⏱️ Timeline Estimate

Phase 131-11-A: 30 minutes (Feature Detection) Phase 131-11-B: 15 minutes (Classification Fix) Phase 131-11-C: 2-3 hours (Pattern 2 Extension)

Total: 3-4 hours to complete Phase 131-11


Success Criteria

Phase 131-11 Complete when:

  1. Case C (minimal) compiles to MIR successfully
  2. Case C (minimal) passes VM execution (prints 3)
  3. Case C (minimal) passes LLVM AOT (EMIT + LINK + RUN)
  4. Case C (with continue) fails with clear error message (Fail-Fast)
  5. No regression in Cases A, B, B2 (all still pass)
  6. Unit tests for classification pass

📚 References

Detailed Analysis: case-c-infinite-loop-analysis.md (13KB, complete investigation)

SSOT: phase131-3-llvm-lowering-inventory.md (updated with root cause)

Related Files:

  • Pattern Detection: src/mir/loop_pattern_detection/mod.rs
  • Feature Extraction: src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs
  • Pattern Router: src/mir/builder/control_flow/joinir/patterns/router.rs
  • Pattern 2 Lowering: src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs

🚦 Next Steps

For ChatGPT (Implementation):

  1. Start with Phase 131-11-A (Feature Detection) - 30 min
  2. Proceed to Phase 131-11-B (Classification Fix) - 15 min
  3. Implement Phase 131-11-C (Pattern 2 Extension) - 2-3 hours
  4. Run unit tests + integration tests
  5. Verify end-to-end LLVM AOT path

For Claude (Review):

  • Review implementation for Box Theory alignment (Fail-Fast, modular boundaries)
  • Verify no regression in existing patterns
  • Check for code duplication opportunities (Pattern 2 finite vs infinite)

Last Updated: 2025-12-14 Phase: 131-11 (Case C本命タスク) Status: 🎯 Ready for Implementation