diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs index c0314ef4..f993fbc8 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs @@ -308,6 +308,9 @@ impl MirBuilder { promoted_var, carrier_name ); + // Phase 224: Record promoted variable before merging + carrier_info.promoted_loopbodylocals.push(promoted_var.clone()); + // Merge promoted carrier into existing CarrierInfo carrier_info.merge_from(&promoted_carrier); @@ -316,6 +319,10 @@ impl MirBuilder { carrier_name, carrier_info.carrier_count() ); + eprintln!( + "[pattern2/cond_promoter] Phase 224: Recorded promoted variable '{}' in carrier_info.promoted_loopbodylocals", + promoted_var + ); // Check if this is a safe Trim pattern if let Some(helper) = carrier_info.trim_helper() { diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern4_carrier_analyzer.rs b/src/mir/builder/control_flow/joinir/patterns/pattern4_carrier_analyzer.rs index 5e05d71c..4ee102ff 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern4_carrier_analyzer.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern4_carrier_analyzer.rs @@ -72,6 +72,7 @@ impl Pattern4CarrierAnalyzer { loop_var_id: all_carriers.loop_var_id, carriers: updated_carriers, trim_helper: all_carriers.trim_helper.clone(), + promoted_loopbodylocals: all_carriers.promoted_loopbodylocals.clone(), // Phase 224 }) } @@ -287,6 +288,7 @@ mod tests { }, ], trim_helper: None, + promoted_loopbodylocals: Vec::new(), // Phase 224 }; // Analyze carriers diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs b/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs index 9ee2897a..8a54bd28 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs @@ -404,6 +404,7 @@ mod tests { }, ], trim_helper: None, + promoted_loopbodylocals: Vec::new(), // Phase 224 }, loop_scope: LoopScopeShapeBuilder::empty_body_locals( BasicBlockId(0), @@ -442,6 +443,7 @@ mod tests { carrier_name: "is_whitespace".to_string(), whitespace_chars: vec![" ".to_string(), "\t".to_string()], }), + promoted_loopbodylocals: Vec::new(), // Phase 224 }, loop_scope: LoopScopeShapeBuilder::empty_body_locals( BasicBlockId(0), diff --git a/src/mir/join_ir/lowering/carrier_info.rs b/src/mir/join_ir/lowering/carrier_info.rs index 64ba9430..3af9b280 100644 --- a/src/mir/join_ir/lowering/carrier_info.rs +++ b/src/mir/join_ir/lowering/carrier_info.rs @@ -46,6 +46,12 @@ pub struct CarrierInfo { pub carriers: Vec, /// Phase 171-C-5: Trim pattern helper (if this CarrierInfo was created from Trim promotion) pub trim_helper: Option, + /// Phase 224: Promoted LoopBodyLocal variables (e.g., "digit_pos" promoted to "is_digit_pos") + /// + /// These variables were originally LoopBodyLocal but have been promoted to carriers + /// during condition promotion (e.g., DigitPosPromoter). The lowerer should skip + /// LoopBodyLocal checks for these variables. + pub promoted_loopbodylocals: Vec, } impl CarrierInfo { @@ -106,6 +112,7 @@ impl CarrierInfo { loop_var_id, carriers, trim_helper: None, // Phase 171-C-5: No Trim pattern by default + promoted_loopbodylocals: Vec::new(), // Phase 224: No promoted variables by default }) } @@ -163,6 +170,7 @@ impl CarrierInfo { loop_var_id, carriers, trim_helper: None, // Phase 171-C-5: No Trim pattern by default + promoted_loopbodylocals: Vec::new(), // Phase 224: No promoted variables by default }) } @@ -189,6 +197,7 @@ impl CarrierInfo { loop_var_id, carriers, trim_helper: None, // Phase 171-C-5: No Trim pattern by default + promoted_loopbodylocals: Vec::new(), // Phase 224: No promoted variables by default } } @@ -242,6 +251,13 @@ impl CarrierInfo { if other.trim_helper.is_some() { self.trim_helper = other.trim_helper.clone(); } + + // Phase 224: Merge promoted_loopbodylocals (deduplicate) + for promoted_var in &other.promoted_loopbodylocals { + if !self.promoted_loopbodylocals.contains(promoted_var) { + self.promoted_loopbodylocals.push(promoted_var.clone()); + } + } } /// Phase 171-C-5: Get Trim pattern helper diff --git a/src/mir/join_ir/lowering/loop_with_break_minimal.rs b/src/mir/join_ir/lowering/loop_with_break_minimal.rs index 8ac71572..17d031a7 100644 --- a/src/mir/join_ir/lowering/loop_with_break_minimal.rs +++ b/src/mir/join_ir/lowering/loop_with_break_minimal.rs @@ -154,8 +154,29 @@ pub(crate) fn lower_loop_with_break_minimal( ); if loop_cond_scope.has_loop_body_local() { + // Phase 224: Filter out promoted variables from body-local check + // Variables that were promoted to carriers should not trigger the error let body_local_names = extract_body_local_names(&loop_cond_scope.vars); - return Err(format_unsupported_condition_error("pattern2", &body_local_names)); + let unpromoted_locals: Vec<&String> = body_local_names + .iter() + .filter(|name| !carrier_info.promoted_loopbodylocals.contains(*name)) + .copied() + .collect(); + + if !unpromoted_locals.is_empty() { + eprintln!( + "[joinir/pattern2] Phase 224: {} body-local variables after promotion filter: {:?}", + unpromoted_locals.len(), + unpromoted_locals + ); + return Err(format_unsupported_condition_error("pattern2", &unpromoted_locals)); + } + + eprintln!( + "[joinir/pattern2] Phase 224: All {} body-local variables were promoted: {:?}", + body_local_names.len(), + body_local_names + ); } eprintln!(