feat(mir): Loop Canonicalizer Phase 4 - router parity verification
## Summary
既存 Router と Canonicalizer の選択が一致することを dev-only で検証。
不一致は理由付き Fail-Fast(strict mode)。
## Changes
- src/mir/builder/control_flow/joinir/routing.rs:
- verify_router_parity() 実装
- cf_loop_joinir_impl でパリティチェック呼び出し
- 2つのユニットテスト追加
- test_parity_check_mismatch_detected
- test_parity_check_match_simple_while
- docs/development/current/main/phases/phase-137/phase-137-4-parity-verification.md:
- Phase 4 完全ドキュメント
## Verification Modes
- Debug mode (HAKO_JOINIR_DEBUG=1): ログのみ
- Strict mode (HAKO_JOINIR_STRICT=1): 不一致でエラー
## Known Mismatch
- skip_whitespace pattern:
- Canonicalizer: Pattern3IfPhi (構造認識)
- Router: Pattern2Break (has_break優先)
- Phase 5+ で分類ルール改善予定
## Tests
- Unit tests: 2 tests PASS
- Integration: skip_whitespace parity mismatch 検出確認
- cargo test --release --lib: 1046/1046 PASS
Phase 137-4 complete
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,197 @@
|
||||
# Phase 137-4: Loop Canonicalizer Router Parity Verification
|
||||
|
||||
**Status**: ✅ Complete
|
||||
**Date**: 2025-12-16
|
||||
|
||||
## Summary
|
||||
|
||||
Dev-only verification that Loop Canonicalizer and Router pattern detection agree on pattern classification. On mismatch, provides detailed diagnostic with Fail-Fast option.
|
||||
|
||||
## Implementation
|
||||
|
||||
### Location
|
||||
|
||||
`src/mir/builder/control_flow/joinir/routing.rs`
|
||||
|
||||
### Components
|
||||
|
||||
1. **Parity Verification Function** (`verify_router_parity`)
|
||||
- Runs canonicalizer on the loop AST
|
||||
- Compares canonicalizer's chosen pattern with router's `ctx.pattern_kind`
|
||||
- Logs match/mismatch results
|
||||
- In strict mode, returns error on mismatch
|
||||
|
||||
2. **Integration Point**
|
||||
- Called in `cf_loop_joinir_impl` after `LoopPatternContext` is created
|
||||
- Only runs when `joinir_dev_enabled()` returns true
|
||||
- Deferred until after ctx creation to access `ctx.pattern_kind`
|
||||
|
||||
### Behavior Modes
|
||||
|
||||
#### Debug Mode (Default)
|
||||
```bash
|
||||
HAKO_JOINIR_DEBUG=1 ./target/release/hakorune program.hako
|
||||
```
|
||||
- Logs parity check results to stderr
|
||||
- On mismatch: Logs warning but continues execution
|
||||
- On match: Logs success message
|
||||
|
||||
#### Strict Mode
|
||||
```bash
|
||||
HAKO_JOINIR_STRICT=1 ./target/release/hakorune program.hako
|
||||
```
|
||||
- Same as debug mode, but on mismatch:
|
||||
- Returns error and stops compilation
|
||||
- Provides detailed mismatch diagnostic
|
||||
|
||||
### Output Examples
|
||||
|
||||
#### Match (Success)
|
||||
```
|
||||
[loop_canonicalizer/PARITY] OK in function 'foo':
|
||||
canonical and actual agree on Pattern1SimpleWhile
|
||||
```
|
||||
|
||||
#### Mismatch (Warning in Debug)
|
||||
```
|
||||
[loop_canonicalizer/PARITY] MISMATCH in function 'main':
|
||||
canonical=Pattern3IfPhi, actual=Pattern2Break
|
||||
```
|
||||
|
||||
#### Mismatch (Error in Strict)
|
||||
```
|
||||
[ERROR] ❌ MIR compilation error:
|
||||
[loop_canonicalizer/PARITY] MISMATCH in function 'main':
|
||||
canonical=Pattern3IfPhi, actual=Pattern2Break
|
||||
```
|
||||
|
||||
#### Canonicalizer Failure
|
||||
```
|
||||
[loop_canonicalizer/PARITY] Canonicalizer failed for 'bar':
|
||||
Phase 3: Loop does not match skip_whitespace pattern
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Unit Tests
|
||||
|
||||
1. **`test_parity_check_mismatch_detected`**
|
||||
- Verifies mismatch detection on skip_whitespace pattern
|
||||
- Canonicalizer: Pattern3IfPhi (recognizes if-else structure)
|
||||
- Router: Pattern2Break (sees has_break flag)
|
||||
- Asserts inequality to document expected mismatch
|
||||
|
||||
2. **`test_parity_check_match_simple_while`**
|
||||
- Verifies canonicalizer fails on Pattern1 (not yet implemented)
|
||||
- Router: Pattern1SimpleWhile
|
||||
- Canonicalizer: Fail-Fast (only supports skip_whitespace in Phase 3)
|
||||
|
||||
### Integration Tests
|
||||
|
||||
```bash
|
||||
# Verify mismatch detection (debug mode)
|
||||
HAKO_JOINIR_DEBUG=1 ./target/release/hakorune \
|
||||
tools/selfhost/test_pattern3_skip_whitespace.hako
|
||||
|
||||
# Verify strict mode error
|
||||
HAKO_JOINIR_STRICT=1 ./target/release/hakorune \
|
||||
tools/selfhost/test_pattern3_skip_whitespace.hako
|
||||
# Expected: Exit with error due to mismatch
|
||||
```
|
||||
|
||||
## Known Mismatches
|
||||
|
||||
### skip_whitespace Pattern
|
||||
|
||||
**Structure**:
|
||||
```nyash
|
||||
loop(p < len) {
|
||||
if is_ws == 1 {
|
||||
p = p + 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Mismatch**:
|
||||
- **Canonicalizer**: Pattern3IfPhi
|
||||
- Recognizes specific if-else structure with conditional carrier update
|
||||
- Sees: `if cond { carrier += 1 } else { break }` as Pattern3 variant
|
||||
|
||||
- **Router**: Pattern2Break
|
||||
- Classification based on `has_break` flag
|
||||
- Priority: break detection takes precedence over if-else structure
|
||||
|
||||
**Resolution Strategy**:
|
||||
- Phase 4: Document and observe (current)
|
||||
- Phase 5+: Refine classification rules to handle hybrid patterns
|
||||
- Option A: Extend Pattern3 to include "break-in-else" variant
|
||||
- Option B: Create new Pattern6 for this specific structure
|
||||
- Option C: Make router defer to canonicalizer's decision
|
||||
|
||||
## Design Rationale
|
||||
|
||||
### Why Two Systems?
|
||||
|
||||
1. **Router (Existing)**
|
||||
- Feature-based classification (`has_break`, `has_continue`, etc.)
|
||||
- Fast, simple flags
|
||||
- Priority-based (e.g., break > if-else)
|
||||
|
||||
2. **Canonicalizer (New)**
|
||||
- Structure-based pattern matching
|
||||
- Deep AST analysis
|
||||
- Recognizes specific code idioms
|
||||
|
||||
### Why Parity Check?
|
||||
|
||||
- **Incremental Migration**: Allows canonicalizer development without breaking router
|
||||
- **Safety Net**: Catches classification divergence early
|
||||
- **Documentation**: Explicitly records where systems disagree
|
||||
- **Flexibility**: Dev-only, no production overhead
|
||||
|
||||
### Why Dev-Only?
|
||||
|
||||
- **No Performance Impact**: Zero cost in release builds (flag-gated)
|
||||
- **Development Insight**: Helps refine both systems
|
||||
- **Fail-Fast Option**: Strict mode for CI/validation
|
||||
- **Graceful Degradation**: Debug mode allows execution to continue
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- ✅ Flag OFF: No behavioral change
|
||||
- ✅ Dev-only: Match/mismatch observable
|
||||
- ✅ Strict mode: Mismatch stops compilation
|
||||
- ✅ Debug mode: Mismatch logs warning
|
||||
- ✅ Unit tests: 2 tests passing
|
||||
- ✅ Integration test: skip_whitespace mismatch detected
|
||||
- ✅ All tests: `cargo test --release --lib` passes (1046/1046)
|
||||
|
||||
## Future Work
|
||||
|
||||
### Phase 5: Pattern Classification Refinement
|
||||
|
||||
- Resolve skip_whitespace classification (Pattern2 vs Pattern3)
|
||||
- Extend Pattern3 to handle break-in-else variant
|
||||
- OR: Create Pattern6 for "conditional update with early exit"
|
||||
|
||||
### Phase 6: Canonicalizer Expansion
|
||||
|
||||
- Add Pattern1 (Simple While) to canonicalizer
|
||||
- Add Pattern2 (Conditional Break) variants
|
||||
- Add Pattern4 (Continue) support
|
||||
- Add Pattern5 (Infinite Early Exit) support
|
||||
|
||||
### Phase 7: Router Migration
|
||||
|
||||
- Consider migrating router to use canonicalizer decisions
|
||||
- Option: Make `ctx.pattern_kind = decision.chosen` if canonicalizer succeeds
|
||||
- Gradual transition from feature-based to structure-based routing
|
||||
|
||||
## References
|
||||
|
||||
- **Phase 137-2**: Loop Canonicalizer observation (dev-only logging)
|
||||
- **Phase 137-3**: skip_whitespace pattern recognition
|
||||
- **Design SSOT**: `docs/development/current/main/design/loop-canonicalizer.md`
|
||||
- **JoinIR Architecture**: `docs/development/current/main/joinir-architecture-overview.md`
|
||||
Reference in New Issue
Block a user