Files
hakorune/docs/development/current/main/phase131-11-case-c-summary.md
nyash-codex 771bf6b0d1 feat(joinir): Phase 132-P3 - Exit PHI collision early detection
Added verify_exit_phi_no_collision() to contract_checks.rs for early detection
of ValueId collisions between exit PHIs and other instructions.

Problem detected:
- If exit_phi_builder uses builder.value_gen.next() (module-level) instead of
  func.next_value_id() (function-level), ValueIds can collide:

  Example:
  - bb0: %1 = const 0   (counter init)
  - bb3: %1 = phi ...   (exit PHI - collision!)

Previous behavior:
- Error only detected at LLVM backend runtime
- Cryptic error: "Cannot overwrite PHI dst=1"

New behavior:
- Panic at Rust compile time (debug build)
- Clear error message with fix suggestion:
  "Exit PHI dst %1 collides with instruction in block 0
   Fix: Use func.next_value_id() in exit_phi_builder.rs"

Benefits:
- 🔥 Fail-Fast: Catch errors during Rust compilation, not LLVM execution
- 📋 Clear messages: Exact collision point + fix suggestion
- 🧪 Testable: verify_exit_phi_no_collision() can be unit tested

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 06:00:48 +09:00

10 KiB
Raw Blame History

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

Date: 2025-12-14 Status: Active - Pattern detection landed; follow-ups tracked


🎯 Task Summary

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

Test File: apps/tests/llvm_stage3_loop_only.hako

状態アップデートPhase 131-11 AC / H

  • Phase 131-11 AC: loop(true) + break/continue を専用パターン(pattern5_infinite_early_exit.rs)へルーティングできる状態まで到達(検出/shape guard
  • Phase 131-11 H: ループキャリアPHIの型が循環で壊れる問題に対して、PHI作成時に entry(init) 側の型のみを seed する修正が入った。
    • 参考(原因レポート): docs/development/current/main/phase-131-11-g-phi-type-bug-report.md
    • PHI/型デバッグ: docs/reference/environment-variables.mdNYASH_PHI_TYPE_DEBUG / NYASH_PHI_META_DEBUG

現状メモ:

  • apps/tests/llvm_stage3_loop_only.hako については Phase 132-P2 で VM/LLVM parityResult: 3)まで到達した。
    • 調査ログ: docs/development/current/main/investigations/phase132-case-c-llvm-exe.md

🔍 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