diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index e44122e6..acaa6aff 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -183,8 +183,35 @@ - PhiBuilderBox ベースの PhiSpec 観察用関数(`extract_phi_spec_from_builder`, `compare_and_log_phi_specs` など)を削除し、PHI 仕様計算を JoinIR 起点の `compute_phi_spec_from_joinir` に一本化。 - 合計約 97 行削減(予想 76 行を超過)。If 側 PHI の「観察・比較」は JoinIR 情報から復元する経路のみとなり、if_phi/PhiBuilderBox は本番ロジックに専念する構造に整理された。 +### 1-00h. Phase 62 — PHI Core Cleanup(phi_core 小箱クリーンアップ) + +- 目的: PHI 箱のうち、既に機能が JoinIR/loopform/phi_merge 側に移っていて「殻だけ残っていた」小箱を片付け、phi_core 直下の実コードをさらに減らす。 +- 実績: + - `phi_core/phi_input_collector.rs` を削除。Phase 59/59b で loopform_builder.rs / loop_builder.rs へのインライン化が完了しており、外部依存 0 であることを PHI_BOX_INVENTORY ベースで確認済み。 + - `phi_core/conservative.rs` を 57 行すべてコメントのみの「歴史メモ」ファイルに縮退(実コードは Phase 58 で `phi_merge.rs::merge_all_vars` 側にインライン済み)。将来的に docs/ への移設候補として扱う。 + - PHI_BOX_INVENTORY.md / phi-reduction-series/INDEX.md / CURRENT_TASK.md を更新し、「PhiInputCollector 削除済み」「ConservativeMerge 本体は inline 済みで conservative.rs は docs 専用」という現状を明示。 + - JoinIR/phi_core 関連テストは全て PASS。既知の `local` キーワード問題を除き、新たな退行はなし。 +### 1-00i. Phase 63-3 — JoinIR 型ヒントの最小配線 + +- 目的: infer_type_from_phi を削る前に、「JoinIR 側で MirType をどこに持てばよいか」を決め、そのための schema 変更と最小限のコード更新を行う。 +- 実績: + - `JoinInst::Select` と `MergePair` に `type_hint: Option` を追加し、If PHI に関わる値まわりに型ヒントをぶら下げる足場を用意した。 + - Select / MergePair を生成する全サイト(if_select.rs / if_merge.rs / nested_if.rs / read_quoted.rs など 13 ファイル)を更新し、新フィールドを一旦 `type_hint: None` で埋めてビルドが通る状態に統一。 + - JoinIR 関連テスト(IfSelect/IfMerge/Frontend 系)はすべて PASS。挙動は従来どおりだが、今後 AST/Frontend/Bridge から型ヒントを流し込む準備が整った。 + +### 1-00j. Phase 63-4 — infer_type_from_phi 縮退設計(設計のみ) + +- 目的: infer_type_from_phi を『JoinIR 型ヒント優先+従来ロジックフォールバック』に縮退する仕様を docs に固定(実装は Phase 63-5+)。 +- 実績: + - 63-4.1: infer_type_from_phi の現状整理(定義場所 / 呼び出し元 / 役割 / JoinIR 準備状況)を文書化。 + - 63-4.2: 縮退後の仕様設計(type_hint がある場合は優先、ない場合は従来ロジックへフォールバック)。 + - 63-4.3: 代表ケースと A/B テスト方針(P1: IfSelectTest.simple/local, P2: read_quoted_from, P3: MethodCall/Box コンストラクタ)を整理。 + - 63-4.4: 削除条件の明確化(5条件、現時点達成率 2/5 = 40%)。 + - 63-4.5: Phase 63-5 への引き継ぎ(infer_type_from_phi_with_hint() 実装タスク定義)。 +- docs: `docs/private/roadmap2/phases/phase-63-joinir-type-info/README.md`, `PHI_BOX_INVENTORY.md` 更新済み + --- ## 2. 中期 TODO(ざっくり) diff --git a/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_both.rs b/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_both.rs index f45635f8..231ffdfb 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_both.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_both.rs @@ -42,6 +42,7 @@ pub fn lower( cond: cond_id, then_val, else_val, + type_hint: None, // Phase 63-3 }); ctx.register_param(var_name.to_string(), result_id); diff --git a/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_then.rs b/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_then.rs index 18f2b1c5..39885e98 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_then.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/if_in_loop/lowering/single_var_then.rs @@ -40,6 +40,7 @@ pub fn lower( cond: cond_id, then_val, else_val, + type_hint: None, // Phase 63-3 }); ctx.register_param(var_name.to_string(), result_id); diff --git a/src/mir/join_ir/frontend/ast_lowerer/if_return.rs b/src/mir/join_ir/frontend/ast_lowerer/if_return.rs index 9b27dd9b..24bec5a8 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/if_return.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/if_return.rs @@ -128,6 +128,7 @@ impl AstToJoinIrLowerer { cond: cond_var, then_val: then_var, else_val: else_var, + type_hint: None, // Phase 63-3 }); // Ret result diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs index a4a194bc..5654cc69 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns/continue_pattern.rs @@ -212,6 +212,7 @@ fn create_loop_step_function_continue( cond: continue_cond_var, then_val: step_acc, // Continue: 更新しない else_val: acc_increment, // 通常: 更新 + type_hint: None, // Phase 63-3 }); // 6. 末尾再帰 diff --git a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns_old.rs b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns_old.rs index af9d405d..771ad0f6 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/loop_patterns_old.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/loop_patterns_old.rs @@ -843,6 +843,7 @@ impl AstToJoinIrLowerer { cond: continue_cond_var, then_val: step_acc, // Continue: 更新しない else_val: acc_increment, // 通常: 更新 + type_hint: None, // Phase 63-3 }); // 6. 末尾再帰 diff --git a/src/mir/join_ir/frontend/ast_lowerer/nested_if.rs b/src/mir/join_ir/frontend/ast_lowerer/nested_if.rs index ebbb49b3..b48c8f3d 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/nested_if.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/nested_if.rs @@ -145,6 +145,7 @@ impl AstToJoinIrLowerer { dst, then_val: then_var, else_val: else_var, + type_hint: None, // Phase 63-3 }); } diff --git a/src/mir/join_ir/frontend/ast_lowerer/read_quoted.rs b/src/mir/join_ir/frontend/ast_lowerer/read_quoted.rs index 07e37a0f..57cddfe3 100644 --- a/src/mir/join_ir/frontend/ast_lowerer/read_quoted.rs +++ b/src/mir/join_ir/frontend/ast_lowerer/read_quoted.rs @@ -403,11 +403,13 @@ impl AstToJoinIrLowerer { dst: i_after_esc, then_val: i_esc, else_val: step_i, + type_hint: None, // Phase 63-3 }, MergePair { dst: ch_merged, then_val: ch_esc, else_val: step_ch, + type_hint: None, // Phase 63-3 }, ], k_next: None, diff --git a/src/mir/join_ir/json.rs b/src/mir/join_ir/json.rs index e3746748..c80e30a1 100644 --- a/src/mir/join_ir/json.rs +++ b/src/mir/join_ir/json.rs @@ -142,12 +142,17 @@ fn write_inst(inst: &JoinInst, out: &mut W) -> std::io::Result<()> { cond, then_val, else_val, + type_hint, } => { write!(out, "{{\"type\":\"select\"")?; write!(out, ",\"dst\":{}", dst.0)?; write!(out, ",\"cond\":{}", cond.0)?; write!(out, ",\"then_val\":{}", then_val.0)?; write!(out, ",\"else_val\":{}", else_val.0)?; + // Phase 63-3: type_hint を JSON 出力(存在する場合のみ) + if let Some(ref th) = type_hint { + write!(out, ",\"type_hint\":\"{}\"", format!("{:?}", th))?; + } write!(out, "}}")?; } // Phase 33-6: IfMerge instruction JSON serialization @@ -577,11 +582,13 @@ mod tests { dst: ValueId(10), then_val: ValueId(20), else_val: ValueId(30), + type_hint: None, // Phase 63-3 }, MergePair { dst: ValueId(11), then_val: ValueId(21), else_val: ValueId(31), + type_hint: None, // Phase 63-3 }, ], k_next: None, diff --git a/src/mir/join_ir/lowering/if_merge.rs b/src/mir/join_ir/lowering/if_merge.rs index bdf90d5f..9194f6ec 100644 --- a/src/mir/join_ir/lowering/if_merge.rs +++ b/src/mir/join_ir/lowering/if_merge.rs @@ -202,6 +202,7 @@ impl IfMergeLowerer { dst, then_val, else_val, + type_hint: None, // Phase 63-3: 現時点では型ヒントなし }); } diff --git a/src/mir/join_ir/lowering/if_select.rs b/src/mir/join_ir/lowering/if_select.rs index b5aef67b..09173776 100644 --- a/src/mir/join_ir/lowering/if_select.rs +++ b/src/mir/join_ir/lowering/if_select.rs @@ -12,6 +12,8 @@ use crate::mir::join_ir::JoinInst; use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; +// Phase 63-2: Type hint inference from MIR +use crate::mir::{ConstValue, MirType}; // Phase 61-1: If-in-loop context support use super::if_phi_context::IfPhiContext; @@ -118,11 +120,16 @@ impl IfSelectLowerer { // Select 命令を生成 let dst = pattern.dst.unwrap_or(pattern.then_val); + // Phase 63-2: MIR の Const 命令から型ヒントを推論 + let type_hint = infer_type_from_mir_pattern(func, pattern.then_val) + .or_else(|| infer_type_from_mir_pattern(func, pattern.else_val)); + Some(JoinInst::Select { dst, cond: pattern.cond, then_val: pattern.then_val, else_val: pattern.else_val, + type_hint, // Phase 63-2: Const 命令から推論した型(Integer/Bool/String など) }) } @@ -364,3 +371,29 @@ impl IfSelectLowerer { }) } } + +/// Phase 63-2: MIR から ValueId の型を推論 +/// +/// Const 命令を探して、ValueId に対応する MirType を返す。 +/// Select の then_val / else_val から型ヒントを埋めるために使用。 +fn infer_type_from_mir_pattern(func: &MirFunction, val_id: ValueId) -> Option { + // 全ブロックの全命令を走査して Const 命令を探す + for block in func.blocks.values() { + for inst in &block.instructions { + if let MirInstruction::Const { dst, value } = inst { + if *dst == val_id { + return Some(match value { + ConstValue::Integer(_) => MirType::Integer, + ConstValue::Bool(_) => MirType::Bool, + ConstValue::String(_) => MirType::String, + ConstValue::Void => MirType::Void, + ConstValue::Null => MirType::Unknown, // Null は Unknown として扱う + // Float は現状未サポート + _ => return None, + }); + } + } + } + } + None +} diff --git a/src/mir/join_ir/mod.rs b/src/mir/join_ir/mod.rs index 2e0f26df..908d07ae 100644 --- a/src/mir/join_ir/mod.rs +++ b/src/mir/join_ir/mod.rs @@ -23,6 +23,8 @@ use std::collections::BTreeMap; use crate::mir::ValueId; +// Phase 63-3: 型ヒント用 +use crate::mir::MirType; // Phase 27.9: Lowering submodule pub mod lowering; @@ -206,6 +208,8 @@ pub struct MergePair { pub then_val: VarId, /// else 分岐での値 pub else_val: VarId, + /// Phase 63-3: 結果型ヒント(MIR PHI 生成時の型推論を回避) + pub type_hint: Option, } /// JoinIR 命令セット(最小版) @@ -296,11 +300,15 @@ pub enum JoinInst { /// Phase 33: If/Else の単純な値選択(単一値) /// cond が true なら then_val、false なら else_val を dst に代入 + /// + /// Phase 63-3: type_hint で結果型を伝播(infer_type_from_phi 削減用) Select { dst: VarId, cond: VarId, then_val: VarId, else_val: VarId, + /// Phase 63-3: 結果型ヒント(MIR PHI 生成時の型推論を回避) + type_hint: Option, }, /// Phase 33-6: If/Else の複数変数 merge diff --git a/src/mir/join_ir/verify.rs b/src/mir/join_ir/verify.rs index f57dd7d1..17ba164f 100644 --- a/src/mir/join_ir/verify.rs +++ b/src/mir/join_ir/verify.rs @@ -245,6 +245,7 @@ pub fn verify_select_minimal( cond, then_val, else_val, + type_hint: _, // Phase 63-3: 検証では未使用 } = select_inst.unwrap() else { unreachable!() diff --git a/src/mir/join_ir_runner.rs b/src/mir/join_ir_runner.rs index b5fcc4f2..6ff53a18 100644 --- a/src/mir/join_ir_runner.rs +++ b/src/mir/join_ir_runner.rs @@ -133,6 +133,7 @@ fn execute_function( cond, then_val, else_val, + type_hint: _, // Phase 63-3: 実行時は未使用 } => { // 1. Evaluate cond (Bool or Int) let cond_value = read_var(&locals, *cond)?; @@ -430,6 +431,7 @@ mod tests { cond: v_cond, then_val: v_then, else_val: v_else, + type_hint: None, // Phase 63-3 }); // return v4 @@ -481,6 +483,7 @@ mod tests { cond: v_cond, then_val: v_then, else_val: v_else, + type_hint: None, // Phase 63-3 }); // return v4 @@ -531,6 +534,7 @@ mod tests { cond: v_cond, then_val: v_then, else_val: v_else, + type_hint: None, // Phase 63-3 }); // return v4 @@ -600,11 +604,13 @@ mod tests { dst: v_result_x, then_val: v_then_x, else_val: v_else_x, + type_hint: None, // Phase 63-3 }, crate::mir::join_ir::MergePair { dst: v_result_y, then_val: v_then_y, else_val: v_else_y, + type_hint: None, // Phase 63-3 }, ], k_next: None, @@ -682,11 +688,13 @@ mod tests { dst: v_result_x, then_val: v_then_x, else_val: v_else_x, + type_hint: None, // Phase 63-3 }, crate::mir::join_ir::MergePair { dst: v_result_y, then_val: v_then_y, else_val: v_else_y, + type_hint: None, // Phase 63-3 }, ], k_next: None, @@ -771,16 +779,19 @@ mod tests { dst: v_result_x, then_val: v_then_x, else_val: v_else_x, + type_hint: None, // Phase 63-3 }, crate::mir::join_ir::MergePair { dst: v_result_y, then_val: v_then_y, else_val: v_else_y, + type_hint: None, // Phase 63-3 }, crate::mir::join_ir::MergePair { dst: v_result_z, then_val: v_then_z, else_val: v_else_z, + type_hint: None, // Phase 63-3 }, ], k_next: None, diff --git a/src/mir/join_ir_vm_bridge/convert.rs b/src/mir/join_ir_vm_bridge/convert.rs index db3b10e3..108f1a70 100644 --- a/src/mir/join_ir_vm_bridge/convert.rs +++ b/src/mir/join_ir_vm_bridge/convert.rs @@ -491,6 +491,7 @@ Call {{\n\ cond, then_val, else_val, + type_hint: _, // Phase 63-3: MIR変換では現時点で未使用 } => { // Phase 33-2: Select を MIR の if/phi に変換 // 最小実装: cond/then/else/merge の 4 ブロック構造 diff --git a/src/tests/mir_joinir_if_select.rs b/src/tests/mir_joinir_if_select.rs index f6760359..aef13d4d 100644 --- a/src/tests/mir_joinir_if_select.rs +++ b/src/tests/mir_joinir_if_select.rs @@ -145,6 +145,7 @@ mod tests { cond, then_val, else_val, + .. }) = result { eprintln!("✅ Simple pattern successfully lowered to Select"); @@ -171,6 +172,7 @@ mod tests { cond, then_val, else_val, + .. }) = result { eprintln!("✅ Local pattern successfully lowered to Select"); @@ -246,6 +248,7 @@ mod tests { cond: ValueId(0), then_val: ValueId(1), else_val: ValueId(2), + type_hint: None, // Phase 63-3 }); // Return result @@ -270,6 +273,7 @@ mod tests { cond: ValueId(0), then_val: ValueId(10), else_val: ValueId(20), + type_hint: None, // Phase 63-3 }); // Second Select (violates single PHI invariant) @@ -278,6 +282,7 @@ mod tests { cond: ValueId(0), then_val: ValueId(30), else_val: ValueId(40), + type_hint: None, // Phase 63-3 }); join_func.body.push(JoinInst::Ret { @@ -591,4 +596,88 @@ mod tests { std::env::remove_var("NYASH_JOINIR_IF_SELECT"); } + + /// Phase 63-2: Helper to create a simple pattern MIR with Const instructions + fn create_simple_pattern_mir_with_const() -> MirFunction { + let mut blocks = BTreeMap::new(); + + // Entry block (bb0): create const 10/20, then branch on cond + let mut entry = BasicBlock::new(BasicBlockId::new(0)); + entry.instructions.push(MirInstruction::Const { + dst: ValueId(1), + value: crate::mir::ConstValue::Integer(10), + }); + entry.instructions.push(MirInstruction::Const { + dst: ValueId(2), + value: crate::mir::ConstValue::Integer(20), + }); + entry.terminator = Some(MirInstruction::Branch { + condition: ValueId(0), // cond parameter + then_bb: BasicBlockId::new(1), + else_bb: BasicBlockId::new(2), + }); + blocks.insert(BasicBlockId::new(0), entry); + + // Then block (bb1): return 10 + let mut then_block = BasicBlock::new(BasicBlockId::new(1)); + then_block.terminator = Some(MirInstruction::Return { + value: Some(ValueId(1)), // const 10 + }); + blocks.insert(BasicBlockId::new(1), then_block); + + // Else block (bb2): return 20 + let mut else_block = BasicBlock::new(BasicBlockId::new(2)); + else_block.terminator = Some(MirInstruction::Return { + value: Some(ValueId(2)), // const 20 + }); + blocks.insert(BasicBlockId::new(2), else_block); + + use crate::mir::function::FunctionMetadata; + use crate::mir::{EffectMask, MirType}; + + MirFunction { + signature: crate::mir::FunctionSignature { + name: "IfSelectTest.test/1".to_string(), + params: vec![MirType::Unknown], + return_type: MirType::Integer, + effects: EffectMask::PURE, + }, + entry_block: BasicBlockId::new(0), + blocks: blocks.into_iter().collect(), + locals: vec![], + params: vec![ValueId(0)], + next_value_id: 3, + metadata: FunctionMetadata::default(), + } + } + + /// Phase 63-2: Test type hint propagation from MIR Const instructions + #[test] + fn test_type_hint_propagation_simple() { + use crate::mir::MirType; + + std::env::set_var("NYASH_JOINIR_IF_SELECT", "1"); + + let func = create_simple_pattern_mir_with_const(); + let entry_block = func.entry_block; + let result = try_lower_if_to_joinir(&func, entry_block, true, None); + + assert!( + result.is_some(), + "Expected simple pattern to be lowered to Select" + ); + + if let Some(JoinInst::Select { type_hint, .. }) = result { + assert_eq!( + type_hint, + Some(MirType::Integer), + "Expected type_hint to be Some(Integer) for IfSelectTest.simple (Const 10/20)" + ); + eprintln!("✅ Phase 63-2: Type hint propagation successful: {:?}", type_hint); + } else { + panic!("Expected Select instruction with type_hint"); + } + + std::env::remove_var("NYASH_JOINIR_IF_SELECT"); + } }