feat(joinir): Phase 224-cont - Promoted variable tracking for lowerer

- Add promoted_loopbodylocals field to CarrierInfo
- Record promoted variables in Pattern2 promotion handler
- Filter promoted variables in lowerer LoopBodyLocal check
- digit_pos → is_digit_pos promotion now continues to lowering

Closes Phase 224 lowerer integration gap.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-10 16:30:53 +09:00
parent 00d1ec7cc5
commit 4cddca1cae
5 changed files with 49 additions and 1 deletions

View File

@ -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() {

View File

@ -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

View File

@ -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),

View File

@ -46,6 +46,12 @@ pub struct CarrierInfo {
pub carriers: Vec<CarrierVar>,
/// Phase 171-C-5: Trim pattern helper (if this CarrierInfo was created from Trim promotion)
pub trim_helper: Option<crate::mir::loop_pattern_detection::trim_loop_helper::TrimLoopHelper>,
/// 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<String>,
}
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

View File

@ -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!(