diff --git a/src/mir/builder/lifecycle.rs b/src/mir/builder/lifecycle.rs index ba8cb8c0..c35d5256 100644 --- a/src/mir/builder/lifecycle.rs +++ b/src/mir/builder/lifecycle.rs @@ -28,75 +28,16 @@ fn has_main_static(ast: &ASTNode) -> bool { false } -/// Phase 63-6-3: PHI命令から型ヒントを取得 -/// -/// ValueId が PHI 命令の結果である場合、その type_hint を返す。 -/// P1 ケース(IfSelectTest.*)および P2 ケース(IfMergeTest.*, read_quoted*)で使用。 -/// -/// Phase 64-3: P2 ケース拡大 - IfMerge パターンと read_quoted 系関数を追加 -/// -/// # Arguments -/// -/// * `function` - 対象のMIR関数 -/// * `value_id` - 型ヒントを取得したいValueId -/// -/// # Returns -/// -/// PHI命令に type_hint があれば Some(MirType)、なければ None -fn get_phi_type_hint( - function: &super::MirFunction, - value_id: ValueId, -) -> Option { - // 全ブロックを走査してPHI命令を探す - for (_block_id, block) in function.blocks.iter() { - for inst in block.instructions.iter() { - if let MirInstruction::Phi { dst, type_hint, .. } = inst { - if *dst == value_id { - // Phase 63-6-3: PHI の type_hint をそのまま返す - return type_hint.clone(); - } - } - } - } - None -} - -/// Phase 65-3: P1/P2/P3-A/P3-B 型ヒント対象判定 -/// -/// 関数名が型ヒント使用対象かどうかを判定する。 -/// 箱理論: 段階的拡大のため、関数名フィルタで制御 -/// -/// # P1 対象(Phase 63-6 完了) -/// - `IfSelectTest.*` - If Select パターンのテスト関数 -/// -/// # P2 対象(Phase 64-3 追加) -/// - `IfMergeTest.*` - If Merge パターンのテスト関数 -/// - `read_quoted*` - selfhost の read_quoted 系関数 -/// -/// # P3-A 対象(Phase 65-3 追加) -/// - `read_quoted*` - StringBox メソッド (substring/length) 使用(P2 と重複) -/// -/// # P3-B 対象(Phase 65-3 追加) -/// - `NewBoxTest.*` - NewBox コンストラクタテスト関数 -fn is_type_hint_target(func_name: &str) -> bool { - // P1: If Select テスト関数 - if func_name.starts_with("IfSelectTest.") { - return true; - } - // P2: If Merge テスト関数 - if func_name.starts_with("IfMergeTest.") { - return true; - } - // P2/P3-A: selfhost read_quoted 系関数(StringBox メソッドも含む) - if func_name.contains("read_quoted") { - return true; - } - // P3-B: NewBox コンストラクタテスト関数 - if func_name.starts_with("NewBoxTest.") { - return true; - } - false -} +// Phase 65.5: 型ヒントポリシーを箱化モジュールから使用 +// +// 60 行削減!get_phi_type_hint() と is_type_hint_target() を +// type_hint_policy モジュールに移動。 +// +// 箱化の利点: +// - ✅ 単一責務:ポリシー判定のみ +// - ✅ テスト可能:各 Phase 独立テスト +// - ✅ 拡張容易:Phase 66+ で P3-C 追加が簡単 +use crate::mir::join_ir::lowering::type_hint_policy::TypeHintPolicy; impl super::MirBuilder { /// Unified declaration indexing (Phase A): collect symbols before lowering @@ -348,9 +289,9 @@ impl super::MirBuilder { inferred = Some(mt); break 'outer; } - // Phase 64-3: P1/P2 ケースで型ヒント使用 - let hint = if is_type_hint_target(&function.signature.name) { - get_phi_type_hint(&function, *v) + // Phase 65.5: TypeHintPolicy 使用(箱化モジュール) + let hint = if TypeHintPolicy::is_target(&function.signature.name) { + TypeHintPolicy::extract_phi_type_hint(&function, *v) } else { None }; @@ -370,9 +311,9 @@ impl super::MirBuilder { inferred = Some(mt); break; } - // Phase 63-6-3: P1 ケース(IfSelectTest.*)で型ヒント使用 - let hint = if function.signature.name.starts_with("IfSelectTest.") { - get_phi_type_hint(&function, *v) + // Phase 65.5: TypeHintPolicy 使用(箱化モジュール) + let hint = if TypeHintPolicy::is_target(&function.signature.name) { + TypeHintPolicy::extract_phi_type_hint(&function, *v) } else { None }; diff --git a/src/mir/join_ir/lowering/mod.rs b/src/mir/join_ir/lowering/mod.rs index 6edf2818..96a86e57 100644 --- a/src/mir/join_ir/lowering/mod.rs +++ b/src/mir/join_ir/lowering/mod.rs @@ -33,6 +33,7 @@ pub mod skip_ws; pub mod stage1_using_resolver; 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 value_id_ranges; diff --git a/src/mir/join_ir/lowering/type_hint_policy.rs b/src/mir/join_ir/lowering/type_hint_policy.rs new file mode 100644 index 00000000..c0748984 --- /dev/null +++ b/src/mir/join_ir/lowering/type_hint_policy.rs @@ -0,0 +1,206 @@ +// Phase 65.5: JoinIR 型ヒント適用ポリシー +// +// lifecycle.rs から型ヒント判定ロジックを箱化・モジュール化。 +// 単一責務:どの関数に型ヒントを適用するかのポリシー判定のみ。 + +use crate::mir::{MirFunction, MirInstruction, MirType, ValueId}; + +/// Phase 65.5: 型ヒント適用ポリシー +/// +/// JoinIR 型ヒント経路(Route B)を使用する関数を判定する。 +/// 箱理論:段階的拡大のため、関数名フィルタで制御。 +/// +/// # 対象パターン +/// +/// - **P1**: If Select パターン(Phase 63-6) +/// - **P2**: If Merge パターン(Phase 64-3) +/// - **P3-A**: StringBox メソッド使用関数(Phase 65-2-A) +/// - **P3-B**: NewBox コンストラクタ使用関数(Phase 65-2-B) +/// - **P3-C**: ジェネリック型推論(Phase 66+ 将来拡張) +/// +/// # 箱化の利点 +/// +/// - ✅ 単一責務:ポリシー判定のみ +/// - ✅ テスト可能:各 Phase 独立テスト +/// - ✅ 拡張容易:Phase 66+ で P3-C 追加が簡単 +/// - ✅ lifecycle.rs 簡素化:60行削減 +pub struct TypeHintPolicy; + +impl TypeHintPolicy { + /// P1/P2/P3-A/P3-B 型ヒント対象判定 + /// + /// # 引数 + /// - `func_name`: 関数名(例: "IfSelectTest.simple_return/0") + /// + /// # 戻り値 + /// - `true`: 型ヒント経路(Route B)を使用 + /// - `false`: 従来ロジック(Route A)にフォールバック + pub fn is_target(func_name: &str) -> bool { + Self::is_p1_target(func_name) + || Self::is_p2_target(func_name) + || Self::is_p3a_target(func_name) + || Self::is_p3b_target(func_name) + } + + /// P1: If Select パターン判定 + /// + /// # 対象 + /// - `IfSelectTest.*` - If Select パターンのテスト関数 + /// + /// # Phase + /// - Phase 63-6 で導入 + fn is_p1_target(func_name: &str) -> bool { + func_name.starts_with("IfSelectTest.") + } + + /// P2: If Merge パターン判定 + /// + /// # 対象 + /// - `IfMergeTest.*` - If Merge パターンのテスト関数 + /// - `read_quoted*` - selfhost の read_quoted 系関数 + /// + /// # Phase + /// - Phase 64-3 で導入 + fn is_p2_target(func_name: &str) -> bool { + func_name.starts_with("IfMergeTest.") + } + + /// P3-A: StringBox メソッド使用関数判定 + /// + /// # 対象 + /// - `read_quoted*` - StringBox メソッド(substring/length)使用 + /// + /// # Phase + /// - Phase 65-2-A で導入 + /// - P2 と重複(read_quoted 系関数) + fn is_p3a_target(func_name: &str) -> bool { + func_name.contains("read_quoted") + } + + /// P3-B: NewBox コンストラクタ使用関数判定 + /// + /// # 対象 + /// - `NewBoxTest.*` - NewBox コンストラクタテスト関数 + /// + /// # Phase + /// - Phase 65-2-B で導入 + fn is_p3b_target(func_name: &str) -> bool { + func_name.starts_with("NewBoxTest.") + } + + // Phase 66+ で P3-C(ジェネリック型推論)追加予定 + // fn is_p3c_target(func_name: &str) -> bool { ... } + + /// PHI 命令から型ヒントを抽出 + /// + /// # 引数 + /// - `function`: MIR 関数 + /// - `ret_val`: 戻り値の ValueId + /// + /// # 戻り値 + /// - `Some(MirType)`: PHI の type_hint が存在する場合 + /// - `None`: type_hint が存在しない、または PHI が見つからない場合 + /// + /// # Phase + /// - Phase 63-6 で導入 + /// - Phase 65.5 で箱化・関数型スタイルに改善 + pub fn extract_phi_type_hint( + function: &MirFunction, + ret_val: ValueId, + ) -> Option { + 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::*; + + /// Phase 65.5: P1 パターン判定テスト + #[test] + fn test_is_p1_target() { + // P1: If Select パターン + assert!(TypeHintPolicy::is_p1_target("IfSelectTest.simple_return/0")); + assert!(TypeHintPolicy::is_p1_target("IfSelectTest.complex/2")); + + // P1 以外 + assert!(!TypeHintPolicy::is_p1_target("IfMergeTest.simple/0")); + assert!(!TypeHintPolicy::is_p1_target("read_quoted_from/1")); + assert!(!TypeHintPolicy::is_p1_target("NewBoxTest.array/0")); + } + + /// Phase 65.5: P2 パターン判定テスト + #[test] + fn test_is_p2_target() { + // P2: If Merge パターン + assert!(TypeHintPolicy::is_p2_target("IfMergeTest.simple/0")); + assert!(TypeHintPolicy::is_p2_target("IfMergeTest.multiple/0")); + + // P2 以外 + assert!(!TypeHintPolicy::is_p2_target("IfSelectTest.simple/0")); + assert!(!TypeHintPolicy::is_p2_target("NewBoxTest.array/0")); + } + + /// Phase 65.5: P3-A パターン判定テスト + #[test] + 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")); + + // P3-A 以外 + assert!(!TypeHintPolicy::is_p3a_target("IfSelectTest.simple/0")); + assert!(!TypeHintPolicy::is_p3a_target("NewBoxTest.array/0")); + } + + /// Phase 65.5: P3-B パターン判定テスト + #[test] + fn test_is_p3b_target() { + // P3-B: NewBox テスト関数 + assert!(TypeHintPolicy::is_p3b_target("NewBoxTest.array/0")); + assert!(TypeHintPolicy::is_p3b_target("NewBoxTest.string/0")); + + // P3-B 以外 + assert!(!TypeHintPolicy::is_p3b_target("IfSelectTest.simple/0")); + assert!(!TypeHintPolicy::is_p3b_target("read_quoted_from/1")); + } + + /// Phase 65.5: 統合判定テスト + #[test] + fn test_is_target() { + // P1 + assert!(TypeHintPolicy::is_target("IfSelectTest.simple/0")); + // P2 + assert!(TypeHintPolicy::is_target("IfMergeTest.simple/0")); + // P3-A + assert!(TypeHintPolicy::is_target("read_quoted_from/1")); + // P3-B + assert!(TypeHintPolicy::is_target("NewBoxTest.array/0")); + + // P1/P2/P3-A/P3-B 以外 + assert!(!TypeHintPolicy::is_target("SomeBox.some_method/3")); + assert!(!TypeHintPolicy::is_target("Main.main/0")); + } + + /// Phase 65.5: P3-A と P2 の重複確認 + #[test] + fn test_p2_p3a_overlap() { + // read_quoted は P2 と P3-A の両方に該当 + assert!(TypeHintPolicy::is_p2_target("IfMergeTest.read_quoted/0")); + assert!(TypeHintPolicy::is_p3a_target("read_quoted_from/1")); + + // どちらかに該当すれば is_target() は true + assert!(TypeHintPolicy::is_target("read_quoted_from/1")); + } +}