diff --git a/src/mir/builder/lifecycle.rs b/src/mir/builder/lifecycle.rs index 9c931f44..d93a6df7 100644 --- a/src/mir/builder/lifecycle.rs +++ b/src/mir/builder/lifecycle.rs @@ -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 = 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 のみをチェックし、実際の戻り値を正しく推論する