diff --git a/src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs b/src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs index 8a75fefb..957f59cf 100644 --- a/src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs +++ b/src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs @@ -15,12 +15,14 @@ //! # Usage //! //! ```rust -//! // Standard break condition analysis -//! let (env, bindings) = ConditionEnvBuilder::build_for_break_condition( +//! // Standard break condition analysis (Phase 201+) +//! let mut space = JoinValueSpace::new(); +//! let (env, bindings, loop_var_join_id) = ConditionEnvBuilder::build_for_break_condition_v2( //! break_condition, //! &loop_var_name, //! &variable_map, //! loop_var_id, +//! &mut space, //! )?; //! ``` @@ -36,78 +38,6 @@ use std::collections::BTreeMap; pub struct ConditionEnvBuilder; impl ConditionEnvBuilder { - /// Build ConditionEnv and ConditionBindings from break condition - /// - /// This extracts all variables used in the break condition (excluding the loop parameter) - /// and creates: - /// 1. ConditionEnv: Maps variable names to JoinIR-local ValueIds - /// 2. ConditionBindings: Records HOST ValueId ↔ JoinIR ValueId mappings for merge - /// - /// # Arguments - /// - /// * `break_condition` - AST node for the break condition - /// * `loop_var_name` - Loop parameter name (excluded from condition-only variables) - /// * `variable_map` - HOST function's variable_map (for looking up HOST ValueIds) - /// * `loop_var_id` - HOST ValueId for the loop parameter - /// - /// # Returns - /// - /// Tuple of: - /// - ConditionEnv: Variable name → JoinIR ValueId mapping - /// - Vec: HOST↔JoinIR value mappings for merge - /// - /// # Errors - /// - /// Returns error if a condition variable is not found in variable_map - pub fn build_for_break_condition( - break_condition: &ASTNode, - loop_var_name: &str, - variable_map: &BTreeMap, - _loop_var_id: ValueId, - ) -> Result<(ConditionEnv, Vec), String> { - // Extract all variables used in the condition (excluding loop parameter) - let condition_var_names = extract_condition_variables( - break_condition, - &[loop_var_name.to_string()], - ); - - let mut env = ConditionEnv::new(); - let mut bindings = Vec::new(); - - // Add loop parameter to env (ValueId(0) in JoinIR space) - // The loop parameter is NOT a condition binding (it's a join_input instead) - env.insert(loop_var_name.to_string(), ValueId(0)); - - // Create a local allocator for JoinIR-local ValueIds for condition-only variables - let mut join_value_counter = 1u32; // Start from 1 (0 is reserved for loop param) - - // For each condition variable, allocate JoinIR-local ValueId and build binding - for var_name in &condition_var_names { - let host_id = variable_map - .get(var_name) - .copied() - .ok_or_else(|| { - format!( - "Condition variable '{}' not found in variable_map. \ - Loop condition references undefined variable.", - var_name - ) - })?; - - let join_id = ValueId(join_value_counter); - join_value_counter += 1; - - env.insert(var_name.clone(), join_id); - bindings.push(ConditionBinding { - name: var_name.clone(), - host_value: host_id, - join_value: join_id, - }); - } - - Ok((env, bindings)) - } - /// Build ConditionEnv with loop parameter only /// /// Used when there are no additional condition-only variables, @@ -339,17 +269,22 @@ mod tests { let mut variable_map = BTreeMap::new(); variable_map.insert("i".to_string(), ValueId(100)); - let (env, bindings) = ConditionEnvBuilder::build_for_break_condition( + let mut space = JoinValueSpace::new(); + let (env, bindings, loop_var_join_id) = ConditionEnvBuilder::build_for_break_condition_v2( &condition, "i", &variable_map, ValueId(100), + &mut space, ) .unwrap(); // Should have loop parameter in env assert!(env.get("i").is_some()); + // Loop var should be in param region (100+) + assert!(loop_var_join_id.0 >= 100); + // Should have no condition-only bindings assert_eq!(bindings.len(), 0); } @@ -374,16 +309,19 @@ mod tests { variable_map.insert("i".to_string(), ValueId(100)); variable_map.insert("max".to_string(), ValueId(200)); - let (env, bindings) = ConditionEnvBuilder::build_for_break_condition( + let mut space = JoinValueSpace::new(); + let (env, bindings, loop_var_join_id) = ConditionEnvBuilder::build_for_break_condition_v2( &condition, "i", &variable_map, ValueId(100), + &mut space, ) .unwrap(); // Should have loop parameter in env assert!(env.get("i").is_some()); + assert!(loop_var_join_id.0 >= 100); // Should have "max" in env with JoinIR-local ValueId assert!(env.get("max").is_some()); @@ -392,7 +330,8 @@ mod tests { assert_eq!(bindings.len(), 1); assert_eq!(bindings[0].name, "max"); assert_eq!(bindings[0].host_value, ValueId(200)); - assert!(bindings[0].join_value.0 > 0); // JoinIR-local ID + // Phase 201: Condition-only variables are allocated from Param region (100+), not Local region + assert!(bindings[0].join_value.0 >= 100); // Should be in param region (100+) } #[test] @@ -415,11 +354,13 @@ mod tests { variable_map.insert("i".to_string(), ValueId(100)); // "undefined_var" is NOT in variable_map - let result = ConditionEnvBuilder::build_for_break_condition( + let mut space = JoinValueSpace::new(); + let result = ConditionEnvBuilder::build_for_break_condition_v2( &condition, "i", &variable_map, ValueId(100), + &mut space, ); // Should return error diff --git a/src/mir/join_ir/lowering/inline_boundary_builder.rs b/src/mir/join_ir/lowering/inline_boundary_builder.rs index 0a3972cd..f49da08e 100644 --- a/src/mir/join_ir/lowering/inline_boundary_builder.rs +++ b/src/mir/join_ir/lowering/inline_boundary_builder.rs @@ -27,7 +27,6 @@ use crate::mir::ValueId; use super::inline_boundary::{JoinInlineBoundary, LoopExitBinding}; use super::condition_to_joinir::ConditionBinding; -use super::join_value_space::JoinValueSpace; /// Role of a parameter in JoinIR lowering (Phase 200-A) /// diff --git a/src/mir/join_ir/lowering/loop_patterns/with_break.rs b/src/mir/join_ir/lowering/loop_patterns/with_break.rs index 9d5d62e0..dadcdcb6 100644 --- a/src/mir/join_ir/lowering/loop_patterns/with_break.rs +++ b/src/mir/join_ir/lowering/loop_patterns/with_break.rs @@ -86,44 +86,30 @@ pub fn lower_loop_with_break_to_joinir( _loop_form: &LoopForm, _lowerer: &mut LoopToJoinLowerer, ) -> Option { - // Phase 188-Impl-2: Delegate to minimal lowerer - // TODO: Extract LoopScopeShape from loop_form for generic implementation - use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; - - use crate::mir::BasicBlockId; - use std::collections::{BTreeMap, BTreeSet}; - - // For now, use a placeholder LoopScopeShape - // TODO: Build actual LoopScopeShape from loop_form - let _placeholder_scope = LoopScopeShape { - header: BasicBlockId(0), - body: BasicBlockId(0), - latch: BasicBlockId(0), - exit: BasicBlockId(0), - pinned: BTreeSet::new(), - carriers: BTreeSet::new(), - body_locals: BTreeSet::new(), - exit_live: BTreeSet::new(), - progress_carrier: None, - variable_definitions: BTreeMap::new(), - }; - - // Generate JoinIR module - // Phase 169: lower_loop_with_break_minimal now requires condition AST and builder - // This test stub is not used by the actual router, so commenting out for now - // let _join_module = lower_loop_with_break_minimal(placeholder_scope, condition, builder)?; - - // Phase 188-Impl-2: Pattern 2 is now integrated in control_flow.rs via cf_loop_pattern2_with_break() - // This function (lower_loop_with_break_to_joinir) is currently not used by the router. - // The actual lowering happens directly in control_flow.rs which calls loop_with_break_minimal. + // Phase 203-A: STUB FUNCTION - Called by router but always returns None // - // TODO: Either: - // 1. Remove this function and rely only on control_flow.rs integration, OR - // 2. Implement JoinModule → JoinInst conversion here (future phase) + // Status: This function is called by loop_pattern_router.rs:148 but is a NO-OP stub. + // The actual Pattern 2 lowering happens via control_flow.rs. + // + // Why this stub exists: + // - Router expects unified interface: lower_*_to_joinir(loop_form, lowerer) + // - Pattern 2 is tightly integrated with control_flow.rs + // - Removing it would require updating router dispatch logic + // + // Current behavior: + // 1. Router calls this function (line 148 in loop_pattern_router.rs) + // 2. Function logs a message and returns None + // 3. Router falls back to control_flow.rs hardcoded Pattern 2 route + // + // Migration options (future): + // - Option 1: Remove stub and update router to call control_flow.rs directly + // - Option 2: Implement JoinModule → JoinInst conversion here + // + // Related code: + // - Router callsite: loop_pattern_router.rs:148 + // - Actual implementation: control_flow::cf_loop_pattern2_with_break() + // - Minimal lowerer: loop_with_break_minimal::lower_loop_with_break_minimal() - eprintln!("[loop_patterns] Pattern 2: Lowering delegated to control_flow.rs"); - - // Temporary: Return None to trigger fallback - // Pattern 2 currently works via hardcoded route in control_flow.rs + eprintln!("[loop_patterns] Pattern 2: Lowering delegated to control_flow.rs (stub)"); None } diff --git a/src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs b/src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs index bfa1ee06..a49593df 100644 --- a/src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs +++ b/src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs @@ -73,7 +73,6 @@ use crate::mir::join_ir::{ BinOpKind, CompareOp, ConstValue, JoinFuncId, JoinFunction, JoinInst, JoinModule, MirLikeInst, UnaryOp, }; -use crate::mir::ValueId; /// Lower Pattern 3 (Loop with If-Else PHI) to JoinIR ///