feat(joinir): Phase 223-3 - LoopBodyCondPromoter implementation
Implements LoopBodyLocal condition promotion for Pattern4/continue patterns.
Previously, loops with LoopBodyLocal in conditions would Fail-Fast.
Now, safe Trim/skip_whitespace patterns (Category A-3) are promoted and lowering continues.
## Implementation
- **LoopBodyCondPromoter Box** (loop_body_cond_promoter.rs)
- extract_continue_condition(): Extract if-condition from continue branches
- try_promote_for_condition(): Thin wrapper delegating to LoopBodyCarrierPromoter
- ConditionPromotionRequest/Result API for Pattern2/4 integration
- **Pattern4 Integration** (pattern4_with_continue.rs)
- Analyze both header condition + continue condition
- On promotion success: merge carrier_info → continue lowering
- On promotion failure: Fail-Fast with clear error message
- **Unit Tests** (5 tests, all PASS)
- test_cond_promoter_skip_whitespace_pattern
- test_cond_promoter_break_condition
- test_cond_promoter_non_substring_pattern
- test_cond_promoter_no_scope_shape
- test_cond_promoter_no_body_locals
- **E2E Test** (phase223_p4_skip_whitespace_min.hako)
- Category A-3 pattern: local ch = s.substring(...); if ch == " " { continue }
- Verifies promotion succeeds and Pattern4 lowering proceeds
## Documentation
- joinir-architecture-overview.md: Updated LoopBodyCondPromoter section (Phase 223-3 完了)
- CURRENT_TASK.md: Added Phase 223-3 completion summary
- PHASE_223_SUMMARY.md: Phase overview and status tracking
- phase223-loopbodylocal-condition-*.md: Design docs and inventory
## Achievement
- **Before**: LoopBodyLocal in condition → Fail-Fast
- **Now**: Trim/skip_whitespace patterns promoted → Pattern4 lowering continues
- **Remaining**: Phase 172+ JoinIR Trim lowering for complete RC correctness
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -209,64 +209,74 @@ impl MirBuilder {
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().varmap("pattern4_start", &self.variable_map);
|
||||
|
||||
// Phase 171-C-3: LoopBodyCarrierPromoter integration
|
||||
// Check if LoopConditionScopeBox detects LoopBodyLocal variables, and attempt promotion
|
||||
// Phase 223-3: LoopBodyCondPromoter integration
|
||||
// Check for LoopBodyLocal in continue condition and attempt promotion
|
||||
{
|
||||
use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox;
|
||||
use crate::mir::loop_pattern_detection::loop_body_carrier_promoter::{
|
||||
LoopBodyCarrierPromoter, PromotionRequest, PromotionResult,
|
||||
use crate::mir::loop_pattern_detection::loop_body_cond_promoter::{
|
||||
LoopBodyCondPromoter, ConditionPromotionRequest, ConditionPromotionResult,
|
||||
};
|
||||
|
||||
// Phase 223-3: Extract continue condition from body (if present)
|
||||
// This handles skip_whitespace pattern: if ch == " " || ... { continue }
|
||||
let continue_cond = LoopBodyCondPromoter::extract_continue_condition(body_to_analyze);
|
||||
|
||||
// Analyze both header condition and continue condition for LoopBodyLocal
|
||||
let conditions_to_analyze: Vec<&ASTNode> = if let Some(cont_cond) = continue_cond {
|
||||
vec![condition, cont_cond]
|
||||
} else {
|
||||
vec![condition]
|
||||
};
|
||||
|
||||
// First check: Does the condition reference LoopBodyLocal variables?
|
||||
let cond_scope = LoopConditionScopeBox::analyze(
|
||||
&loop_var_name,
|
||||
&[condition],
|
||||
&conditions_to_analyze,
|
||||
Some(&scope),
|
||||
);
|
||||
|
||||
if cond_scope.has_loop_body_local() {
|
||||
// Phase 171-C-3: Try promotion
|
||||
// Pattern 4 has no break condition
|
||||
let request = PromotionRequest {
|
||||
scope: &scope,
|
||||
// Phase 223-3: Try promotion using LoopBodyCondPromoter
|
||||
let promotion_req = ConditionPromotionRequest {
|
||||
loop_param_name: &loop_var_name,
|
||||
cond_scope: &cond_scope,
|
||||
break_cond: None, // Pattern 4 doesn't have break
|
||||
scope_shape: Some(&scope),
|
||||
break_cond: None, // Pattern 4 has no break
|
||||
continue_cond,
|
||||
loop_body: body_to_analyze,
|
||||
};
|
||||
|
||||
match LoopBodyCarrierPromoter::try_promote(&request) {
|
||||
PromotionResult::Promoted { trim_info } => {
|
||||
match LoopBodyCondPromoter::try_promote_for_condition(promotion_req) {
|
||||
ConditionPromotionResult::Promoted {
|
||||
carrier_info: promoted_carrier,
|
||||
promoted_var,
|
||||
carrier_name,
|
||||
} => {
|
||||
eprintln!(
|
||||
"[pattern4/promoter] LoopBodyLocal '{}' promoted to carrier '{}'",
|
||||
trim_info.var_name, trim_info.carrier_name
|
||||
"[pattern4/cond_promoter] LoopBodyLocal '{}' promoted to carrier '{}'",
|
||||
promoted_var, carrier_name
|
||||
);
|
||||
|
||||
// Phase 171-C-4: Convert to CarrierInfo and merge
|
||||
let promoted_carrier = trim_info.to_carrier_info();
|
||||
// Phase 223-3: Merge promoted carrier into existing CarrierInfo
|
||||
carrier_info.merge_from(&promoted_carrier);
|
||||
|
||||
eprintln!(
|
||||
"[pattern4/promoter] Phase 171-C-4: Merged carrier '{}' into CarrierInfo (total carriers: {})",
|
||||
trim_info.carrier_name,
|
||||
"[pattern4/cond_promoter] Merged carrier '{}' into CarrierInfo (total carriers: {})",
|
||||
carrier_name,
|
||||
carrier_info.carrier_count()
|
||||
);
|
||||
|
||||
// Phase 171-impl-Trim: Check if this is a safe Trim pattern
|
||||
// Phase 223-3: Check if this is a safe Trim pattern
|
||||
if let Some(helper) = carrier_info.trim_helper() {
|
||||
if helper.is_safe_trim() {
|
||||
eprintln!("[pattern4/trim] Safe Trim pattern detected, bypassing LoopBodyLocal restriction");
|
||||
eprintln!("[pattern4/trim] Carrier: '{}', original var: '{}', whitespace chars: {:?}",
|
||||
helper.carrier_name, helper.original_var, helper.whitespace_chars);
|
||||
|
||||
// Phase 171-impl-Trim: Validation successful!
|
||||
// Phase 172+ will implement the actual JoinIR generation for Trim patterns
|
||||
// For now, return an informative message that the pattern is recognized but not yet lowered
|
||||
return Err(format!(
|
||||
"[cf_loop/pattern4] ✅ Trim pattern validation successful! \
|
||||
Carrier '{}' ready for Phase 172 implementation. \
|
||||
(Pattern detection: PASS, Safety check: PASS, JoinIR lowering: TODO)",
|
||||
helper.carrier_name
|
||||
));
|
||||
eprintln!(
|
||||
"[pattern4/cond_promoter] Safe Trim/skip_whitespace pattern detected"
|
||||
);
|
||||
eprintln!(
|
||||
"[pattern4/cond_promoter] Carrier: '{}', original var: '{}', whitespace chars: {:?}",
|
||||
helper.carrier_name, helper.original_var, helper.whitespace_chars
|
||||
);
|
||||
// Phase 223-3: Continue with Pattern4 lowering
|
||||
// (fall through to normal lowering path)
|
||||
} else {
|
||||
return Err(format!(
|
||||
"[cf_loop/pattern4] Trim pattern detected but not safe: carrier='{}', whitespace_count={}",
|
||||
@ -274,15 +284,12 @@ impl MirBuilder {
|
||||
helper.whitespace_count()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(format!(
|
||||
"[cf_loop/pattern4] Promoted but no TrimLoopHelper attached (carrier: '{}')",
|
||||
trim_info.carrier_name
|
||||
));
|
||||
}
|
||||
// Phase 223-3: Continue with normal Pattern4 lowering
|
||||
// The carrier has been promoted and merged, lowering can proceed
|
||||
}
|
||||
PromotionResult::CannotPromote { reason, vars } => {
|
||||
// Phase 171-C-3: Fail-Fast on promotion failure
|
||||
ConditionPromotionResult::CannotPromote { reason, vars } => {
|
||||
// Phase 223-3: Fail-Fast on promotion failure
|
||||
return Err(format!(
|
||||
"[cf_loop/pattern4] Cannot promote LoopBodyLocal variables {:?}: {}",
|
||||
vars, reason
|
||||
|
||||
Reference in New Issue
Block a user