feat(joinir): Phase 176 Pattern2 multi-carrier lowering complete

Task 176-1: Pattern2 limitation investigation
- Identified 10 limitation points where only position carrier was handled
- Added TODO markers for Phase 176-2/3 implementation
- Created phase176-pattern2-limitations.md documentation

Task 176-2: CarrierUpdateLowerer helper implementation
- Implemented emit_carrier_update() helper function
- Supports CounterLike and AccumulationLike UpdateExpr patterns
- Added 6 unit tests (all passing)
- Fail-Fast error handling for carrier/variable not found

Task 176-3: Pattern2 lowerer multi-carrier extension
- Extended header PHI generation for all carriers
- Implemented loop update for all carriers using emit_carrier_update()
- Extended ExitLine/ExitMeta construction for all carriers
- Updated function call/jump args to include all carriers
- 9/10 tests passing (1 pre-existing test issue)

Task 176-4: E2E testing and bug fixes
- Fixed Trim pattern loop_var_name overwrite bug (pattern2_with_break.rs)
- Fixed InstructionRewriter latch_incoming mapping bug
- All E2E tests passing (RC=0): pos + result dual-carrier loops work
- test_jsonparser_parse_string_min2.hako verified

Task 176-5: Documentation updates
- Created phase176-completion-report.md
- Updated phase175-multicarrier-design.md with completion status
- Updated joinir-architecture-overview.md roadmap
- Updated CURRENT_TASK.md with Phase 176 completion + Phase 177 TODO
- Updated loop_pattern_space.md F-axis (multi-carrier support complete)

Technical achievements:
- Pattern2 now handles single/multiple carriers uniformly
- CarrierInfo architecture proven to work end-to-end
- Two critical bugs fixed (loop_var overwrite, latch_incoming mapping)
- No regressions in existing tests

Next: Phase 177 - Apply to JsonParser _parse_string full implementation
This commit is contained in:
nyash-codex
2025-12-08 15:17:53 +09:00
parent 24aa8ced75
commit 99d329096f
13 changed files with 1345 additions and 55 deletions

View File

@ -0,0 +1,116 @@
# Task 176-4: Trim Pattern Loop Variable Overwrite Bug Fix
**Status**: ✅ COMPLETED
**Date**: 2025-12-08
## Problem
In `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`, lines 271-272 were incorrectly overwriting the loop variable information during Trim pattern processing:
```rust
// ❌ Incorrect code (lines 271-272)
carrier_info.loop_var_id = is_ch_match0;
carrier_info.loop_var_name = carrier_name.clone(); // Overwrites "pos" with "is_ch_match"
```
### Root Cause
The Trim pattern implementation (Phase 171-172) was confusing two distinct concepts:
1. **Loop variable**: The actual loop counter (e.g., `pos`) that increments through the string
2. **Promoted carrier**: The derived variable (e.g., `is_ch_match`) that tracks whether the current character matches whitespace
The code was incorrectly treating the promoted carrier as a replacement for the loop variable, when it should only be an additional carrier alongside the loop variable.
### Impact
- **ExitMeta generation**: Would use wrong variable name ("is_ch_match" instead of "pos")
- **PHI node construction**: Would create PHI nodes for the wrong variable
- **Variable mapping**: Would lose track of the actual loop counter
## Solution
Removed lines 271-272 and replaced with explanatory comment:
```rust
// Note: DO NOT overwrite carrier_info.loop_var_id/loop_var_name here!
// The loop variable is 'pos' (counter), not 'is_ch_match' (carrier).
// carrier_info.loop_var_name should remain as the original loop variable.
eprintln!("[pattern2/trim] Carrier registered. Loop var='{}' remains unchanged",
carrier_info.loop_var_name);
```
### Design Principle
In Trim patterns:
- `loop_var_name` = "pos" (the counter variable)
- `carriers` = ["result", "is_ch_match"] (accumulated values)
- `is_ch_match` is a **promoted carrier**, not a loop variable replacement
## Verification
### 1. Build Status
✅ Build succeeded with no errors
### 2. Log Output Verification
Both E2E tests show correct behavior:
```
[pattern2/promoter] Phase 171-C-4 DEBUG: BEFORE merge - carrier_info.loop_var_name='pos'
[pattern2/promoter] Phase 171-C-4 DEBUG: promoted_carrier.loop_var_name='is_ch_match'
[pattern2/promoter] Phase 171-C-4 DEBUG: AFTER merge - carrier_info.loop_var_name='pos' ← CORRECT!
[pattern2/trim] Carrier registered. Loop var='pos' remains unchanged ← NEW LOG MESSAGE
[pattern2/before_lowerer] About to call lower_loop_with_break_minimal with carrier_info.loop_var_name='pos'
```
**Key observation**: The loop_var_name correctly remains as 'pos' throughout the entire process.
### 3. Regression Tests
✅ All carrier update tests pass (6/6):
- `test_emit_binop_update_with_const`
- `test_emit_binop_update_with_variable`
- `test_emit_const_update`
- `test_emit_update_lhs_mismatch`
- `test_emit_update_carrier_not_in_env`
- `test_emit_update_rhs_variable_not_found`
❌ One pre-existing test failure (unrelated to this fix):
- `test_pattern2_accepts_loop_param_only` - Failed on both HEAD and with our changes
### 4. E2E Test Results
**test_jsonparser_parse_string_min2.hako**:
- ✅ Loop variable name correctly preserved as 'pos'
- ⚠️ Execution fails with: "Phase 33-16: Carrier 'result' has no latch incoming set"
- **Note**: This is a separate issue unrelated to our fix (carrier PHI initialization)
**test_trim_simple.hako** (new test):
- ✅ Loop variable name correctly preserved as 'pos'
- ⚠️ Same carrier PHI error as above
## Remaining Issues (Out of Scope)
The following error is NOT caused by this fix and exists independently:
```
[ERROR] ❌ MIR compilation error: Phase 33-16: Carrier 'result' has no latch incoming set
```
This appears to be related to PHI node initialization for carriers in Pattern 2, and will need to be addressed separately.
## Files Changed
1. `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`
- Lines 271-272: Removed incorrect loop_var overwrite
- Lines 270-275: Added explanatory comment and new debug log
## Conclusion
**Bug successfully fixed**
- Loop variable name no longer gets overwritten by carrier name
- Design clarification: promoted carriers are additions, not replacements
- No regressions introduced in carrier update logic
- Remaining errors are pre-existing and unrelated to this fix
The fix correctly implements the design intention: in Trim patterns, `is_ch_match` should be an additional carrier alongside the original loop variable `pos`, not a replacement for it.