## Task A: Loop Invariants Architecture (Option A - Boundary Extension) Introduced explicit loop_invariants concept for variables that are: - Used in loop body but never modified (e.g., substring needle in index_of) - Need header PHI (all iterations use same value) - Do NOT need exit PHI (not a LoopState) Implementation: - Added `loop_invariants: Vec<(String, ValueId)>` field to JoinInlineBoundary - Added `with_loop_invariants()` method to JoinInlineBoundaryBuilder - Modified Pattern 6 to use loop_invariants instead of ConditionOnly misuse * s (haystack) and ch (needle) now properly classified * exit_bindings simplified to only LoopState carriers - Extended LoopHeaderPhiBuilder to generate invariant PHIs * Entry PHI: from host * Latch PHI: self-reference (same value every iteration) - Updated instruction_rewriter to handle invariant latch incoming Files Modified: - src/mir/join_ir/lowering/inline_boundary.rs (structure + builder) - src/mir/join_ir/lowering/inline_boundary_builder.rs (builder method) - src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs - src/mir/builder/control_flow/joinir/merge/loop_header_phi_builder.rs - src/mir/builder/control_flow/joinir/merge/mod.rs - src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs ## Task B: Code Quality - var() Helper Unification Created common module to eliminate var() duplication: - New module: src/mir/builder/control_flow/joinir/patterns/common/ - Centralized var() helper in ast_helpers.rs - Updated Pattern 6 and Pattern 2 to use common var() - Test code (5 occurrences) deferred to Phase 256+ per 80/20 rule Result: Eliminated 2 duplicate var() functions, 5 test occurrences remain Files Created: - src/mir/builder/control_flow/joinir/patterns/common/ast_helpers.rs - src/mir/builder/control_flow/joinir/patterns/common/mod.rs Files Modified: - src/mir/builder/control_flow/joinir/patterns/mod.rs - src/mir/builder/control_flow/joinir/patterns/pattern6_scan_with_init.rs - src/mir/builder/control_flow/joinir/patterns/policies/balanced_depth_scan_policy.rs ## Task C: Documentation - PostLoopEarlyReturnPlan Usage Examples Enhanced post_loop_early_return_plan.rs with: - Architecture explanation (exit PHI usage prevents DCE) - Pattern 2 example (Less: balanced_depth_scan) - Pattern 6 example (NotEqual: index_of) - Builder defer decision: when 4+ patterns emerge, add builder Files Modified: - src/mir/builder/control_flow/joinir/patterns/policies/post_loop_early_return_plan.rs ## Task D: Phase 256 Preparation Analyzed next failure from smoke tests: - `StringUtils.split/2` with variable-step loop - Not constant step (i += len or similar) - Three implementation options identified Created Phase 256 README with: - Minimal reproduction code - Root cause analysis - Implementation options with trade-offs - Clear next steps Files Created: - docs/development/current/main/phases/phase-256/README.md ## Verification Results ✅ All tests passing: - pattern254_p0_index_of_vm.sh: PASS - No regression in Pattern 1-5 - Smoke test progresses past json_lint_vm to next failure ✅ Architecture achievements: - Semantic clarity: loop_invariants vs exit_bindings properly separated - ConditionOnly misuse eliminated - PHI generation correct for all carrier types - Code quality: var() duplication reduced - Next phase clearly defined ## Summary Phase 255 P2 achieves root-cause fix for multi-param loop support: - Boundary concept expanded (loop_invariants field) - Pattern 6 architecture corrected (no ConditionOnly misuse) - Code quality improved (var() centralized) - Next pattern (variable-step) is now the challenge ✨ Box-first principles maintained: clean separation, explicit roles, minimal coupling 🧠 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
4.4 KiB
4.4 KiB
Phase 256: StringUtils.split/2 Pattern Support
Status: Planning Scope: Loop pattern recognition for split/tokenization operations Related:
- Phase 255 完了(loop_invariants 導入、Pattern 6 完成)
- Phase 254 完了(Pattern 6 index_of 実装)
失敗詳細
テスト: json_lint_vm (quick profile)
エラー: [joinir/freeze] Loop lowering failed: JoinIR does not support this pattern
関数: StringUtils.split/2
エラーメッセージ全体
[trace:dev] loop_canonicalizer: Decision: FAIL_FAST
[trace:dev] loop_canonicalizer: Missing caps: [ConstStep]
[trace:dev] loop_canonicalizer: Reason: Phase 143-P2: Loop does not match read_digits(loop(true)),
skip_whitespace, parse_number, continue, parse_string, or parse_array pattern
[ERROR] ❌ MIR compilation error: [joinir/freeze] Loop lowering failed: JoinIR does not support this pattern,
and LoopBuilder has been removed.
Function: StringUtils.split/2
Hint: This loop pattern is not supported. All loops must use JoinIR lowering.
期待される動作
StringUtils.split(s, separator) が正常にコンパイルされ、文字列分割が動作すること。
実際の動作
Loop canonicalizer が ConstStep を要求しているが、このループはステップが複雑で定数ではない。
最小再現コード
split(s, separator) {
local result = new ArrayBox()
// Early return for empty separator
if separator.length() == 0 {
result.push(s)
return result
}
local start = 0
local i = 0
// Main scan loop
loop(i <= s.length() - separator.length()) {
if s.substring(i, i + separator.length()) == separator {
result.push(s.substring(start, i))
start = i + separator.length()
i = start // Variable step - moves by separator.length()
} else {
i = i + 1 // Constant step - moves by 1
}
}
// Push remaining segment
if start <= s.length() {
result.push(s.substring(start, s.length()))
}
return result
}
分析
ループ構造
- 条件:
i <= s.length() - separator.length() - ボディ:
- If branch: マッチング検出時
result.push()でセグメント追加start = i + separator.length()で次の開始位置更新i = startで大きくジャンプ(可変ステップ)
- Else branch: マッチなし
i = i + 1で 1 進む(定数ステップ)
- If branch: マッチング検出時
- 特徴:
- 可変ステップ: マッチング時は
separator.length()分ジャンプ - 複数キャリア:
i,start,resultを更新 - MethodCall:
substring(),push(),length()を使用
- 可変ステップ: マッチング時は
Canonicalizer の問題
Missing caps: [ConstStep]
- 既存の Pattern 1-6 は定数ステップを想定
- このループは条件分岐で異なるステップ幅を使う
- Pattern 2 (balanced_depth_scan) に近いが、可変ステップがネック
実装計画
Option A: Pattern 7 - Split/Tokenization Pattern
新しいパターン追加:
- 可変ステップサポート
- 複数キャリア(i, start, accumulator)
- If-else での異なるステップ幅処理
検出条件:
- Loop condition:
i <= expr - len - Body has if statement:
- Then:
i = something_big(可変ジャンプ) - Else:
i = i + 1(定数ステップ)
- Then:
- Accumulator への追加操作 (
pushなど)
Option B: Pattern 2 拡張
既存 Pattern 2 を拡張:
- ConstStep 要件を緩和
- If-else で異なるステップ幅を許可
- balanced_depth_scan_policy を拡張
Option C: Normalization 経路
ループ正規化で対応:
- 可変ステップを定数ステップに変換
- Carrier 追加で状態管理
次のステップ
- StepTree 詳細解析: split ループの完全な AST 構造確認
- 類似パターン調査: 他の可変ステップループ(indexOf, contains など)
- Option 選択: Pattern 7 新設 vs Pattern 2 拡張 vs Normalization
- 実装戦略策定: 選択した Option の詳細設計
備考
- Phase 255 で loop_invariants が導入されたが、このケースは invariants 以前の問題(可変ステップ)
- Phase 254-256 の流れで Pattern 6 → Pattern 7 の自然な進化が期待される
- split/tokenization は一般的なパターンなので、汎用的な解決策が望ましい