fix(mir): edge-copy insertion before terminator - resolve ValueId undefined errors

【問題】
Stage-B(JSON v0 Bridge)で「use of undefined value ValueId(...)」エラー発生
- 原因: merge.rs:38-42でedge-copyを終端命令**後**に追加していた
- 結果: Copy命令が到達不能となり、ValueIdが未定義のまま参照される

【根本原因分析】
1. if_else.rs:34で`set_terminator(Jump)`を設定
2. if_else.rs:62で`merge_var_maps()`呼び出し
3. merge.rs:39で`add_instruction(Copy)` ← **ここで終端後に追加!**
4. BasicBlock構造上、terminator設定後のadd_instruction()は到達不能

【修正内容】
1. BasicBlock::add_instruction_before_terminator()メソッド追加
   - 終端命令の有無に関わらず、instructions vecに追加
   - terminator自体の追加は許可しない(panic)

2. merge_values()でedge-copy挿入方法を変更
   - add_instruction() → add_instruction_before_terminator()
   - これによりCopyが終端の**前**に配置される

【修正箇所】
- src/mir/basic_block.rs: add_instruction_before_terminator()追加(12行)
- src/runner/json_v0_bridge/lowering/merge.rs: 呼び出し変更(2行)

【テスト結果】
 if文PHIテスト: /tmp/phi_simple_if2.nyash → 出力 1
 loop文PHIテスト: /tmp/phi_loop_test.nyash → 出力 10
 userbox_*スモークテスト: 全6テストPASS
⚠️ Stage-B: namespace conflict未解決のため未確認
   (apps/selfhost.vm.* と lang/hakorune.vm.* の競合)

【影響範囲】
- JSON v0 Bridge経路のif/else合流処理
- edge-copy(PHI-off mode)の正しい配置保証
- Builder経路は元々正常動作(影響なし)

🤖 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-01 14:37:54 +09:00
parent 83db6a715c
commit 79b9d2b32c
2 changed files with 17 additions and 2 deletions

View File

@ -102,6 +102,20 @@ impl BasicBlock {
} }
} }
/// Add instruction before terminator (for edge-copy in PHI-off mode)
/// If no terminator exists, behaves like add_instruction()
pub fn add_instruction_before_terminator(&mut self, instruction: MirInstruction) {
// Update effect mask
self.effects = self.effects | instruction.effects();
// Non-terminator instructions always go into instructions vec
if !self.is_terminator(&instruction) {
self.instructions.push(instruction);
} else {
panic!("Cannot add terminator via add_instruction_before_terminator");
}
}
/// Check if an instruction is a terminator /// Check if an instruction is a terminator
fn is_terminator(&self, instruction: &MirInstruction) -> bool { fn is_terminator(&self, instruction: &MirInstruction) -> bool {
matches!( matches!(

View File

@ -35,11 +35,12 @@ pub(super) fn merge_values(
} }
let dst = f.next_value_id(); let dst = f.next_value_id();
if no_phi { if no_phi {
// Insert edge-copy BEFORE terminator (critical fix for ValueId undefined errors)
if let Some(bb) = f.get_block_mut(pred_a) { if let Some(bb) = f.get_block_mut(pred_a) {
bb.add_instruction(MirInstruction::Copy { dst, src: val_a }); bb.add_instruction_before_terminator(MirInstruction::Copy { dst, src: val_a });
} }
if let Some(bb) = f.get_block_mut(pred_b) { if let Some(bb) = f.get_block_mut(pred_b) {
bb.add_instruction(MirInstruction::Copy { dst, src: val_b }); bb.add_instruction_before_terminator(MirInstruction::Copy { dst, src: val_b });
} }
} else if let Some(bb) = f.get_block_mut(merge_bb) { } else if let Some(bb) = f.get_block_mut(merge_bb) {
bb.insert_instruction_after_phis(MirInstruction::Phi { bb.insert_instruction_after_phis(MirInstruction::Phi {