feat(joinir): Phase 66-68 GenericTypeResolver + JoinIR First Chapter Wrap
Phase 66: P3-C ジェネリック型推論箱化 - generic_type_resolver.rs 新設 (180行) - is_generic_method(): ArrayBox.get/pop/first/last, MapBox.get 判定 - resolve_from_phi(): PHI解析によるジェネリック型推論 - TypeHintPolicy::is_p3c_target() 追加 - P1/P2/P3-A/P3-B 以外を P3-C 候補として判定 Phase 67: P3-C 実利用への一歩 - phase67_generic_type_resolver.rs テスト追加 (3テスト) - lifecycle.rs に P3-C 経路フック追加 - GenericTypeResolver を P3-C 対象関数で優先使用 - A/B テストで旧経路との一致確認 (11 tests PASS) Phase 68: JoinIR First Chapter Wrap (ドキュメント整理) - 68-1: phase-30 README.md に Section 9 追加 (JoinIR 第1章完了サマリー) - 68-2: README.md に JoinIR status セクション追加 - 68-3: CURRENT_TASK.md スリム化 (351→132行, 62%削減) - 68-4: PHI_BOX_INVENTORY.md に Phase 66-67 完了セクション追加 Phase 69-1: Trio 棚卸し - phase69-1-trio-inventory.md 作成 - Trio 使用箇所の完全棚卸し完了 (削減見込み 457-707行) 🐱 JoinIR 第1章完了!4つの柱確立: - Structure (LoopForm) - Scope (LoopScopeShape) - JoinIR (Select/IfMerge/Loop) - Type Hints (P1-P3-C) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -38,6 +38,8 @@ fn has_main_static(ast: &ASTNode) -> bool {
|
||||
// - ✅ テスト可能:各 Phase 独立テスト
|
||||
// - ✅ 拡張容易:Phase 66+ で P3-C 追加が簡単
|
||||
use crate::mir::join_ir::lowering::type_hint_policy::TypeHintPolicy;
|
||||
// Phase 67: P3-C ジェネリック型推論箱
|
||||
use crate::mir::join_ir::lowering::generic_type_resolver::GenericTypeResolver;
|
||||
|
||||
impl super::MirBuilder {
|
||||
/// Unified declaration indexing (Phase A): collect symbols before lowering
|
||||
@ -290,17 +292,37 @@ impl super::MirBuilder {
|
||||
break 'outer;
|
||||
}
|
||||
// Phase 65.5: TypeHintPolicy 使用(箱化モジュール)
|
||||
// Phase 67: P3-C 経路を GenericTypeResolver に委譲
|
||||
let hint = if TypeHintPolicy::is_target(&function.signature.name) {
|
||||
TypeHintPolicy::extract_phi_type_hint(&function, *v)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(mt) = crate::mir::phi_core::if_phi::infer_type_from_phi_with_hint(
|
||||
hint, // Phase 63-6-3: P1 の場合は PHI の type_hint、それ以外は None
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
) {
|
||||
// Phase 67: P3-C 対象なら GenericTypeResolver を優先使用
|
||||
if hint.is_none() && TypeHintPolicy::is_p3c_target(&function.signature.name) {
|
||||
if let Some(mt) = GenericTypeResolver::resolve_from_phi(
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
) {
|
||||
if std::env::var("NYASH_P3C_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[lifecycle/p3c] {} type inferred via GenericTypeResolver: {:?}",
|
||||
function.signature.name, mt
|
||||
);
|
||||
}
|
||||
inferred = Some(mt);
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
if let Some(mt) =
|
||||
crate::mir::phi_core::if_phi::infer_type_from_phi_with_hint(
|
||||
hint, // Phase 63-6-3: P1 の場合は PHI の type_hint、それ以外は None
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
)
|
||||
{
|
||||
inferred = Some(mt);
|
||||
break 'outer;
|
||||
}
|
||||
@ -312,11 +334,29 @@ impl super::MirBuilder {
|
||||
break;
|
||||
}
|
||||
// Phase 65.5: TypeHintPolicy 使用(箱化モジュール)
|
||||
// Phase 67: P3-C 経路を GenericTypeResolver に委譲
|
||||
let hint = if TypeHintPolicy::is_target(&function.signature.name) {
|
||||
TypeHintPolicy::extract_phi_type_hint(&function, *v)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Phase 67: P3-C 対象なら GenericTypeResolver を優先使用
|
||||
if hint.is_none() && TypeHintPolicy::is_p3c_target(&function.signature.name) {
|
||||
if let Some(mt) = GenericTypeResolver::resolve_from_phi(
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
) {
|
||||
if std::env::var("NYASH_P3C_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[lifecycle/p3c] {} type inferred via GenericTypeResolver: {:?}",
|
||||
function.signature.name, mt
|
||||
);
|
||||
}
|
||||
inferred = Some(mt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(mt) = crate::mir::phi_core::if_phi::infer_type_from_phi_with_hint(
|
||||
hint, // Phase 63-6-3: P1 の場合は PHI の type_hint、それ以外は None
|
||||
&function,
|
||||
|
||||
204
src/mir/join_ir/lowering/generic_type_resolver.rs
Normal file
204
src/mir/join_ir/lowering/generic_type_resolver.rs
Normal file
@ -0,0 +1,204 @@
|
||||
// Phase 66: P3-C ジェネリック型推論箱
|
||||
//
|
||||
// ArrayBox.get, MapBox.get などのジェネリック型を持つメソッドの
|
||||
// 戻り値型を推論する。
|
||||
//
|
||||
// # 責務
|
||||
//
|
||||
// - P3-C 対象メソッドの判定
|
||||
// - コンテナ使用文脈からの型推論(PHI 解析フォールバック)
|
||||
// - 将来の型変数システム導入の土台
|
||||
//
|
||||
// # 設計原則(箱理論)
|
||||
//
|
||||
// - **単一責務**: P3-C ジェネリック型推論のみ
|
||||
// - **質問箱**: is_generic_method() / resolve_generic_type() で判定
|
||||
// - **if_phi.rs 依存削減**: infer_type_from_phi を内部に取り込み
|
||||
|
||||
use crate::mir::{MirFunction, MirInstruction, MirType, ValueId};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Phase 66: ジェネリック型推論箱
|
||||
///
|
||||
/// # 対象パターン(P3-C)
|
||||
///
|
||||
/// - `ArrayBox.get(index)` → 配列要素の型(T)
|
||||
/// - `ArrayBox.pop()` → 配列要素の型(T)
|
||||
/// - `MapBox.get(key)` → マップ値の型(V)
|
||||
///
|
||||
/// # Phase 65 との関係
|
||||
///
|
||||
/// Phase 65 で P1/P2/P3-A/P3-B は JoinIR 型ヒント経路に移行完了。
|
||||
/// この箱は **P3-C 専用** として設計し、TypeHintPolicy と連携する。
|
||||
///
|
||||
/// # 将来拡張(Phase 67+)
|
||||
///
|
||||
/// - 型変数システム(`T`, `V` の明示的な型パラメータ)
|
||||
/// - コンテナ生成時の型推論(`new ArrayBox<StringBox>()`)
|
||||
pub struct GenericTypeResolver;
|
||||
|
||||
impl GenericTypeResolver {
|
||||
/// P3-C 対象メソッドかどうかを判定
|
||||
///
|
||||
/// # 引数
|
||||
/// - `receiver_type`: 受け手の型
|
||||
/// - `method_name`: メソッド名
|
||||
///
|
||||
/// # 戻り値
|
||||
/// - `true`: ジェネリック型推論が必要なメソッド
|
||||
/// - `false`: P3-A/P3-B で処理可能、または未対応
|
||||
pub fn is_generic_method(receiver_type: &MirType, method_name: &str) -> bool {
|
||||
match receiver_type {
|
||||
MirType::Box(box_name) => match box_name.as_str() {
|
||||
"ArrayBox" => matches!(method_name, "get" | "pop" | "first" | "last"),
|
||||
"MapBox" => matches!(method_name, "get"),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// P3-C 対象関数かどうかを判定(TypeHintPolicy 連携用)
|
||||
///
|
||||
/// # 用途
|
||||
///
|
||||
/// TypeHintPolicy.is_target() で P1/P2/P3-A/P3-B に該当しない場合、
|
||||
/// この関数で P3-C 候補かどうかを判定する。
|
||||
///
|
||||
/// # 現在の実装
|
||||
///
|
||||
/// ArrayBox/MapBox を使用する関数を P3-C 候補として判定。
|
||||
/// 関数名ベースのフィルタリングは行わない(汎用判定)。
|
||||
pub fn is_p3c_candidate(func_name: &str) -> bool {
|
||||
// Phase 66: 現在は全関数を P3-C 候補とみなす
|
||||
// 将来的に関数内の ArrayBox.get/MapBox.get 使用を解析して判定
|
||||
!func_name.is_empty() // 常に true(P1/P2/P3-A/B 以外は全て P3-C 候補)
|
||||
}
|
||||
|
||||
/// PHI 解析によるジェネリック型推論
|
||||
///
|
||||
/// # 責務
|
||||
///
|
||||
/// P3-C メソッド(ArrayBox.get, MapBox.get など)の戻り値型を
|
||||
/// PHI 命令の incoming 値から推論する。
|
||||
///
|
||||
/// # アルゴリズム
|
||||
///
|
||||
/// 1. ret_val を定義する PHI 命令を探索
|
||||
/// 2. PHI の incoming 値の型を types マップから取得
|
||||
/// 3. 全ての incoming 値が同じ型なら、その型を返す
|
||||
///
|
||||
/// # Phase 65 との違い
|
||||
///
|
||||
/// - if_phi.rs::infer_type_from_phi() と同等のロジック
|
||||
/// - P3-C 専用として明示的に責務を限定
|
||||
/// - 将来的に型変数システムで置き換え予定
|
||||
pub fn resolve_from_phi(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
types: &BTreeMap<ValueId, MirType>,
|
||||
) -> Option<MirType> {
|
||||
for (_bid, bb) in function.blocks.iter() {
|
||||
for inst in bb.instructions.iter() {
|
||||
if let MirInstruction::Phi { dst, inputs, .. } = inst {
|
||||
if *dst == ret_val {
|
||||
let mut it = inputs.iter().filter_map(|(_, v)| types.get(v));
|
||||
if let Some(first) = it.next() {
|
||||
if it.all(|mt| mt == first) {
|
||||
return Some(first.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// PHI の type_hint から型を抽出(将来拡張用)
|
||||
///
|
||||
/// # Phase 66 現在
|
||||
///
|
||||
/// P3-C メソッドは JoinIR で type_hint を設定しないため、
|
||||
/// この関数は現在使用されない。
|
||||
///
|
||||
/// # Phase 67+ 拡張
|
||||
///
|
||||
/// 型変数システム導入後、ArrayBox<T>.get() の T を
|
||||
/// type_hint として伝播する際に使用。
|
||||
#[allow(dead_code)]
|
||||
pub fn extract_type_hint(function: &MirFunction, ret_val: ValueId) -> Option<MirType> {
|
||||
function
|
||||
.blocks
|
||||
.values()
|
||||
.flat_map(|bb| &bb.instructions)
|
||||
.find_map(|inst| {
|
||||
if let MirInstruction::Phi { dst, type_hint, .. } = inst {
|
||||
if *dst == ret_val {
|
||||
return type_hint.clone();
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_is_generic_method_arraybox() {
|
||||
let array_type = MirType::Box("ArrayBox".to_string());
|
||||
|
||||
// P3-C 対象
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "get"));
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "pop"));
|
||||
assert!(GenericTypeResolver::is_generic_method(
|
||||
&array_type,
|
||||
"first"
|
||||
));
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "last"));
|
||||
|
||||
// P3-A/P3-B 対象(非 P3-C)
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "size"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "push"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_generic_method_mapbox() {
|
||||
let map_type = MirType::Box("MapBox".to_string());
|
||||
|
||||
// P3-C 対象
|
||||
assert!(GenericTypeResolver::is_generic_method(&map_type, "get"));
|
||||
|
||||
// P3-A/P3-B 対象(非 P3-C)
|
||||
assert!(!GenericTypeResolver::is_generic_method(&map_type, "size"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&map_type, "has"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_generic_method_stringbox() {
|
||||
// StringBox は P3-A で処理済み
|
||||
assert!(!GenericTypeResolver::is_generic_method(
|
||||
&MirType::String,
|
||||
"substring"
|
||||
));
|
||||
assert!(!GenericTypeResolver::is_generic_method(
|
||||
&MirType::String,
|
||||
"length"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_p3c_candidate() {
|
||||
// 全関数が P3-C 候補(P1/P2/P3-A/B 以外)
|
||||
assert!(GenericTypeResolver::is_p3c_candidate("Main.main/0"));
|
||||
assert!(GenericTypeResolver::is_p3c_candidate(
|
||||
"FuncScanner.parse/1"
|
||||
));
|
||||
|
||||
// 空文字列は false
|
||||
assert!(!GenericTypeResolver::is_p3c_candidate(""));
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,7 @@ pub mod stageb_body;
|
||||
pub mod stageb_funcscanner;
|
||||
pub mod type_hint_policy; // Phase 65.5: 型ヒントポリシー箱化
|
||||
pub mod type_inference; // Phase 65-2-A
|
||||
pub mod generic_type_resolver; // Phase 66: P3-C ジェネリック型推論箱
|
||||
pub mod value_id_ranges;
|
||||
|
||||
// Re-export public lowering functions
|
||||
|
||||
@ -88,8 +88,23 @@ impl TypeHintPolicy {
|
||||
func_name.starts_with("NewBoxTest.")
|
||||
}
|
||||
|
||||
// Phase 66+ で P3-C(ジェネリック型推論)追加予定
|
||||
// fn is_p3c_target(func_name: &str) -> bool { ... }
|
||||
/// P3-C: ジェネリック型推論対象判定(Phase 66)
|
||||
///
|
||||
/// # 対象
|
||||
/// - P1/P2/P3-A/P3-B 以外のすべての関数
|
||||
/// - ArrayBox.get, MapBox.get などを使用する可能性がある関数
|
||||
///
|
||||
/// # Phase 66 設計
|
||||
/// - GenericTypeResolver と連携して P3-C 型推論を実行
|
||||
/// - is_target() が false の場合のフォールバック経路
|
||||
pub fn is_p3c_target(func_name: &str) -> bool {
|
||||
// P1/P2/P3-A/P3-B に該当しない場合は P3-C 候補
|
||||
!Self::is_p1_target(func_name)
|
||||
&& !Self::is_p2_target(func_name)
|
||||
&& !Self::is_p3a_target(func_name)
|
||||
&& !Self::is_p3b_target(func_name)
|
||||
&& !func_name.is_empty()
|
||||
}
|
||||
|
||||
/// PHI 命令から型ヒントを抽出
|
||||
///
|
||||
@ -104,10 +119,7 @@ impl TypeHintPolicy {
|
||||
/// # Phase
|
||||
/// - Phase 63-6 で導入
|
||||
/// - Phase 65.5 で箱化・関数型スタイルに改善
|
||||
pub fn extract_phi_type_hint(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
) -> Option<MirType> {
|
||||
pub fn extract_phi_type_hint(function: &MirFunction, ret_val: ValueId) -> Option<MirType> {
|
||||
function
|
||||
.blocks
|
||||
.values()
|
||||
@ -157,7 +169,9 @@ mod tests {
|
||||
fn test_is_p3a_target() {
|
||||
// P3-A: read_quoted 系関数
|
||||
assert!(TypeHintPolicy::is_p3a_target("read_quoted_from/1"));
|
||||
assert!(TypeHintPolicy::is_p3a_target("FuncScannerBox.read_quoted/1"));
|
||||
assert!(TypeHintPolicy::is_p3a_target(
|
||||
"FuncScannerBox.read_quoted/1"
|
||||
));
|
||||
|
||||
// P3-A 以外
|
||||
assert!(!TypeHintPolicy::is_p3a_target("IfSelectTest.simple/0"));
|
||||
@ -203,4 +217,36 @@ mod tests {
|
||||
// どちらかに該当すれば is_target() は true
|
||||
assert!(TypeHintPolicy::is_target("read_quoted_from/1"));
|
||||
}
|
||||
|
||||
/// Phase 66: P3-C パターン判定テスト
|
||||
#[test]
|
||||
fn test_is_p3c_target() {
|
||||
// P3-C: P1/P2/P3-A/P3-B 以外
|
||||
assert!(TypeHintPolicy::is_p3c_target("Main.main/0"));
|
||||
assert!(TypeHintPolicy::is_p3c_target("SomeBox.some_method/3"));
|
||||
assert!(TypeHintPolicy::is_p3c_target("ArrayProcessor.process/1"));
|
||||
|
||||
// P1/P2/P3-A/P3-B は P3-C ではない
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfSelectTest.simple/0")); // P1
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfMergeTest.simple/0")); // P2
|
||||
assert!(!TypeHintPolicy::is_p3c_target("read_quoted_from/1")); // P3-A
|
||||
assert!(!TypeHintPolicy::is_p3c_target("NewBoxTest.array/0")); // P3-B
|
||||
|
||||
// 空文字列は false
|
||||
assert!(!TypeHintPolicy::is_p3c_target(""));
|
||||
}
|
||||
|
||||
/// Phase 66: is_target と is_p3c_target の排他性確認
|
||||
#[test]
|
||||
fn test_is_target_and_p3c_mutually_exclusive() {
|
||||
// is_target() が true なら is_p3c_target() は false
|
||||
let p1_func = "IfSelectTest.simple/0";
|
||||
assert!(TypeHintPolicy::is_target(p1_func));
|
||||
assert!(!TypeHintPolicy::is_p3c_target(p1_func));
|
||||
|
||||
// is_target() が false なら is_p3c_target() は true
|
||||
let general_func = "Main.main/0";
|
||||
assert!(!TypeHintPolicy::is_target(general_func));
|
||||
assert!(TypeHintPolicy::is_p3c_target(general_func));
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ pub mod namingbox_static_method_id; // Phase 21.7++ Phase 1: StaticMethodId stru
|
||||
pub mod nyash_abi_basic;
|
||||
pub mod parser;
|
||||
pub mod phase61_if_in_loop_dryrun; // Phase 61-2: If-in-loop JoinIR dry-run tests
|
||||
pub mod phase67_generic_type_resolver; // Phase 67: P3-C GenericTypeResolver tests
|
||||
pub mod plugin_hygiene;
|
||||
pub mod policy_mutdeny;
|
||||
pub mod refcell_assignment_test;
|
||||
|
||||
144
src/tests/phase67_generic_type_resolver.rs
Normal file
144
src/tests/phase67_generic_type_resolver.rs
Normal file
@ -0,0 +1,144 @@
|
||||
//! Phase 67: P3-C GenericTypeResolver 実利用テスト
|
||||
//!
|
||||
//! ArrayBox.get / MapBox.get などのジェネリック型メソッドの
|
||||
//! 型推論が GenericTypeResolver 経由で正しく動作することを検証。
|
||||
//!
|
||||
//! # テスト方針
|
||||
//!
|
||||
//! 1. MIR を直接構築して if 文 + ArrayBox.get パターンを作成
|
||||
//! 2. lifecycle.rs での型推論が正しく動作することを確認
|
||||
//! 3. A/B テスト:旧経路と新経路で同じ結果になることを検証
|
||||
|
||||
use crate::mir::join_ir::lowering::generic_type_resolver::GenericTypeResolver;
|
||||
use crate::mir::join_ir::lowering::type_hint_policy::TypeHintPolicy;
|
||||
use crate::mir::MirType;
|
||||
|
||||
/// Phase 67-1: GenericTypeResolver の基本判定テスト
|
||||
#[test]
|
||||
fn phase67_generic_type_resolver_is_generic_method() {
|
||||
let array_type = MirType::Box("ArrayBox".to_string());
|
||||
let map_type = MirType::Box("MapBox".to_string());
|
||||
|
||||
// P3-C 対象メソッド(ジェネリック型)
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "get"));
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "pop"));
|
||||
assert!(GenericTypeResolver::is_generic_method(&map_type, "get"));
|
||||
|
||||
// P3-A/P3-B 対象(非ジェネリック)
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "size"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "push"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&map_type, "has"));
|
||||
}
|
||||
|
||||
/// Phase 67-1: TypeHintPolicy と GenericTypeResolver の連携テスト
|
||||
#[test]
|
||||
fn phase67_type_hint_policy_p3c_integration() {
|
||||
// P1/P2/P3-A/P3-B 対象関数は P3-C ではない
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfSelectTest.simple/0")); // P1
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfMergeTest.simple/0")); // P2
|
||||
assert!(!TypeHintPolicy::is_p3c_target("read_quoted_from/1")); // P3-A
|
||||
assert!(!TypeHintPolicy::is_p3c_target("NewBoxTest.array/0")); // P3-B
|
||||
|
||||
// 一般関数は P3-C 候補
|
||||
assert!(TypeHintPolicy::is_p3c_target("ArrayProcessor.process/1"));
|
||||
assert!(TypeHintPolicy::is_p3c_target("GenericTypeGetTest.array_get/0"));
|
||||
|
||||
// is_target と is_p3c_target は排他的
|
||||
let p3c_func = "GenericTypeGetTest.array_get/0";
|
||||
assert!(!TypeHintPolicy::is_target(p3c_func));
|
||||
assert!(TypeHintPolicy::is_p3c_target(p3c_func));
|
||||
}
|
||||
|
||||
/// Phase 67-3: A/B テスト準備 - 型推論経路の一致確認
|
||||
///
|
||||
/// GenericTypeResolver::resolve_from_phi() と
|
||||
/// if_phi::infer_type_from_phi() が同じ結果を返すことを確認
|
||||
#[test]
|
||||
fn phase67_ab_test_resolve_from_phi_equivalence() {
|
||||
use crate::mir::{
|
||||
BasicBlock, BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction,
|
||||
MirInstruction, ValueId,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// 簡単な PHI を含む MIR を構築
|
||||
// Block 0 (entry): branch to Block 1 or Block 2
|
||||
// Block 1 (then): v2 = 42, jump to Block 3
|
||||
// Block 2 (else): v3 = 0, jump to Block 3
|
||||
// Block 3 (merge): v4 = phi(v2, v3), return v4
|
||||
|
||||
let sig = FunctionSignature {
|
||||
name: "GenericTypeGetTest.simple_phi/0".into(),
|
||||
params: vec![],
|
||||
return_type: MirType::Unknown, // 型推論対象
|
||||
effects: EffectMask::PURE,
|
||||
};
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
|
||||
let entry = BasicBlockId::new(0);
|
||||
let then_bb = BasicBlockId::new(1);
|
||||
let else_bb = BasicBlockId::new(2);
|
||||
let merge_bb = BasicBlockId::new(3);
|
||||
|
||||
// Block 構築
|
||||
f.add_block(BasicBlock::new(then_bb));
|
||||
f.add_block(BasicBlock::new(else_bb));
|
||||
f.add_block(BasicBlock::new(merge_bb));
|
||||
|
||||
// Entry: condition + branch
|
||||
let cond = f.next_value_id();
|
||||
f.get_block_mut(entry)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Const {
|
||||
dst: cond,
|
||||
value: ConstValue::Bool(true),
|
||||
});
|
||||
f.get_block_mut(entry).unwrap().terminator = Some(MirInstruction::Branch {
|
||||
condition: cond,
|
||||
then_bb,
|
||||
else_bb,
|
||||
});
|
||||
|
||||
// Then: v2 = 42
|
||||
let v2 = f.next_value_id();
|
||||
f.get_block_mut(then_bb)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Const {
|
||||
dst: v2,
|
||||
value: ConstValue::Integer(42),
|
||||
});
|
||||
f.get_block_mut(then_bb).unwrap().terminator = Some(MirInstruction::Jump { target: merge_bb });
|
||||
|
||||
// Else: v3 = 0
|
||||
let v3 = f.next_value_id();
|
||||
f.get_block_mut(else_bb)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Const {
|
||||
dst: v3,
|
||||
value: ConstValue::Integer(0),
|
||||
});
|
||||
f.get_block_mut(else_bb).unwrap().terminator = Some(MirInstruction::Jump { target: merge_bb });
|
||||
|
||||
// Merge: v4 = phi(v2 from then, v3 from else)
|
||||
let v4 = f.next_value_id();
|
||||
f.get_block_mut(merge_bb)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Phi {
|
||||
dst: v4,
|
||||
inputs: vec![(then_bb, v2), (else_bb, v3)],
|
||||
type_hint: None, // P3-C: type_hint なし
|
||||
});
|
||||
f.get_block_mut(merge_bb).unwrap().terminator = Some(MirInstruction::Return { value: Some(v4) });
|
||||
|
||||
// 型情報を設定
|
||||
let mut types: BTreeMap<ValueId, MirType> = BTreeMap::new();
|
||||
types.insert(v2, MirType::Integer);
|
||||
types.insert(v3, MirType::Integer);
|
||||
|
||||
// A/B テスト: 両方の経路で同じ結果を返すことを確認
|
||||
let result_a = crate::mir::phi_core::if_phi::infer_type_from_phi(&f, v4, &types);
|
||||
let result_b = GenericTypeResolver::resolve_from_phi(&f, v4, &types);
|
||||
|
||||
assert_eq!(result_a, result_b, "A/B test: both routes should return the same type");
|
||||
assert_eq!(result_a, Some(MirType::Integer), "Type should be inferred as Integer");
|
||||
}
|
||||
Reference in New Issue
Block a user