From 7603ef8a6a6ac09eeade23abf82c733b9928edb0 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Thu, 18 Dec 2025 04:50:32 +0900 Subject: [PATCH] feat(control_tree): emit Normalized JoinModule for if-only (dev-only) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 122 P1: StepTree→Normalized JoinModule generation - Generate env layout from writes (SSOT, deterministic) - Minimal implementation: main function + Ret only - Full If/Assign/Return lowering in future P2-P4 - Dev-only: no behavior change to existing path --- .../control_tree/normalized_shadow/builder.rs | 77 +++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/src/mir/control_tree/normalized_shadow/builder.rs b/src/mir/control_tree/normalized_shadow/builder.rs index 67c45612..2d734cda 100644 --- a/src/mir/control_tree/normalized_shadow/builder.rs +++ b/src/mir/control_tree/normalized_shadow/builder.rs @@ -36,6 +36,13 @@ impl StepTreeNormalizedShadowLowererBox { /// - Only processes if-only patterns (no loops/breaks/continues) /// - Uses contract information only (no AST re-analysis) /// - Dev-only: caller must check `joinir_dev_enabled()` before calling + /// + /// ## Phase 122 Implementation + /// + /// - Generates Normalized JoinIR (env + continuation) + /// - env layout: writes only (SSOT) + /// - merge = join_k(env) tail-call (no PHI) + /// - Minimal node support: If/Return/Assign(Const/Variable/BinOp(Add)) pub fn try_lower_if_only( step_tree: &StepTree, ) -> Result, String> { @@ -43,19 +50,77 @@ impl StepTreeNormalizedShadowLowererBox { let capability = check_if_only(step_tree); match capability { CapabilityCheckResult::Supported => { - // Phase 121 P1: For now, return empty module + empty meta - // Full lowering implementation in future phases - let module = JoinModule::new(); - let meta = JoinFragmentMeta::empty(); - Ok(Some((module, meta))) + // Phase 122 P1: Generate Normalized JoinModule + Self::lower_if_only_to_normalized(step_tree) + .map(Some) } CapabilityCheckResult::Unsupported(_reason) => { - // Out of scope for Phase 121 + // Out of scope for Phase 121/122 Ok(None) } } } + /// Lower if-only StepTree to Normalized JoinModule (Phase 122) + /// + /// ## Design + /// + /// - env レイアウト: `writes` に含まれる変数だけ(決定的順序) + /// - merge 形式: `join_k(env)` への tail-call(PHI 禁止) + /// - 対応ノード: If/Return/Assign(最小セット) + /// + /// ## Returns + /// + /// - `Ok((module, meta))`: Normalized JoinModule生成成功 + /// - `Err(msg)`: 生成できるはずなのに失敗(内部エラー) + fn lower_if_only_to_normalized( + step_tree: &StepTree, + ) -> Result<(JoinModule, JoinFragmentMeta), String> { + use crate::mir::join_ir::{JoinFunction, JoinFuncId, JoinInst}; + use crate::mir::ValueId; + use std::collections::BTreeMap; + + // Phase 122 P1: 最小実装 - main関数1つ + Ret のみ + // env レイアウト: writes から決定的に決める + let env_fields: Vec = step_tree.contract.writes.iter().cloned().collect(); + + // 関数ID生成(Phase 122では固定ID使用) + let main_func_id = JoinFuncId::new(0); + + // env フィールドに対応する引数ValueIdを生成 + let mut next_value_id = 1; + let env_params: Vec = env_fields + .iter() + .map(|_| { + let vid = ValueId(next_value_id); + next_value_id += 1; + vid + }) + .collect(); + + // main 関数生成(最小: Ret のみ) + let mut main_func = JoinFunction::new( + main_func_id, + "main".to_string(), + env_params.clone(), + ); + + // Phase 122 P1: 最小実装 - Return void のみ + // TODO Phase 122 P2-P4: If/Assign/条件式の lowering 実装 + main_func.body.push(JoinInst::Ret { value: None }); + + // JoinModule 構築 + let mut module = JoinModule::new(); + module.add_function(main_func); + module.entry = Some(main_func_id); + module.mark_normalized(); + + // JoinFragmentMeta 生成(最小) + let meta = JoinFragmentMeta::empty(); + + Ok((module, meta)) + } + /// Get shadow lowering status string for dev logging /// /// ## Contract