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>
10 KiB
Phase 223: LoopBodyLocal Condition Promotion - Summary
Overview
Phase 223 addresses the "LoopBodyLocal in condition" constraint that blocks JsonParser loops (discovered in Phase 221). This phase enables Pattern2/Pattern4 to handle loops where loop-body-local variables appear in break/continue conditions.
Phase Breakdown
Phase 223-1: Comprehensive Inventory ✅ COMPLETE
Deliverable: /docs/development/current/main/phase223-loopbodylocal-condition-inventory.md
Key Findings:
- Category A (Safe for Promotion): 6 patterns
- A-1/A-2: Trim leading/trailing (✅ already handled by TrimLoopHelper)
- A-3: Skip whitespace (Pattern 4) - P0 target ⚠️ needs Pattern4 support
- A-4: Digit detection (cascading LoopBodyLocal) - P1 candidate
- A-5: String comparison (multi-variable) - P2 candidate
- A-6: atoi range check (complex) - P2 candidate
- Category B (Fail-Fast Maintained): 1 pattern (complex nested conditions)
- Category C (Body-Only): 2 patterns (not blocked, already working)
Priority Classification:
- P0: Category A-3 (skip_whitespace) - critical for JsonParser
- P1: Category A-4 (cascading LoopBodyLocal) - high priority
- P2: Category A-5/A-6 (multi-variable, complex) - future extension
Phase 223-2: API-Level Design ✅ COMPLETE
Deliverable: /docs/development/current/main/phase223-loopbodylocal-condition-design.md
Key Design Decisions:
-
New Box: LoopBodyCondPromoter (thin coordinator)
- Location:
src/mir/loop_pattern_detection/loop_body_cond_promoter.rs(to be created in Phase 223-3) - Role: Unified API for Pattern2/Pattern4 condition promotion
- Delegation: Reuses existing
LoopBodyCarrierPromoterfor detection logic - Output: Metadata only (no code generation)
- Location:
-
API Signature:
pub struct ConditionPromotionRequest<'a> { pub loop_param_name: &'a str, pub cond_scope: &'a LoopConditionScope, pub scope_shape: Option<&'a LoopScopeShape>, pub break_cond: Option<&'a ASTNode>, pub continue_cond: Option<&'a ASTNode>, pub loop_body: &'a [ASTNode], } pub enum ConditionPromotionResult { Promoted { carrier_info, promoted_var, carrier_name }, CannotPromote { reason, vars }, } impl LoopBodyCondPromoter { pub fn try_promote_for_condition(req: ConditionPromotionRequest) -> ConditionPromotionResult; } -
Pattern4 Integration Strategy:
- Current: Immediate Fail-Fast when
has_loop_body_local() == true - Future (Phase 223-3):
if loop_cond_scope.has_loop_body_local() { match LoopBodyCondPromoter::try_promote_for_condition(req) { Promoted { carrier_info, .. } => { // Merge carrier, continue Pattern4 lowering } CannotPromote { .. } => { // Fail-Fast (same as current) } } }
- Current: Immediate Fail-Fast when
-
P0 Constraints (strict):
- Single LoopBodyLocal variable only (e.g.,
ch) - Must match existing Trim pattern (substring + equality chain)
- No cascading dependencies (A-4:
ch+digit_pos→ rejected) - No multi-variable patterns (A-5:
ch_s+ch_lit→ rejected)
- Single LoopBodyLocal variable only (e.g.,
-
Box Role Matrix:
| Box | Detection | Metadata | Code Gen | Integration |
|---|---|---|---|---|
| LoopConditionScopeBox | ✅ Classify vars | ❌ | ❌ | Pattern2/4 |
| LoopBodyCarrierPromoter | ✅ Trim pattern | ✅ TrimPatternInfo | ❌ | TrimLoopLowerer |
| TrimLoopLowerer | ❌ (delegates) | ✅ CarrierInfo | ✅ MIR emission | Pattern2 only |
| LoopBodyCondPromoter (新) | ❌ (delegates) | ✅ CarrierInfo | ❌ | Pattern2/4 |
Design Principle: Single Responsibility
- Detection: LoopBodyCarrierPromoter
- Metadata: TrimPatternInfo, CarrierInfo
- Code Generation: Pattern-specific lowerers (TrimLoopLowerer for P2, Pattern4 lowerer for P4)
- Coordination: LoopBodyCondPromoter (thin wrapper)
Phase 223-3: Implementation (PLANNED)
Estimated Deliverables:
-
LoopBodyCondPromoter implementation (~50-80 lines)
- Extract promotion logic from TrimLoopLowerer
- Add P0 constraint checking (single var, simple pattern)
- Delegate to LoopBodyCarrierPromoter
-
Pattern4 integration (+30-40 lines)
- Call LoopBodyCondPromoter before Fail-Fast
- Merge promoted carrier into existing CarrierInfo
- Continue with Pattern4 lowering if promotion succeeds
-
Unit tests (5-7 test cases)
- P0 promotion success (Category A-3: skip_whitespace)
- Cascading Fail-Fast (Category A-4: ch + digit_pos)
- Complex pattern Fail-Fast (Category B-1: nested if)
- Multi-variable Fail-Fast (Category A-5: ch_s + ch_lit)
-
E2E test (1 file)
apps/tests/phase223_p4_skip_whitespace.hako- Pattern: _skip_whitespace with continue
- Expected: Pattern4 lowering + MIR execution success
Total Estimated Size: +150-200 lines (net)
Documentation Updates
CURRENT_TASK.md ✅ UPDATED
Added Phase 223 summary:
- **Phase 223 進行中**: LoopBodyLocal Condition Promotion(条件昇格システム)
- **Phase 223-1 完了** ✅: 包括的棚卸(Category A: 6 patterns, Category B: 1, Category C: 2)
- **Phase 223-2 完了** ✅: API レベル設計(LoopBodyCondPromoter Box, P0: Pattern4/_skip_whitespace 向け)
- **Phase 223-3 予定**: 実装(LoopBodyCondPromoter 抽出, Pattern4 統合, E2E テスト)
joinir-architecture-overview.md ✅ UPDATED
Added LoopBodyCondPromoter to Section 2.2 (条件式ライン):
- **LoopBodyCondPromoter(Phase 223-2 設計完了)**
- ファイル: `src/mir/loop_pattern_detection/loop_body_cond_promoter.rs`(Phase 223-3 で実装予定)
- 責務: ループ条件に出てくる LoopBodyLocal を carrier に昇格する統一 API
- 設計原則: Thin coordinator, Pattern-agnostic, Fail-Fast
- 入出力: ConditionPromotionRequest → ConditionPromotionResult
- 使用元: Pattern4 (promotion-first), Pattern2 (TrimLoopLowerer 経由)
Impact Analysis
Immediate Impact (P0 - Phase 223-3)
Unblocks:
apps/tests/parser_box_minimal.hako(skip_ws method)tools/hako_shared/json_parser.hako(_skip_whitespace)
Pattern Coverage:
- Category A-1/A-2: Already working (TrimLoopHelper)
- Category A-3: WILL WORK (Phase 223-3 target) ✨
- Category A-4/A-5/A-6: Still blocked (P1/P2 future work)
JsonParser Loop Coverage:
- Before Phase 223: 7/13 loops (54%)
- After Phase 223-3 (P0): 8/13 loops (62%) (+1 loop: _skip_whitespace Pattern4 variant)
Future Extensions (P1/P2)
P1: Cascading LoopBodyLocal (Category A-4)
- Pattern:
local ch = ...; local digit_pos = digits.indexOf(ch); if digit_pos < 0 { break } - Solution: Promote only leaf variable (
digit_pos→is_digit) - Requires: Dependency analysis in LoopBodyCarrierPromoter
P2: Multi-Variable Patterns (Category A-5, A-6)
- Pattern:
local ch_s = ...; local ch_lit = ...; if ch_s != ch_lit { break } - Solution: Promote to single carrier (
chars_match) - Requires: Multi-variable carrier initialization
Non-Goals:
- Category B (Complex patterns): Continue to Fail-Fast
- Nested if with reassignment
- Method call chains
Test Strategy
Phase 223-3 Tests
-
Unit Tests (5-7 cases):
test_p0_skip_whitespace_promotion(): Category A-3 successtest_cascading_fail_fast(): Category A-4 rejection (P0 constraint)test_multi_variable_fail_fast(): Category A-5 rejectiontest_complex_pattern_fail_fast(): Category B-1 rejectiontest_pattern2_integration(): Verify existing TrimLoopLowerer still works
-
E2E Tests (1 file):
apps/tests/phase223_p4_skip_whitespace.hako- Expected output: Correct whitespace skipping behavior
- Verification: MIR execution returns expected result
-
Regression Tests:
- All Phase 220-222 tests must continue to pass
- Existing TrimLoopHelper tests (Phase 171-176) must pass
Success Criteria
Phase 223-2 ✅ COMPLETE
- Design document created (
phase223-loopbodylocal-condition-design.md) - API types defined (ConditionPromotionRequest/Result)
- Box roles clarified (LoopBodyCondPromoter vs existing boxes)
- Pattern4 integration strategy documented
- P0 constraints specified (single var, Trim pattern only)
- CURRENT_TASK.md updated
- joinir-architecture-overview.md updated
Phase 223-3 (PLANNED)
- LoopBodyCondPromoter implementation (~50-80 lines)
- Pattern4 integration (+30-40 lines)
- Unit tests (5-7 cases) all passing
- E2E test passing (phase223_p4_skip_whitespace.hako)
- No regressions in Phase 220-222 tests
- TrimLoopHelper tests continue to pass
Files Modified/Created
Phase 223-1
- Created:
docs/development/current/main/phase223-loopbodylocal-condition-inventory.md
Phase 223-2
- Created:
docs/development/current/main/phase223-loopbodylocal-condition-design.md - Updated:
CURRENT_TASK.md - Updated:
docs/development/current/main/joinir-architecture-overview.md - Created:
docs/development/current/main/PHASE_223_SUMMARY.md(this file)
Phase 223-3 (Planned)
- Create:
src/mir/loop_pattern_detection/loop_body_cond_promoter.rs(~80 lines) - Modify:
src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs(+40 lines) - Create:
apps/tests/phase223_p4_skip_whitespace.hako(E2E test) - Create: Unit test module in
loop_body_cond_promoter.rs(~100 lines tests)
Relation to Overall JoinIR Roadmap
Phase 223 is part of the JsonParser実戦投入ライン (Phase 220-225):
Phase 220: ConditionEnv統合 ✅
Phase 221: 実戦投入・制約整理 ✅
Phase 222: If Condition正規化 ✅
Phase 223: LoopBodyLocal Condition Promotion ← 現在地
├─ Phase 223-1: Inventory ✅
├─ Phase 223-2: Design ✅ (完了)
└─ Phase 223-3: Implementation (次)
Phase 224: P1 Cascading LoopBodyLocal (計画中)
Phase 225: P2 Multi-Variable Patterns (計画中)
Overall Goal: Enable all JsonParser loops to use JoinIR Pattern1-4 infrastructure
Current Coverage:
- Before Phase 223: 7/13 loops (54%)
- After Phase 223-3 (P0): 8/13 loops (62%)
- After Phase 224 (P1): 10/13 loops (77% estimated)
- After Phase 225 (P2): 11/13 loops (85% estimated)
- Remaining 2 loops: Category B (complex, may remain Fail-Fast)
Revision History
- 2025-12-10: Phase 223-2 design complete, summary document created