feat(joinir): Phase 223.5 - LoopBodyCondPromoter Pattern2 integration

- Integrate LoopBodyCondPromoter into Pattern2 (break condition analysis)
- Add Pattern2 error message functions to error_messages.rs
- Create A-4 minimal test (phase2235_p2_digit_pos_min.hako)
- Unified promotion structure for Pattern2/Pattern4

🤖 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:20:44 +09:00
parent 9b3d2bf001
commit b5661c1915
3 changed files with 337 additions and 0 deletions

View File

@ -4,6 +4,7 @@ use crate::ast::ASTNode;
use crate::mir::builder::MirBuilder;
use crate::mir::ValueId;
use super::super::trace;
use crate::mir::loop_pattern_detection::error_messages;
/// Phase 185-2: Collect body-local variable declarations from loop body
///
@ -266,6 +267,84 @@ impl MirBuilder {
break_condition_raw.clone()
};
// Phase 223.5: LoopBodyLocal Condition Promotion
//
// Check for LoopBodyLocal in loop/break conditions and attempt promotion.
// Safe Trim patterns (Category A-3/A-4) are promoted to carriers.
{
use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox;
use crate::mir::loop_pattern_detection::loop_body_cond_promoter::{
LoopBodyCondPromoter, ConditionPromotionRequest, ConditionPromotionResult,
};
// Analyze both header condition and break condition for LoopBodyLocal
let conditions_to_analyze: Vec<&ASTNode> = vec![condition, &break_condition_node];
let cond_scope = LoopConditionScopeBox::analyze(
&loop_var_name,
&conditions_to_analyze,
Some(&scope),
);
if cond_scope.has_loop_body_local() {
// Try promotion using LoopBodyCondPromoter
let promotion_req = ConditionPromotionRequest {
loop_param_name: &loop_var_name,
cond_scope: &cond_scope,
scope_shape: Some(&scope),
break_cond: Some(&break_condition_node), // Pattern 2 has break
continue_cond: None, // Pattern 2 has no continue
loop_body: _body,
};
match LoopBodyCondPromoter::try_promote_for_condition(promotion_req) {
ConditionPromotionResult::Promoted {
carrier_info: promoted_carrier,
promoted_var,
carrier_name,
} => {
eprintln!(
"[pattern2/cond_promoter] LoopBodyLocal '{}' promoted to carrier '{}'",
promoted_var, carrier_name
);
// Merge promoted carrier into existing CarrierInfo
carrier_info.merge_from(&promoted_carrier);
eprintln!(
"[pattern2/cond_promoter] Merged carrier '{}' into CarrierInfo (total carriers: {})",
carrier_name,
carrier_info.carrier_count()
);
// Check if this is a safe Trim pattern
if let Some(helper) = carrier_info.trim_helper() {
if helper.is_safe_trim() {
eprintln!(
"[pattern2/cond_promoter] Safe Trim pattern detected"
);
eprintln!(
"[pattern2/cond_promoter] Carrier: '{}', original var: '{}', whitespace chars: {:?}",
helper.carrier_name, helper.original_var, helper.whitespace_chars
);
// Continue with Pattern2 lowering (fall through)
} else {
return Err(error_messages::format_error_pattern2_trim_not_safe(
&helper.carrier_name,
helper.whitespace_count()
));
}
}
// Carrier promoted and merged, proceed with normal lowering
}
ConditionPromotionResult::CannotPromote { reason, vars } => {
// Fail-Fast on promotion failure
return Err(error_messages::format_error_pattern2_promotion_failed(&vars, &reason));
}
}
}
}
// Phase 180-3: Delegate Trim/P5 processing to TrimLoopLowerer
let effective_break_condition = if let Some(trim_result) = super::trim_loop_lowering::TrimLoopLowerer::try_lower_trim_like_loop(
self,