fix(mir): Phase 131-9 - PHI 型推論修正(String→Integer)

Phase 131-9: MIR PHI 型推論バグ修正

問題:
- PHI が String 型として推論される
- 結果: 0,01,011(文字列連結)
- 期待: 0,1,2(整数 increment)

根本原因:
- PHI emission 時に circular dependency
- latch incoming value が PHI 型を継承
- 使用側(print)の型要求で String に

修正:
- src/mir/builder/lifecycle.rs (+75 lines):
  - Global PHI Type Inference Pass 追加
  - PHI 型を incoming values から再推論
  - PhiTypeResolver を再利用

MIR 変化:
- Before: %3: String = phi [%2, bb0], [%12, bb7]
- After:  %3: Integer = phi [%2, bb0], [%12, bb7]

テスト結果:
- Rust VM: 0,01,011 → 0,1,2  完璧!
- LLVM: Segfault(別バグ、Phase 131-10 で対応)

箱化モジュール化:
-  PhiTypeResolver 再利用
-  単一責任: PHI 型補正のみ
-  Debug flag: NYASH_PHI_GLOBAL_DEBUG=1

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-14 08:30:54 +09:00
parent cf4d98ed08
commit bfe047840b

View File

@ -307,13 +307,88 @@ impl super::MirBuilder {
let mut module = self.current_module.take().unwrap();
let mut function = self.current_function.take().unwrap();
function.metadata.value_types = self.value_types.clone();
// Phase 84-2: Copy命令型伝播return型推論の前に実行
//
// Loop exit や If merge の edge copy で発生する型欠如を解消する。
// Copy チェーン: v1 → v2 → v3 で v1 の型が既知なら v2, v3 にも伝播。
CopyTypePropagator::propagate(&function, &mut self.value_types);
// Phase 131-9: Global PHI type inference
//
// Infer types for ALL PHI nodes, not just return values.
// This fixes loop carrier PHIs that don't get inferred otherwise.
// Uses PhiTypeResolver to infer from incoming values (not usage).
//
// Bug: loop_min_while.hako PHI %3 was typed as String instead of Integer
// Cause: PHI incoming values unavailable at emission time
// Fix: Run PhiTypeResolver after CopyTypePropagator, before return type inference
//
// Collect ALL PHI dsts for re-inference (not just untyped)
// This is necessary because propagate_phi_meta may have assigned incorrect types
// due to circular dependencies (e.g., loop carrier PHIs)
let mut all_phi_dsts: Vec<ValueId> = Vec::new();
for (_bid, bb) in function.blocks.iter() {
for inst in &bb.instructions {
if let MirInstruction::Phi { dst, .. } = inst {
if std::env::var("NYASH_PHI_GLOBAL_DEBUG").is_ok() {
let existing_type = self.value_types.get(dst);
eprintln!(
"[lifecycle/phi-scan] {} PHI {:?} existing type: {:?}",
function.signature.name, dst, existing_type
);
}
all_phi_dsts.push(*dst);
}
}
}
if std::env::var("NYASH_PHI_GLOBAL_DEBUG").is_ok() {
eprintln!(
"[lifecycle/phi-scan] {} found {} total PHIs to re-infer",
function.signature.name,
all_phi_dsts.len()
);
}
// Re-infer types for ALL PHI nodes using PhiTypeResolver
// This fixes incorrect types assigned by propagate_phi_meta during circular dependencies
if !all_phi_dsts.is_empty() {
let phi_resolver = PhiTypeResolver::new(&function, &self.value_types);
let mut inferred_types: Vec<(ValueId, MirType)> = Vec::new();
for dst in all_phi_dsts {
if let Some(mt) = phi_resolver.resolve(dst) {
// Check if type changed
let existing_type = self.value_types.get(&dst);
if existing_type.is_none() || existing_type != Some(&mt) {
inferred_types.push((dst, mt));
}
}
}
// Now insert/update all inferred types
for (dst, mt) in inferred_types {
let old_type = self.value_types.get(&dst).cloned();
self.value_types.insert(dst, mt.clone());
if std::env::var("NYASH_PHI_GLOBAL_DEBUG").is_ok() {
if let Some(old) = old_type {
eprintln!(
"[lifecycle/phi-global] {} PHI {:?} type corrected: {:?} -> {:?}",
function.signature.name, dst, old, mt
);
} else {
eprintln!(
"[lifecycle/phi-global] {} PHI {:?} type inferred: {:?}",
function.signature.name, dst, mt
);
}
}
}
}
// Phase 131-9: Update function metadata with corrected types
// MUST happen after PHI type correction above
function.metadata.value_types = self.value_types.clone();
// Phase 82-5: lifecycle.rs バグ修正 - terminator の Return のみをチェック
// 問題: instructions を先に走査すると、中間値const void 等)を誤って推論対象にしてしまう
// 解決: terminator の Return のみをチェックし、実際の戻り値を正しく推論する