//! Phase 121: StepTree → JoinModule shadow lowering (if-only) //! //! ## Responsibility //! //! - Convert StepTree to JoinModule (Normalized dialect) //! - Only for if-only patterns (no loops) //! - Returns None for out-of-scope patterns //! - Returns Err for patterns that should be supported but conversion failed //! //! ## Design //! //! - Input: `&StepTree` with pre-computed contract //! - No AST re-analysis (contract-only decisions) //! - Single responsibility: structure → JoinIR conversion use crate::mir::control_tree::step_tree::StepTree; use crate::mir::join_ir::lowering::carrier_info::{ExitMeta, JoinFragmentMeta}; use crate::mir::join_ir::JoinModule; use super::contracts::{check_if_only, CapabilityCheckResult}; /// Box-First: StepTree → Normalized shadow lowering pub struct StepTreeNormalizedShadowLowererBox; impl StepTreeNormalizedShadowLowererBox { /// Try to lower an if-only StepTree to normalized form /// /// ## Returns /// /// - `Ok(None)`: Out of scope (e.g., contains loops) /// - `Ok(Some(...))`: Shadow generation succeeded /// - `Err(...)`: Should be supported but conversion failed (internal error) /// /// ## Contract /// /// - 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 pub fn try_lower_if_only( step_tree: &StepTree, ) -> Result, String> { // Phase 121 P1: Capability check (if-only scope) 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))) } CapabilityCheckResult::Unsupported(_reason) => { // Out of scope for Phase 121 Ok(None) } } } /// Get shadow lowering status string for dev logging /// /// ## Contract /// /// - Returns 1-line summary: "shadow_lowered=true/false reason=..." /// - Does not perform actual lowering (use `try_lower_if_only` for that) pub fn get_status_string(step_tree: &StepTree) -> String { let capability = check_if_only(step_tree); match capability { CapabilityCheckResult::Supported => { format!( "shadow_lowered=true step_tree_sig={} exits={:?} writes={:?}", step_tree.signature_basis_string(), step_tree.contract.exits, step_tree.contract.writes ) } CapabilityCheckResult::Unsupported(reason) => { format!( "shadow_lowered=false reason=\"{}\" step_tree_sig={}", reason.reason(), step_tree.signature_basis_string() ) } } } } #[cfg(test)] mod tests { use super::*; use crate::mir::control_tree::step_tree::{StepNode, StepTreeFeatures, StepTreeSignature}; use crate::mir::control_tree::step_tree_contract_box::StepTreeContract; fn make_if_only_tree() -> StepTree { StepTree { root: StepNode::Block(vec![]), features: StepTreeFeatures { has_if: true, has_loop: false, has_break: false, has_continue: false, has_return: false, max_if_depth: 1, max_loop_depth: 0, }, contract: StepTreeContract { exits: Default::default(), writes: Default::default(), required_caps: Default::default(), cond_sig: Default::default(), }, signature: StepTreeSignature(0), } } fn make_loop_tree() -> StepTree { StepTree { root: StepNode::Block(vec![]), features: StepTreeFeatures { has_if: false, has_loop: true, has_break: false, has_continue: false, has_return: false, max_if_depth: 0, max_loop_depth: 1, }, contract: StepTreeContract { exits: Default::default(), writes: Default::default(), required_caps: Default::default(), cond_sig: Default::default(), }, signature: StepTreeSignature(0), } } #[test] fn test_if_only_supported() { let tree = make_if_only_tree(); let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree); assert!(result.is_ok()); assert!(result.unwrap().is_some()); } #[test] fn test_loop_rejected() { let tree = make_loop_tree(); let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree); assert!(result.is_ok()); assert!(result.unwrap().is_none()); } #[test] fn test_status_string_if_only() { let tree = make_if_only_tree(); let status = StepTreeNormalizedShadowLowererBox::get_status_string(&tree); assert!(status.contains("shadow_lowered=true")); assert!(status.contains("step_tree_sig=")); } #[test] fn test_status_string_loop() { let tree = make_loop_tree(); let status = StepTreeNormalizedShadowLowererBox::get_status_string(&tree); assert!(status.contains("shadow_lowered=false")); assert!(status.contains("reason=\"contains loop")); } }