fix(phi): if-block PHI reassignment のSSA違反を解消

**問題**: If-block PHI nodes がグローバルValueIdアロケーター使用 → 関数ローカルIDと衝突
- insert_phi() が value_gen.next() 使用
- 関数内で後から割り当てられるValueIdと重複 → SSA違反

**根本原因**:
```rust
//  Before: グローバルアロケーター
let phi_val = self.value_gen.next();

//  After: 関数ローカルアロケーター
let phi_val = if let Some(ref mut f) = self.current_function {
    f.next_value_id()  // 関数コンテキスト
} else {
    self.value_gen.next()  // モジュールコンテキスト
};
```

**修正内容**:

1. **insert_phi() 修正** (src/mir/utils/phi_helpers.rs:63-70)
   - 関数コンテキストでは f.next_value_id() 使用
   - pin_to_slot() / loop builder (e2d061d1) と同じパターン

2. **insert_phi_with_dst() ドキュメント強化** (lines 94-114)
   - 正しいValueId割り当て方法を例示
   -  間違い: 常に value_gen.next() 使用
   -  正しい: 関数コンテキスト判定

**テスト結果**:
 Simple if-param-method: PASS (SSA違反なし)
 Test1/Test3: PASS (regression なし)
⚠️ Test2 (Stage-B): ValueId(22) 残存(別問題: receiver materialization)

**残存問題** (別issue):
- ValueId(22) = receiver materialization 問題
- pin_to_slot / emit_guard / BlockScheduleBox が分散
- 責務の集約が必要(次タスク)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-17 06:54:48 +09:00
parent e2d061d113
commit cc9fb2f654
2 changed files with 33 additions and 7 deletions

View File

@ -60,7 +60,14 @@ impl MirBuilder {
/// ```
#[inline]
pub fn insert_phi(&mut self, inputs: Vec<(BasicBlockId, ValueId)>) -> Result<ValueId, String> {
let phi_val = self.value_gen.next();
// Phase 25.1b fix: Use function-local ID allocator to avoid SSA verification failures
// This prevents PHI dst ValueIds from colliding with function-local IDs allocated later.
// Same pattern as pin_to_slot() and the loop builder fix in e2d061d1.
let phi_val = if let Some(ref mut f) = self.current_function {
f.next_value_id() // Function context: use local ID allocator
} else {
self.value_gen.next() // Module context: use global ID allocator
};
// 統一された挿入ロジック(既存パターンと完全互換)
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
@ -84,9 +91,28 @@ impl MirBuilder {
/// - 複雑なif式で結果ValueIdを先に確保している場合
/// - PHI命令の結果を複数箇所で参照する必要がある場合
///
/// ## 重要: ValueId割り当てルール
/// `dst`は必ず関数コンテキストに適したアロケーターで確保すること:
/// ```rust
/// // ✅ 正しい: 関数ローカルアロケーター使用
/// let result_val = if let Some(ref mut f) = self.current_function {
/// f.next_value_id()
/// } else {
/// self.value_gen.next()
/// };
/// self.insert_phi_with_dst(result_val, vec![...])?;
///
/// // ❌ 間違い: 常にグローバルアロケーター使用SSA違反の原因
/// let result_val = self.value_gen.next();
/// ```
///
/// ## 例
/// ```rust
/// let result_val = self.value_gen.next();
/// let result_val = if let Some(ref mut f) = self.current_function {
/// f.next_value_id() // 関数コンテキスト: ローカルID
/// } else {
/// self.value_gen.next() // モジュールコンテキスト: グローバルID
/// };
/// // ... 複雑なロジック ...
/// self.insert_phi_with_dst(result_val, vec![
/// (then_block, then_value),