Files
hakorune/docs/development/current/main/phase217-if-sum-multi.md
nyash-codex d4f90976da refactor(joinir): Phase 244 - ConditionLoweringBox trait unification
Unify condition lowering logic across Pattern 2/4 with trait-based API.

New infrastructure:
- condition_lowering_box.rs: ConditionLoweringBox trait + ConditionContext (293 lines)
- ExprLowerer implements ConditionLoweringBox trait (+51 lines)

Pattern migrations:
- Pattern 2 (loop_with_break_minimal.rs): Use trait API
- Pattern 4 (loop_with_continue_minimal.rs): Use trait API

Benefits:
- Unified condition lowering interface
- Extensible for future lowering strategies
- Clean API boundary between patterns and lowering logic
- Zero code duplication

Test results: 911/911 PASS (+2 new tests)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 02:35:31 +09:00

275 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 217: Multi-Carrier If-Sum Complete
## Overview
Phase 217 validates that Pattern 3 if-sum implementation supports **multiple accumulators** (sum + count) with **zero additional code**.
**Status**: ✅ **COMPLETE** - Multi-carrier if-sum works out-of-the-box
## The Surprise: Zero Implementation Needed
### Expected Work (Task 217-3)
- Modify `loop_with_if_phi_if_sum.rs` for multi-carrier
- Update AST extraction to handle 2+ updates
- Wire multiple carriers through JoinIR generation
### Actual Work
**ZERO LINES OF CODE CHANGED** 🎉
### Why It Just Worked
Phase 217 is the culmination of three previous phases working in perfect harmony:
1. **Phase 195 (Multi-Carrier PHI Foundation)**
- `CarrierInfo` tracks arbitrary number of carriers
- Exit PHI generation handles N carriers
- ExitLineReconnector updates variable_map for all carriers
2. **Phase 214 (Dynamic Join Inputs)**
- Removed hardcoded 3-input assumption
- `join_inputs = (0..total_inputs).map(|i| ValueId(i))`
- Automatically scales: 1 loop_var + N carriers = N+1 inputs
3. **Phase 215 (ExprResult Exit Contract)**
- Marks first carrier as expr_result
- Propagates through Boundary → ExitLine → Return
- Works regardless of carrier count
**Result**: The "boxes" compose perfectly!
## Test Case
### Multi-Carrier If-Sum Pattern
**File**: `apps/tests/phase217_if_sum_multi_min.hako`
```hako
static box IfSumMultiTest {
sum_and_count(defs) {
local sum = 0
local count = 0
local i = 0
local len = 3
loop(i < len) {
if i > 0 {
sum = sum + 1 // Carrier 1 (conditional)
count = count + 1 // Carrier 2 (conditional)
print(sum)
print(count)
} else {
print(0)
}
i = i + 1
}
return sum // Returns first carrier
}
main() {
local result = IfSumMultiTest.sum_and_count(0)
return result
}
}
```
**Pattern**:
- Counter: `i` (0 to 2)
- Accumulator 1: `sum` (incremented at i=1, i=2)
- Accumulator 2: `count` (incremented at i=1, i=2)
**Expected**: RC=2 (sum value)
**Actual**: **RC=2**
## Test Results
### Primary Target
| Test File | Carriers | Loop Var | Expected | Actual | Status |
|-----------|----------|----------|----------|--------|--------|
| phase217_if_sum_multi_min.hako | sum+count (2) | i | RC=2 | RC=2 | ✅ PASS |
**Verification**:
```bash
./target/release/nyash apps/tests/phase217_if_sum_multi_min.hako
# Output: (prints 1, 1, 2, 2)
# RC=2
```
### Regression Tests (All Passing)
| Test File | Pattern | Carriers | Expected | Actual | Status |
|-----------|---------|----------|----------|--------|--------|
| loop_if_phi.hako | P3 | sum (1) | RC=2 | RC=2 | ✅ PASS |
| phase212_if_sum_min.hako | P3 | sum (1) | RC=2 | RC=2 | ✅ PASS |
| loop_min_while.hako | P1 | i (1) | RC=2 | RC=2 | ✅ PASS |
## Architecture Verification
### Carrier Detection (Automatic)
Phase 195's `CarrierInfo` automatically detected:
- Carrier 1: `sum` (UpdateKind::AccumulationLike)
- Carrier 2: `count` (UpdateKind::AccumulationLike)
- Loop var: `i` (UpdateKind::CounterLike)
### Dynamic Input Generation (Phase 214)
```rust
// Automatic scaling
let total_inputs = 1 + exit_bindings.len(); // 1 + 2 = 3
let join_inputs: Vec<ValueId> = (0..total_inputs)
.map(|i| ValueId(i as u32))
.collect(); // [ValueId(0), ValueId(1), ValueId(2)]
let host_inputs = vec![
ctx.loop_var_id, // i
exit_binding_0, // sum
exit_binding_1, // count
];
```
### Exit PHI Generation (Phase 195)
```
Loop Header (bb4):
%i_phi = phi [0, bb3], [%i_next, bb14] // Loop variable
%sum_phi = phi [0, bb3], [%sum_exit, bb14] // Carrier 1
%count_phi = phi [0, bb3], [%count_exit, bb14] // Carrier 2
Loop Body (bb5-bb13):
(if-else branches update sum/count conditionally)
Loop Exit (bb14):
%sum_exit = phi [%sum_then, bb_then], [%sum_phi, bb_else]
%count_exit = phi [%count_then, bb_then], [%count_phi, bb_else]
%i_next = add %i_phi, 1
branch bb4 // Loop back with all 3 values
```
### ExprResult Selection (Phase 215)
```rust
// Phase 215: First carrier becomes expr_result
let fragment_meta = JoinFragmentMeta::with_expr_result(
sum_exit, // First carrier (sum)
exit_meta // Contains both sum and count
);
// Result: sum reaches return statement (RC=2)
// count updates variable_map only
```
## Box Theory Validation
Phase 217 proves the **"Everything is Box"** philosophy:
### Box Composition
```
┌─────────────────────────────────────────────┐
│ Phase 195: Multi-Carrier PHI (Box A) │
│ - Handles N carriers automatically │
│ - CarrierInfo + ExitMeta │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Phase 214: Dynamic Inputs (Box B) │
│ - Scales to N+1 inputs automatically │
│ - join_inputs generation │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Phase 215: ExprResult Contract (Box C) │
│ - Selects first carrier for return │
│ - Works regardless of carrier count │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Phase 217: Multi-Carrier If-Sum │
│ - Boxes A + B + C compose perfectly │
│ - ZERO additional code needed │
└─────────────────────────────────────────────┘
```
### Key Insight
**Well-designed boxes compose without modification.**
Each phase created a **reusable box** with clear contracts:
- Box A: "I handle N carriers"
- Box B: "I generate N+1 inputs"
- Box C: "I select expr_result from carriers"
When combined, these boxes **just work** for multi-carrier patterns.
## Lessons Learned
### 1. Fail-Fast Design Pays Off
Phase 195's strict assertions caught problems early:
```rust
debug_assert_eq!(
join_inputs.len(),
host_inputs.len(),
"join_inputs != host_inputs"
);
```
This forced Phase 214 to fix the root cause (hardcoded inputs), which then made Phase 217 trivial.
### 2. Single Responsibility Principle
Each phase had one clear job:
- Phase 195: Multi-carrier **detection and PHI generation**
- Phase 214: Multi-carrier **input scaling**
- Phase 215: Multi-carrier **expr_result selection**
No phase tried to solve everything at once.
### 3. Box-First Development
By treating each capability as a "box" (module with clear interface), we:
- Avoided tight coupling
- Enabled composition
- Made testing independent
- Reduced implementation risk
## Future Work
### Phase 218: Nested If-Else Patterns
- Target: `esc_json()` with nested conditions
- Validates complex if-else inside loops
- Likely needs: ConditionEnv or BoolExprLowerer enhancements
### Phase 219: JsonParser Integration
- Apply multi-carrier if-sum to actual JsonParser loops
- First target: numeric processing with flags
- Validates selfhost compiler real use case
### Phase 220: Variable Limit Conditions
- Support: `loop(i < len)` where `len` is variable (not literal)
- Currently only integer literals supported in if-sum lowerer
- Needs: AST extraction enhancement for variable references
## Files Modified
**ZERO source code files modified** in Phase 217.
**Files Added**:
- `apps/tests/phase217_if_sum_multi_min.hako` (test case)
- `docs/development/current/main/phase217-if-sum-multi.md` (this doc)
## Summary
Phase 217 is a **validation phase** that proves the correctness of the Phase 195/214/215 architecture:
- ✅ Multi-carrier if-sum works with **zero additional code**
- ✅ All regression tests passing
- ✅ Box composition working perfectly
- ✅ Ready for more complex patterns (Phase 218+)
The fact that Phase 217 required **no implementation** is not a bug—it's a **feature** of good box-first design. When boxes compose correctly, new capabilities emerge naturally.
**「箱理論」の勝利!** 🎉
Status: Active
Scope: If-sum multi ケースJoinIR v2