Files
hakorune/docs/development/current/main/phases/phase-137/phase-137-4-parity-verification.md
nyash-codex 9ea15e8417 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>
2025-12-16 05:51:57 +09:00

5.7 KiB

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)

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

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

# 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:

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