## 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>
Status: Completed
Scope: Phase 252 (JoinIR Pattern2 break 条件: this.methodcall(...) 対応 + policy SSOT)
Related:
- docs/development/current/main/10-Now.md
- docs/development/current/main/phases/phase-251/README.md
Phase 252: Pattern2 break 条件の this.methodcall(...) 対応
目的
--profile quickのjson_lint_vmで露出した JoinIR Pattern2 の回帰を潰す。- 具体的には
if not this.is_whitespace(s.substring(i, i + 1)) { break }のようなthis.methodcall(...)を break 条件として lowering できるようにする。
実装(P0/P1: 完了)
1) ユーザー定義メソッドの許可ポリシー(SSOT)
ファイル:
src/mir/join_ir/lowering/user_method_policy.rs
要点:
- CoreMethodId(builtin)とは別に、
this.methodcall(...)の「許可」を一箇所に集約する。 - by-name の if 分岐で散らさず、ポリシーテーブルとして SSOT 化する。
2) ConditionLowerer: ASTNode::MethodCall(object: Me, ...) の受理
ファイル:
src/mir/join_ir/lowering/condition_lowerer.rs
要点:
- break 条件のトップレベルが
MethodCall(Me, ...)の場合に lowering できる分岐を追加。 thisの所属 box 名はcurrent_static_box_nameを経由して受け取る(固定名分岐しない)。
3) current_static_box_name の配線(Pattern2 まで)
変更点:
ConditionContextにcurrent_static_box_nameを追加- Pattern2 lowering 入力(inputs)から break/header 条件 lowering まで
current_static_box_nameを伝搬
注:
- ここは “構造” による情報伝達であり、特定関数名での回避分岐(ハードコード)ではない。
4) 局所リファクタ(DebugOutputBox 統一)
ファイル:
src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs
要点:
- 無条件/散在ログを追加しない方針を維持しつつ、出力 API を
DebugOutputBoxに統一する。 - デフォルトでは出力ゼロ(smoke の期待出力を壊さない)。
5) テスト/fixture の追加
- unit tests を追加(
this.methodcall(...)条件の lowering 回帰固定) - v2 smoke fixture を追加(integration profile)
検証状況(Phase 252 終点)
cargo checkが通る(0 errors、warnings のみ)--profile quickの最初の FAIL は次に切り出し(Phase 253):[joinir/mutable-acc-spec] Assignment form not accumulator pattern (required: target = target + x)
次の作業(Phase 253)
次の SSOT: docs/development/current/main/phases/phase-253/README.md