## Phase 131-11-H: ループキャリアPHI型修正 - PHI生成時に初期値(entry block)の型のみ使用 - backedge の値を型推論に使わない(循環依存回避) - NYASH_CARRIER_PHI_DEBUG=1 でトレース ## Phase 131-12-P0: def_blocks 登録 & STRICT エラー化 - safe_vmap_write() で PHI 上書き保護 - resolver miss を STRICT でエラー化(フォールバック 0 禁止) - def_blocks 自動登録 ## Phase 131-12-P1: vmap_cur スナップショット実装 - DeferredTerminator 構造体(block, term_ops, vmap_snapshot) - Pass A で vmap_cur をスナップショット - Pass C でスナップショット復元(try-finally) - STRICT モード assert ## 結果 - ✅ MIR PHI型: Integer(正しい) - ✅ VM: Result: 3 - ✅ vmap snapshot 機構: 動作確認 - ⚠️ LLVM: Result: 0(別のバグ、次Phase で調査) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
10 KiB
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 A–C / H)
- Phase 131-11 A–C:
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.mdのNYASH_PHI_TYPE_DEBUG/NYASH_PHI_META_DEBUG
- 参考(原因レポート):
現状メモ:
- VM では期待値に一致するが、LLVM では結果が一致しないケースが残っている(別トピックとして棚卸し/切り分けが必要)。
🔍 Root Cause (完全解明済み)
問題の核心
Case C fails because:
- Pattern Gap:
loop(true)(infinite loop) is NOT recognized by any of Patterns 1-4 - Loop Variable Extraction Fails:
extract_loop_variable_from_condition()expects binary comparison (i < 3), not boolean literal (true) - Classification Priority Bug:
has_continue = trueroutes 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! |
💡 Recommended Solution: Dedicated “InfiniteEarlyExit” pattern (recommended)
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?
- Correctness-first:
has_break && has_continuemust not route to Pattern 4 (Pattern 4 assumes a loop variable in the condition). - No naming collision: Existing “Trim/P5” already exists; avoid calling this “Pattern 5”.
- Minimal + Fail-Fast: Support exactly the Case C skeleton first, reject everything else.
- 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: 5–6 files modified (+1 new pattern module)
-
src/mir/loop_pattern_detection/mod.rs- Add
is_infinite_loop: boolfield toLoopFeaturesstruct - Add
LoopPatternKind::InfiniteEarlyExit - Update
classify()(infinite+break+continue must not route to Pattern4)
- Add
-
src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs- Update
extract_features()signature (addcondition: &ASTNodeparam) - Detect
loop(true)in condition
- Update
-
src/mir/builder/control_flow/joinir/patterns/router.rs- Pass condition into
extract_features() - Ensure
LOOP_PATTERNStable routesInfiniteEarlyExit
- Pass condition into
-
src/mir/builder/control_flow/joinir/patterns/mod.rspub(in crate::mir::builder) mod pattern_infinite_early_exit;(new module export)
-
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:
- ✅ Case C (minimal) compiles to MIR successfully
- ✅ Case C (minimal) passes VM execution (prints
3) - ✅ Case C (minimal) passes LLVM AOT (EMIT + LINK + RUN)
- ✅ Case C (with continue) fails with clear error message (Fail-Fast)
- ✅ No regression in Cases A, B, B2 (all still pass)
- ✅ 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):
- Start with Phase 131-11-A (Feature Detection) - 30 min
- Proceed to Phase 131-11-B (Classification Fix) - 15 min
- Implement Phase 131-11-C (Pattern 2 Extension) - 2-3 hours
- Run unit tests + integration tests
- 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