Files
hakorune/docs/development/current/main/phases/phase-253/README.md

84 lines
3.6 KiB
Markdown
Raw Normal View History

feat(joinir): Phase 254-255 - Pattern 6 (ScanWithInit) + exit PHI DCE fix ## Phase 254: Pattern 6 (ScanWithInit) Detection & JoinIR Lowering Pattern 6 detects index_of/find/contains-style loops: - Loop condition: i < x.length() - Loop body: if with method call condition + early return - Step: i = i + 1 - Post-loop: return not-found value (-1) Key features: - Minimal lowering: main/loop_step/k_exit functions - substring hoisted to init-time BoxCall - Two k_exit jumps (found: i, not found: -1) - Tests: phase254_p0_index_of_min.hako ## Phase 255 P0: Multi-param Loop CarrierInfo Implemented CarrierInfo architecture for Pattern 6's 3-variable loop (s, ch, i): - i: LoopState (header PHI + exit PHI) - s, ch: ConditionOnly (header PHI only) - Alphabetical ordering for determinism - All 3 PHI nodes created correctly - Eliminates "undefined ValueId" errors ## Phase 255 P1: Exit PHI DCE Fix Prevents exit PHI from being deleted by DCE: - PostLoopEarlyReturnStepBox emits post-loop guard - if (i != -1) { return i } forces exit PHI usage - Proven pattern from Pattern 2 (balanced_depth_scan) - VM/LLVM backends working ## Test Results ✅ pattern254_p0_index_of_vm.sh: PASS (exit code 1) ✅ pattern254_p0_index_of_llvm_exe.sh: PASS (mock) ✅ Quick profile: json_lint_vm PASS (progresses past index_of) ✅ Pattern 1-5: No regressions ## Files Added - src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs - src/mir/join_ir/lowering/scan_with_init_minimal.rs - apps/tests/phase254_p0_index_of_min.hako - docs/development/current/main/phases/phase-254/README.md - docs/development/current/main/phases/phase-255/README.md 🧠 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-19 23:32:25 +09:00
Status: Completed
Scope: Phase 253 (`--profile quick` 回帰: mutable-acc-spec / accumulator 判定の改善)
Related:
- docs/development/current/main/10-Now.md
- docs/development/current/main/phases/phase-252/README.md
# Phase 253: `json_lint_vm` 回帰mutable-acc-spec
## 現象(最初の FAIL
`./tools/smokes/v2/run.sh --profile quick``json_lint_vm` で失敗する。
エラー:
```
[ERROR] ❌ MIR compilation error: [joinir/mutable-acc-spec] Assignment form not accumulator pattern (required: target = target + x)
```
## 背景(なぜここで落ちるか)
`Pattern2` の pipeline は、ループ本体の代入から「mutable accumulator`x = x + y`)」を検出して
最適化/簡略化に利用する。ところが現在の analyzer が Fail-Fast すぎて、
“accumulator ではない単なる代入” を見つけた時点で Err にしてしまい、JoinIR 経路全体を落としている。
対象 SSOT:
- `src/mir/loop_pattern_detection/mutable_accumulator_analyzer.rs`
## 方針(構造的に直す)
### 原則
- “accumulator pattern を検出できた時だけ” spec を返す。
- それ以外は Err ではなく `Ok(None)` に戻して **別経路(通常 loweringへ譲る**
- 例外として、本当に矛盾があるケースだけ Err例: 同一変数への複数代入など、既に `Ok(None)` にしている)。
### 対処療法の禁止
- 特定関数名(`StringUtils.*`)や特定 script 名(`json_lint_vm`)で分岐しない。
-`-` の時だけ” のような場当たりでなく、spec と契約として整理する。
## 実装タスクP0
### 1) Analyzer の振る舞いを “検出器” に寄せる
ファイル:
- `src/mir/loop_pattern_detection/mutable_accumulator_analyzer.rs`
変更案:
- 以下のケースを `Err` ではなく `Ok(None)` に変更する(= accumulator ではないと判断する)
- `value_node``BinaryOp` ではない(例: `i = s.length() - 1`
- `BinaryOperator``Add` 以外(例: `i = i - 1`
- 左辺が `target` と一致しない(例: `x = y + x`
- RHS が Literal/Variable 以外(例: `x = x + (i + 1)`
目的:
- “accumulator っぽくない代入” が混ざる loop でも、JoinIR 全体を落とさずに進める。
### 2) `-`decrementを accumulator として扱うかの設計を決めるP1 で可)
選択肢:
- A) `i = i - 1` は “accumulator としては未対応” なので `Ok(None)`(安全・最小)
- B) `i = i - 1` を “step=-1” として spec に載せる(将来の表現力は上がるが、下流の取り扱い整備が必要)
まずは quick を緑に戻す目的で A を推奨。
## テスト(仕様固定)
- unit tests を追加して「非 accumulator 代入があっても Err にならず `Ok(None)`」を固定する。
- 例: ループ body に `local i = s.length() - 1` 相当の Assignment があるケース
- 例: `i = i - 1` があるケース
## 受け入れ基準
- `./tools/smokes/v2/run.sh --profile quick` が PASS
- “たまたま `json_lint_vm` だけ通す” ための by-name 分岐を追加していない
- analyzer の戻り値契約が docs と tests で固定されている
## 結果Phase 253 終点)
- `mutable_accumulator_analyzer` は “検出器” として振る舞うようになり、非 accumulator 代入で Err を出さず `Ok(None)` に譲る。
- quick の最初の FAIL は次に切り出しPhase 254:
- `[joinir/freeze] Loop lowering failed: JoinIR does not support this pattern`
- Function: `StringUtils.index_of/2`