Files
hakorune/docs/development/current/main/phase166-validation-report.md
nyash-codex e30116f53d feat(joinir): Phase 171-fix ConditionEnv/ConditionBinding architecture
Proper HOST↔JoinIR ValueId separation for condition variables:

- Add ConditionEnv struct (name → JoinIR-local ValueId mapping)
- Add ConditionBinding struct (HOST/JoinIR ValueId pairs)
- Modify condition_to_joinir to use ConditionEnv instead of builder.variable_map
- Update Pattern2 lowerer to build ConditionEnv and ConditionBindings
- Extend JoinInlineBoundary with condition_bindings field
- Update BoundaryInjector to inject Copy instructions for condition variables

This fixes the undefined ValueId errors where HOST ValueIds were being
used directly in JoinIR instructions. Programs now execute (RC: 0),
though loop variable exit values still need Phase 172 work.

Key invariants established:
1. JoinIR uses ONLY JoinIR-local ValueIds
2. HOST↔JoinIR bridging is ONLY through JoinInlineBoundary
3. condition_to_joinir NEVER accesses builder.variable_map

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 01:45:03 +09:00

347 lines
11 KiB
Markdown

# Phase 166 Validation Report: JsonParserBox Unit Test with BoolExprLowerer
**Date**: 2025-12-06 (Updated: 2025-12-07 Phase 170)
**Status**: ⚠️ **Blocked** - ValueId boundary mapping issue
**Blocker**: Condition variables not included in JoinInlineBoundary
**Phase 170 Update**: BoolExprLowerer is now integrated (Phase 167-169), but a critical ValueId boundary mapping bug prevents runtime execution. See [phase170-valueid-boundary-analysis.md](phase170-valueid-boundary-analysis.md) for details.
---
## Phase 170 Re-validation Results (2025-12-07)
After Phase 167-169 (BoolExprLowerer integration), Phase 170 re-tested JsonParserBox with the following results:
### ✅ Whitelist Expansion Complete
- Added 6 JsonParserBox methods to routing whitelist
- Methods now route to JoinIR instead of `[joinir/freeze]`
- Pattern matching works correctly (Pattern2 detected for `_trim`)
### ⚠️ Runtime Failure: ValueId Boundary Issue
**Test**: `local_tests/test_trim_main_pattern.hako`
**Pattern Matched**: Pattern2 (twice, for 2 loops)
**Result**: Silent runtime failure (no output)
**Root Cause**: Condition variables (`start`, `end`) are resolved from HOST `variable_map` but not included in `JoinInlineBoundary`, causing undefined ValueId references.
**Evidence**:
```
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(12) inst_idx=0 used=ValueId(33)
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(12) inst_idx=0 used=ValueId(34)
```
**Solution**: Option A in [phase170-valueid-boundary-analysis.md](phase170-valueid-boundary-analysis.md) - Extract condition variables and add to boundary.
---
## Executive Summary (Original Phase 166)
Phase 166 aimed to validate that JsonParserBox can parse JSON through the JoinIR path, confirming Pattern1-4 support. However, investigation revealed that:
1. **✅ JoinIR Pattern Detection Works**: Pattern 2 (break) correctly detected ← **Still true in Phase 170**
2. **✅ Simple JSON Parsing Works**: Non-loop or simple-condition patterns execute fine
3. **~~❌ Complex Conditions Blocked~~** ← **FIXED in Phase 169**: BoolExprLowerer integrated
4. **❌ NEW BLOCKER (Phase 170)**: ValueId boundary mapping prevents runtime execution
---
## Test Results
### ✅ Test 1: Simple JSON Parser (No Loops)
**File**: `local_tests/test_json_parser_simple_string.hako`
```bash
./target/release/hakorune local_tests/test_json_parser_simple_string.hako
# Output: PASS: Got 'hello'
```
**Result**: **SUCCESS** - Basic string parsing without complex conditions works.
---
### ❌ Test 2: _trim Pattern with OR Chains
**File**: `local_tests/test_trim_or_pattern.hako`
```bash
./target/release/hakorune local_tests/test_trim_or_pattern.hako
# Output: [joinir/freeze] Loop lowering failed
```
**Result**: **BLOCKED** - OR condition causes `[joinir/freeze]` error.
---
### ⚠️ Test 3: _trim Pattern in main() with Simple Condition
**File**: `local_tests/test_trim_main_pattern.hako`
```bash
./target/release/hakorune local_tests/test_trim_main_pattern.hako
# Output: FAIL - Result: ' hello ' (not trimmed)
```
**Result**: **PATTERN DETECTED BUT LOGIC WRONG** - Pattern 2 matches, but uses hardcoded `i < 3` instead of actual condition.
**Debug Output**:
```
[trace:pattern] route: Pattern2_WithBreak MATCHED
[trace:varmap] pattern2_start: end→r9, s→r4, start→r6
Final start: 0 (unchanged - loop didn't execute properly)
```
---
## Root Cause Analysis
### Discovery 1: Function Name Whitelisting
**File**: `src/mir/builder/control_flow/joinir/routing.rs` (lines 44-68)
JoinIR is **ONLY enabled for specific function names**:
- `"main"`
- `"JoinIrMin.main/0"`
- `"JsonTokenizer.print_tokens/0"`
- `"ArrayExtBox.filter/2"`
**Impact**: `JsonParserBox._trim/1` is NOT whitelisted → `[joinir/freeze]` error.
**Workaround**: Test in `main()` function instead.
---
### Discovery 2: Hardcoded Conditions in Minimal Lowerers
**File**: `src/mir/join_ir/lowering/loop_with_break_minimal.rs` (lines 171-197)
```rust
// HARDCODED: !(i < 3)
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: const_3,
value: ConstValue::Integer(3), // ← HARDCODED VALUE
}));
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
dst: cmp_lt,
op: CompareOp::Lt, // ← HARDCODED OPERATOR
lhs: i_param,
rhs: const_3,
}));
```
**Impact**: Pattern 2 lowerer generates fixed `i < 3` check, **ignoring the actual AST condition**.
**Current Behavior**:
- AST condition: `start < end` with `ch == " "` check
- Generated JoinIR: `i < 3` with `i >= 2` break check
- Result: Loop doesn't execute correctly
---
### Discovery 3: BoolExprLowerer Not Integrated
**Files**:
- `src/mir/join_ir/lowering/bool_expr_lowerer.rs` (Phase 167-168, 436 lines, complete)
- `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs` (line 58)
```rust
// Current code:
let loop_var_name = self.extract_loop_variable_from_condition(condition)?;
// Missing:
// use crate::mir::join_ir::lowering::bool_expr_lowerer::BoolExprLowerer;
// let mut bool_lowerer = BoolExprLowerer::new(self.builder);
// let cond_val = bool_lowerer.lower_condition(&ctx.condition)?;
```
**Impact**: BoolExprLowerer exists but isn't called by Pattern 2/4 lowerers.
---
### Discovery 4: LoopBuilder Hard Freeze
**File**: `src/mir/builder/control_flow/mod.rs` (lines 112-119)
```rust
// Phase 186: LoopBuilder Hard Freeze - Legacy path disabled
// Phase 187-2: LoopBuilder module removed - all loops must use JoinIR
return Err(format!(
"[joinir/freeze] Loop lowering failed: JoinIR does not support this pattern, and LoopBuilder has been removed.\n\
Function: {}\n\
Hint: This loop pattern is not supported. All loops must use JoinIR lowering.",
self.current_function.as_ref().map(|f| f.signature.name.as_str()).unwrap_or("<unknown>")
));
```
**Impact**: NO fallback exists when JoinIR patterns don't match.
---
## Architecture Issues
### Issue 1: Minimal Lowerers Are Test-Specific
**Design**: Pattern 1-4 lowerers are "minimal implementations" for specific test cases:
- Pattern 1: `apps/tests/joinir_simple_loop.hako` (`i < 5`)
- Pattern 2: `apps/tests/joinir_min_loop.hako` (`i < 3`, `i >= 2`)
- Pattern 3: `apps/tests/loop_if_phi_sum.hako` (hardcoded sum accumulation)
- Pattern 4: `apps/tests/loop_continue_pattern4.hako` (hardcoded continue logic)
**Problem**: These lowerers are **NOT** generic - they can't handle arbitrary conditions.
---
### Issue 2: Condition Extraction vs. Evaluation
**Current**:
- `extract_loop_variable_from_condition()` - Extracts variable name (`i`, `start`)
- Used for: Carrier detection, not condition evaluation
- Only supports: Simple comparisons like `i < 3`
**Missing**:
- Dynamic condition evaluation (BoolExprLowerer)
- OR chain support
- Complex boolean expressions
---
### Issue 3: JoinIR Generation Architecture
**Current Pipeline**:
```
AST Loop → Pattern Detection → Hardcoded JoinIR Generator
Fixed condition (i < 3)
```
**Needed Pipeline**:
```
AST Loop → Pattern Detection → BoolExprLowerer → Dynamic JoinIR Generator
↓ ↓
Condition MIR → Convert to JoinInst
```
---
## Phase 166 Status Update
### ✅ Completed Validation
1. **Pattern Detection**: Pattern 2 (break) correctly identified
2. **Simple Cases**: Non-loop JSON parsing works
3. **Infrastructure**: JoinIR pipeline functional
4. **Whitelist Behavior**: Function name routing confirmed
### ❌ Remaining Blockers
1. **OR Chains**: `ch == " " || ch == "\t"...` not supported
2. **Dynamic Conditions**: Hardcoded `i < 3` instead of actual condition
3. **BoolExprLowerer Integration**: Phase 167-168 code not used
4. **JsonParserBox._trim**: Cannot execute due to whitelisting
---
## Recommended Next Steps
### Phase 169: BoolExprLowerer Integration (HIGH PRIORITY)
**Goal**: Make JoinIR patterns support arbitrary conditions.
**Tasks**:
1. **Modify Pattern 2 Lowerer** (`loop_with_break_minimal.rs`):
- Accept `condition: &ASTNode` parameter
- Call `BoolExprLowerer::lower_condition(condition)`
- Generate JoinIR instructions from condition MIR
- Replace hardcoded `const_3`, `cmp_lt` with dynamic values
2. **Modify Pattern 4 Lowerer** (`loop_with_continue_minimal.rs`):
- Same changes as Pattern 2
3. **Update Caller** (`pattern2_with_break.rs`):
- Pass `ctx.condition` to lowerer
- Handle condition evaluation errors
4. **Test Coverage**:
- `_trim` pattern with OR chains
- Complex boolean expressions
- Nested conditions
**Estimated Effort**: 2-3 hours (architecture already designed in Phase 167-168)
---
### Phase 170: Function Whitelist Expansion (MEDIUM PRIORITY)
**Goal**: Enable JoinIR for JsonParserBox methods.
**Options**:
1. **Option A**: Add to whitelist:
```rust
"JsonParserBox._trim/1" => true,
"JsonParserBox._skip_whitespace/2" => true,
```
2. **Option B**: Enable JoinIR globally for all functions:
```rust
let is_target = true; // Always try JoinIR first
```
3. **Option C**: Add pattern-based routing (e.g., all `_trim*` functions)
**Recommended**: Option A (conservative, safe)
---
### Phase 171: JsonParserBox Full Validation (POST-169)
**Goal**: Validate all JsonParserBox methods work through JoinIR.
**Tests**:
- `_trim` (OR chains)
- `_skip_whitespace` (OR chains)
- `_parse_number` (digit loop)
- `_parse_string` (escape sequences)
- `_parse_array` (recursive calls)
- `_parse_object` (key-value pairs)
---
## Files Modified This Session
### Created Test Files
1. `local_tests/test_json_parser_simple_string.hako` - Simple JSON test (PASS)
2. `local_tests/test_trim_or_pattern.hako` - OR chain test (BLOCKED)
3. `local_tests/test_trim_simple_pattern.hako` - Simple condition test (BLOCKED)
4. `local_tests/test_trim_main_pattern.hako` - Whitelisted function test (WRONG LOGIC)
5. `local_tests/test_trim_debug.hako` - Debug output test
### Documentation
1. `docs/development/current/main/phase166-validation-report.md` (this file)
---
## Conclusion
**Phase 166 Validation Status**: ⚠️ **Partially Complete**
**Key Findings**:
1. JoinIR Pattern Detection **works correctly**
2. Simple patterns **execute successfully**
3. Complex OR chains **are blocked** by hardcoded conditions
4. BoolExprLowerer (Phase 167-168) **exists but isn't integrated**
**Next Critical Phase**: **Phase 169 - BoolExprLowerer Integration** to unblock JsonParserBox._trim and enable dynamic condition evaluation.
**Timeline**:
- Phase 169: 2-3 hours (integration work)
- Phase 170: 30 minutes (whitelist update)
- Phase 171: 1 hour (full validation testing)
**Total Estimated Time to Complete Phase 166**: 4-5 hours
---
## References
- **Phase 166 Goal**: `docs/development/current/main/phase166-joinir-json-parser-validation.md`
- **Phase 167-168**: `src/mir/join_ir/lowering/bool_expr_lowerer.rs`
- **Pattern 2 Lowerer**: `src/mir/join_ir/lowering/loop_with_break_minimal.rs`
- **Routing Logic**: `src/mir/builder/control_flow/joinir/routing.rs`
- **LoopBuilder Freeze**: `src/mir/builder/control_flow/mod.rs` (lines 112-119)