diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 18c01e60..8d0019c8 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -1,876 +1,103 @@ # Current Task -このファイルは「いま何に集中しているか」と「次にやる候補」だけを書く軽量ビューに戻すよ。 -過去フェーズの詳細ログは `docs/development/current/main/10-Now.md` と各 `phase-XX*.md` に残してあるので、履歴はそちらを見てね。 +このファイルは「いま何に集中しているか」と「次にやり得る候補」だけを書く軽量ビューだよ。 +詳細ログや過去フェーズの記録は `docs/development/current/main/` 以下の各 `phase-*.md` と +`joinir-architecture-overview.md` を真実のソースとして扱うことにするね。 --- -## 🎯 今フォーカスしているテーマ +## 🎯 今フォーカスしているテーマ(2025-12-09 時点のスナップショット) -### 1. JoinIR ループ基盤 → JsonParser / Trim への適用 +### 1. JoinIR ループ基盤の状態 -- 現状 - - LoopBuilder は完全削除済み。ループは JoinIR Pattern1–4(while / break / if‑PHI / continue)で統一。 - - LoopExit / ExitLine / Boundary / Header PHI のラインは代表ケース(Pattern1–4)で安定。 - - LoopConditionScopeBox(Phase 170‑D)はバグ修正済みで、 - - ループ条件に出てくる変数を `LoopParam / OuterLocal / LoopBodyLocal` に分類 - - 関数パラメータや外側ローカル(例: `s`, `pos`, `len`)は正しく OuterLocal と判定できるようになった。 -- 直近の目的 - - JsonParserBox / Trim 系ループを、Pattern1–4 + LoopConditionScopeBox の上にどこまで安全に載せられるかを再観測する。 - - LoopBodyLocal を条件に含むパターン(Trim の `ch` など)を、Pattern5 でどう扱うか設計する。 -- 次にやる候補 - - [x] Phase 171‑A: LoopConditionScope 修正版で JsonParser / Trim ループの再インベントリ ✅ - → どのループが Pattern1–4 内に入り、どれが LoopBodyLocal 条件で弾かれているかを整理。 - - [x] Phase 171‑B: Pattern5‑A のターゲット決定 ✅ - → Trim の leading whitespace ループを代表として選定。 - - [x] Phase 171‑C-1: LoopBodyCarrierPromoter スケルトン実装 ✅ - → API 定義(PromotionRequest → PromotionResult)、基本検出ロジック。 - - [x] Phase 171‑C-2: Trim パターン昇格ロジック実装 ✅ - → `find_definition_in_body()`, `is_substring_method_call()`, `extract_equality_literals()` 実装。 - → `TrimPatternInfo` で検出結果を返す。10 unit tests。 - - [x] Phase 171‑C-3: Pattern 2/4 ルーティングとの統合 ✅ - → routing.rs で LoopBodyCarrierPromoter を呼び出し、昇格可能なら Pattern2 へルート。 - - [x] Phase 171‑C-4: CarrierInfo への統合 ✅ (2025-12-07) - → `CarrierInfo::merge_from()` で昇格後のキャリアをマージ。 - → `TrimPatternInfo::to_carrier_info()` で変換ヘルパ実装。 - → Pattern2/4 lowerer で `Promoted` ブランチをマージに更新。7 unit tests。 - - [x] Phase 171‑C-5: TrimLoopHelper 設計 ✅ (2025-12-07) - → `TrimLoopHelper` struct で Trim 専用ロジックを一箇所に集約。 - → `CarrierInfo::trim_helper()` アクセサ追加。4 unit tests。 - - [x] Phase 171‑impl-Trim: Trim 用 JoinIR 生成 ✅ (2025-12-08) - → `CarrierInfo::trim_helper()` を使って bool carrier の初期化・更新・exit PHI を生成。 - - [x] Phase 172-Trim-impl: Trim 用 MIR 生成 ✅ (2025-12-08) - → Pattern2 で Trim パターンの JoinIR→MIR lowering 実装完了。 - → emit_whitespace_check(), extract_substring_args() ヘルパ追加。 - - [x] Phase 173: JsonParser P5 展開 ✅ (2025-12-08) - → Task 173-1: JsonParser 代表ループの再チェック(_skip_whitespace 選定)。 - → Task 173-2: 「Trim と同型」なループを 1 本選定(_skip_whitespace 確定)。 - → Task 173-3: Trim 用 P5 パイプラインを JsonParser 用にも開放する設計(設計ドキュメント作成)。 - → Task 173-4: 1 本だけ実際に JoinIR で通す(_skip_whitespace Pattern detection 成功)。 - → Task 173-5: ドキュメント更新(phase173-jsonparser-p5-impl.md + CURRENT_TASK)。 - → **成果**: Trim パイプラインが JsonParser でも機能することを実証、P5 の汎用性が完全証明された。 - - [x] Phase 200: JoinIR パイプライン Cleanup (Part 1) ✅ (2025-12-08) - → Task 200-1: Pattern × Box マトリクス表をドキュメント化(loop_pattern_space.md に追加)。 - → Task 200-2: JoinInlineBoundaryBuilder 導入(Pattern2 で試験導入、Builder パターンで構築統一化)。 - → Task 200-3: JoinIRVerifier 追加(LoopHeader PHI / ExitLine 契約のデバッグ検証)。 - → Task 200-4: CURRENT_TASK/overview 微修正(Phase 200 内容を反映)。 - - [x] Phase 201: JoinInlineBoundaryBuilder Pattern3/4 展開 ✅ (2025-12-08) - → Task 201-1: Pattern2 の Builder 使用パターンを正として固める(設計ドキュメント作成)。 - → Task 201-2: Pattern3 を Builder に載せ替え(フィールド直書き排除)。 - → Task 201-3: Pattern4 を Builder に載せ替え(continue/Trim 特例対応)。 - → Task 201-4: 共通ルールチェック & unit test 拡張(2つの新テスト追加)。 - → Task 201-5: ドキュメント更新(overview + CURRENT_TASK)。 - → **成果**: 全パターン(P1/P2/P3/P4)で Builder 統一完了、フィールド直書き完全排除、挙動不変(テスト全 PASS)。 - - [x] Phase 174: JsonParser 複雑ループ P5 拡張(設計+1本め) ✅ (2025-12-08) - → Task 174-1: 残り JsonParser ループの再チェック(_parse_string/_parse_array/_parse_object 分析)。 - → Task 174-2: 「次に攻める1本」を決定(_parse_string 選定、Trim に最も近い構造)。 - → Task 174-3: 箱の再利用 vs 追加を決定(TrimLoopHelper 再利用可能、最小化版で検証)。 - → Task 174-4: 小さな PoC を 1 本動かす(_parse_string 最小化版で P5 パイプライン成功)。 - → Task 174-5: ドキュメント更新(phase174-jsonparser-p5b-design.md + CURRENT_TASK)。 - → **成果**: Trim P5 パイプラインが `_parse_string` 最小化版でも機能することを実証。 - 文字比較対象が `"\""`(終端クォート)でも Trim と同じ昇格パターンで動作確認。 - - [x] Phase 175: P5 複数キャリア対応(_parse_string 向け) ✅ (2025-12-08) - → Task 175-1: _parse_string のキャリア候補を洗い出す(pos, result, is_ch_match の 3 キャリア特定)。 - → Task 175-2: CarrierInfo / ExitMeta に複数キャリアを載せる設計を固める(既存箱がすべて複数対応済みと確認)。 - → Task 175-3: 小さい PoC で 2 キャリアだけ通してみる(MIR 検証で Pattern2 の制約を特定)。 - → Task 175-4: CURRENT_TASK / joinir-architecture-overview 更新。 - → **成果**: P5 アーキテクチャが複数キャリアに対応済みであることを確認。 - CarrierInfo は 3 キャリア検出済み(pos, result, is_ch_match)。 - Pattern2 実装が Trim 最適化により `pos` のみ emit する制約を発見(Phase 176 改善対象)。 - - [x] Phase 176: Pattern2 multi-carrier lowering ✅ (2025-12-08) - → Task 176-1: 制限ポイント特定(10箇所の TODO マーク) - → Task 176-2: CarrierUpdateLowerer ヘルパ実装(6 unit tests) - → Task 176-3: ヘッダ PHI / ループ更新 / ExitLine を全キャリア対応に拡張 - → Task 176-4: E2E テスト成功(2キャリア: pos + result) - → Task 176-5: ドキュメント更新 - → **成果**: Pattern2 が複数キャリアに完全対応。CarrierInfo に載っている全キャリアの UpdateExpr を MIR に emit。 - → **バグ修正**: Trim pattern の loop_var_name 上書き問題、InstructionRewriter の latch_incoming 設定問題。 +- LoopBuilder は完全削除済みで、ループは JoinIR Pattern1–4(while / break / if‑PHI / continue)+ P5(Trim系) で統一。 +- JoinValueSpace / LoopHeaderPhi / ExitLine / JoinInlineBoundary / JoinIRVerifier まで含めた + 「Loop → JoinIR → MIR → return」のパイプラインは、代表パターンと JsonParser ミニケースで安定している。 +- P3(if‑PHI) は if‑sum 最小パターン(`phase212_if_sum_min.hako`)まで AST ベースで一般化済みで、 + ExprResult の出口契約も Pattern2 と同じ形に揃って RC=2 まで通るようになった。 -- 今後 1〜2 フェーズの TODO(JoinIR 周りのサマリ) - - [x] **Phase 213-E: NYASH_JOINIR_CORE deprecate cleanup** ✅ (2025-12-09) - - JoinIR は常時 ON(LoopBuilder 削除済み)。`NYASH_JOINIR_CORE` は警告のみで無視する。 - - config/env でガード追加済み、スクリプトからの export を撤去、docs に「常時 ON + Fail-Fast」の注記を追加。 - - [x] **Phase 177: Multi-carrier PHI 接続修正** ✅ (2025-12-08) - - Task 177-STRUCT-1: CarrierVar に join_id 追加 - - Task 177-STRUCT-2: carrier_order で順序保持(LoopHeaderPhiInfo) - - **成果**: Int テスト成功(sum=3)、index mismatch 問題解決 - - [x] **Phase 178: LoopUpdateAnalyzer string 検出** ✅ (2025-12-08) - - Task 178-1: UpdateRhs 拡張(StringLiteral, Other 追加) - - Task 178-2: analyze_rhs 分岐拡張(string/method call 検出) - - Task 178-3: Pattern2/4 can_lower で string 拒否(Fail-Fast) - - Task 178-4: Legacy fallback コメント修正(LoopBuilder 削除済み反映) - - **成果**: String loop は明示的エラー、numeric loop は正常動作維持 - - **注意**: グローバルテスト 79 件失敗は Phase 178 以前からの既知問題(別途対応) - - [x] **Phase 180: Trim/P5 サブモジュール化** ✅ (2025-12-08) - - Task 180-1: 設計ドキュメント作成(phase180-trim-module-design.md) - - Task 180-2: TrimLoopLowerer スケルトン実装(try_lower_trim_like_loop 骨格) - - Task 180-3: Pattern2 リファクタリング(~160 行の Trim ロジックを TrimLoopLowerer に委譲) - - Task 180-4: Pattern4 分析(Trim 検出のみで lowering なし、スキップ) - - Task 180-5: ドキュメント更新(joinir-architecture-overview.md + CURRENT_TASK.md) - - **成果**: Pattern2 から Trim 専用ロジックを完全分離、-135 行の削減 - - **TrimLoopLowerer**: LoopConditionScopeBox + LoopBodyCarrierPromoter 統合 - - **再利用性向上**: Pattern2/4/未来パターンすべてで同じ Trim lowering を利用可能 - - **テスト**: cargo build --release SUCCESS (0 errors, warnings のみ) - - [x] **Phase 181: JsonParser ループ空間の再インベントリ** ✅ (2025-12-08) - - Task 181-1: JsonParserBox 内の全 11 ループを LoopPatternSpace の軸(A〜F)で分類 - - Task 181-2: 各ループの Pattern1–4 + P5 へのマッピング(_parse_number/_atoi/_match_literal 等は P2/P1 で対応可能) - - Task 181-3: `_skip_whitespace` / `_trim*` / `_parse_string` 最小版 など、既に JoinIR/P5 経路で動作しているケースを確認 - - Task 181-4: 残りループの優先度と難易度を整理(_parse_array/_parse_object/_unescape_string は後続 Phase で対応) - - **成果**: JsonParser の全ループが「形としては P1–P4(+P5) で表現可能」であることを確認。 - ループ形の追加は不要で、複雑さは BoolExprLowerer / ContinueBranchNormalizer / TrimLoopLowerer 側で吸収する方針を確定。 - - [x] **Phase 179-B: Generic Pattern Framework** ✅ (2025-12-08) - - Task 179-B-1: 設計ドキュメント作成(phase179-generic-pattern-framework.md) - - Task 179-B-2: PatternPipelineContext 実装(pattern_pipeline.rs) - - Task 179-B-3: Pattern 1 統一(168→149行, 11%削減) - - Task 179-B-4: Pattern 3 統一(168→149行, 11%削減) - - Task 179-B-5: Pattern 2 統一(517→509行, 1.5%削減) - - Task 179-B-6: Pattern 4 統一(422→414行, 1.9%削減) - - Task 179-B-7: テスト・ドキュメント更新(全代表ケース PASS) - - **成果**: 全パターン(P1/P2/P3/P4)で PatternPipelineContext 統一、 - 前処理ロジック一本化、挙動不変(テスト全 PASS)。 - - **設計原則**: Pure analysis container(解析のみ、emission なし)、 - Analyzer-only dependencies、Pattern-specific variants(Option)。 - - **注意**: Pattern 2/4 の複雑ロジック(Trim, carrier 解析)は inline 維持。 - 将来 Phase 180+ で Trim module 化予定。 - - [x] **Phase 181: JsonParser 残りループ設計調査** ✅ (2025-12-08) - - Task 181-1: 全11ループの再チェック(Pattern × Box マトリクス作成) - - Task 181-2: ブロック分析(LoopConditionScopeBox 制約との照合) - - Task 181-3: ロードマップ作成(phase181-jsonparser-loop-roadmap.md) - - **成果**: 全ループが「LoopParam/OuterLocal のみ」という制約を満たし、理論的に全対応可能 - - **発見**: ブロックされるループは存在しない(Trim は昇格パターンで対応済み) - - **優先度**: P2 Break(3個: _parse_number/_atoi/_atof_loop)> P1 Simple(1個: _match_literal)> P4 Continue(3個: _parse_array/_parse_object/_unescape_string) - - [x] **Phase 182: JsonParser P1/P2 パターン検証** ✅ (2025-12-08) - - Task 182-1: 設計ドキュメント作成(phase182-simple-loops-design.md) - - Task 182-2: Routing whitelist 更新(_parse_number/2, _atoi/1, _match_literal/3 追加) - - Task 182-3: Pattern routing 確認(NYASH_JOINIR_STRUCTURE_ONLY=1 tracing) - - Task 182-5: 代表テスト作成・実行 - - ✅ Pattern1: phase182_p1_match_literal.hako PASS - - ✅ Pattern2: phase182_p2_break_integer.hako PASS - - Task 182-6: ドキュメント更新(joinir-architecture-overview.md, CURRENT_TASK.md) - - **成果**: P1/P2 パターンの基本動作確認完了(整数演算・early return で動作実証) - - **ブロッカー発見**: - 1. LoopBodyLocal 変数処理(`ch`, `digit_pos`, `pos`) - - 現状: Trim 専用の carrier 昇格を試みてエラー - - 必要: P1/P2 で純粋なローカル変数(昇格不要)として扱う仕組み - 2. 文字列連結フィルタ(Phase 178) - - 現状: `num_str = num_str + ch` を保守的に reject - - 必要: JsonParser 向けに段階的有効化 - - **次ステップ**: Phase 183 で LoopBodyLocal 処理と string ops 対応 - - [x] **Phase 183: LoopBodyLocal 役割分離** ✅ (2025-12-08) - - Task 183-1: 設計メモ作成(phase183-loopbodylocal-role-separation.md) - - LoopBodyLocal を 2 カテゴリに分類設計(Condition vs Body-only) - - Trim promotion は条件に出てくる変数のみ対象 - - body-only local は昇格スキップ - - Task 183-2: LoopBodyLocal 役割分離実装 - - TrimLoopLowerer に `is_var_used_in_condition()` ヘルパー追加 - - 条件で使われていない LoopBodyLocal を Trim 昇格対象から除外 - - 5 unit tests(variable detection, binary op, method call, nested) - - Task 183-3: 代表ループテスト作成 - - `phase183_body_only_loopbodylocal.hako`: body-only LoopBodyLocal デモ - - トレース確認: `[TrimLoopLowerer] No LoopBodyLocal detected, skipping Trim lowering` ✅ - - Task 183-4: ドキュメント更新(joinir-architecture-overview.md, CURRENT_TASK.md) - - **成果**: LoopBodyLocal 役割分離完了、body-only 変数は Trim promotion されない - - **残課題**: body-local 変数の MIR lowering 対応(Phase 184+ で対応予定) - - **発見**: Pattern1 実行問題(別途対応必要、Phase 183 スコープ外) - - [x] **Phase 184: Body-local MIR Lowering Infrastructure** ✅ (2025-12-08) - - Task 184-1: 設計ドキュメント作成 ✅ - - phase184-body-local-mir-lowering.md(Two-Environment System 設計) - - 箱理論: LoopBodyLocalEnv(Storage Box)+ UpdateEnv(Composition Box) - - Task 184-2: LoopBodyLocalEnv 実装 ✅ - - loop_body_local_env.rs(216行)新規作成 - - BTreeMap 決定性保証、7 unit tests 全 PASS - - Task 184-3: UpdateEnv 実装 ✅ - - update_env.rs(237行)新規作成 - - Priority order: ConditionEnv → LoopBodyLocalEnv、8 unit tests 全 PASS - - Task 184-4: CarrierUpdateEmitter 統合 ✅ - - emit_carrier_update_with_env() 新規追加(UpdateEnv 版) - - emit_carrier_update() 後方互換維持、4 新規 unit tests 全 PASS(全 10 tests PASS) - - Task 184-5: 代表テストケース作成 ✅ - - phase184_body_local_update.hako(Pattern1 検証) - - phase184_body_local_with_break.hako(Pattern2 統合未実施、Phase 185 予定) - - Task 184-6: ドキュメント更新 ✅ - - joinir-architecture-overview.md(Phase 184 セクション追加) - - CURRENT_TASK.md(本項目追加) - - **成果**: Body-local 変数の MIR lowering インフラ完成 - - 3つの小箱(LoopBodyLocalEnv/UpdateEnv/CarrierUpdateEmitter)が単一責任で独立 - - 全 25 unit tests PASS(決定性・優先順位・後方互換性検証済み) - - **制約**: Pattern2/4 への統合は Phase 185 で実施予定(body-local 収集機能必要) - - [x] **Phase 187: String UpdateLowering 設計(doc-only)** ✅ (2025-12-09) - - UpdateKind ベースのホワイトリスト設計(コード変更なし) - - StringAppendChar/StringAppendLiteral を安全パターンとして定義 - - Complex (method call / nested BinOp) は Fail-Fast 維持 - - Phase 178 の Fail-Fast は完全保持 - - Phase 188+ での実装方針を確立 - - [x] **Phase 188: StringAppend 実装** ✅ (2025-12-09) - - Task 188-1: LoopUpdateAnalyzer 拡張(既存の UpdateRhs で対応済み) - - Task 188-2: Pattern2/4 can_lower ホワイトリスト更新(UpdateRhs::Other のみ拒否) - - Task 188-3: CarrierUpdateEmitter JoinIR emission 拡張(StringLiteral → Const emission) - - Task 188-4: E2E テスト(phase188_string_append_char.hako / phase188_string_append_literal.hako) - - Task 188-5: ドキュメント更新(phase187-string-update-design.md + joinir-architecture-overview.md) - - **成果**: Pattern2/4 が安全な string 更新パターンを受理。Complex パターンのみ Fail-Fast。 - - 許可: `s = s + ch`, `s = s + "literal"` - - 拒否: `s = s + s.substring(...)` (method call), `s = s + (a + b)` (nested BinOp) - - [x] **Phase 189: JsonParser ミニ適用検証** ✅ (2025-12-09) - - Task 189-1: phase183 テスト(_parse_number/_atoi/_match_literal)の再検証 - - Task 189-2: キャリア検出問題の根本原因分析 - - Task 189-3: 検証レポート作成(phase189-jsonparser-mini-verification.md) - - Task 189-4: CURRENT_TASK / roadmap ドキュメント更新 - - **成果**: Phase 188 StringAppend 実装は完了しているが、**キャリア検出の根本的制約**を発見 - - **ブロッカー**: Pattern1/2 はループ条件の変数のみ追跡(アキュムレータ変数を自動検出しない) - - **検証結果**: - - phase183_p2_parse_number: ❌ LoopBodyLocal blocker(設計通り、Pattern5 必要) - - phase183_p2_atoi: ❌ `result` 変数が追跡されず(キャリア検出問題) - - phase182_p1_match_literal: ✅ 動作(アキュムレータ不要) - - **Phase 188 コード自体は正常**: StringAppend ホワイトリスト・emission ロジック正しい - - **E2E テストは Phase 190+ まで保留**: キャリア検出強化が先決 - - **次ステップ**: Phase 190 でキャリア検出強化(3つのオプション設計済み) - - [x] **Phase 190: NumberAccumulation Update 設計(doc-only)** ✅ (2025-12-09) - - Task 190-1: _parse_number/_atoi パターン調査 ✅ - - Task 190-2: UpdateKind::NumberAccumulation 設計 ✅ - - Task 190-3: LoopUpdateAnalyzer アルゴリズム設計 ✅ - - Task 190-4: Pattern2/4 can_lower 仕様策定 ✅ - - Task 190-5: CarrierUpdateLowerer 責務設計 ✅ - - Task 190-6: ドキュメント更新(phase190-number-update-design.md + overview) ✅ - - **成果**: `v = v * 10 + digit` パターンの完全設計 - - UpdateKind::NumberAccumulation { base: i64 } 定義 - - Whitelist 制御: Integer のみ許可、Complex は Fail-Fast - - 2-instruction emission: `tmp = v * base; result = tmp + addend` - - AST 構造解析(名前依存禁止)、LHS 出現回数チェック - - Implementation phases 定義(Phase 190-impl-A/B/C/D) - - **次ステップ**: Phase 190-impl で実装(コード変更は別フェーズ) - - [x] **Phase 190-impl: NumberAccumulation 実装** ✅ (2025-12-09) - - Phase 190-impl-A: Core Detection (LoopUpdateAnalyzer 拡張) ✅ - - Phase 190-impl-B: CarrierUpdateLowerer Extension (JoinIR emission) ✅ - - Phase 190-impl-C: Pattern2/4 Integration (can_lower 更新) ✅ - - Phase 190-impl-D: E2E Validation + PHI 配線デバッグ ✅ - - **バグ発見**: body-local と carrier の ValueId 衝突問題 - - **修正**: `body_local_start_offset = env.len() + carrier_info.carriers.len()` - - **E2E 結果**: `phase190_atoi_impl.hako` → 12 ✅、`phase190_parse_number_impl.hako` → 123 ✅ - - ExitLine contract Verifier 追加(`#[cfg(debug_assertions)]`) - - **残課題**: body-local 変数 assignment は JoinIR 未対応(Phase 191 で対応) - - [x] **Phase 191: Body-Local Init & Update Lowering Integration** ✅ (2025-12-09) - - **目的**: LoopBodyLocalEnv / UpdateEnv / LoopBodyLocalInitLowerer を Pattern2 に本番統合完了 - - 191-1: 対象ケース選定 → `phase191_body_local_atoi.hako` 作成 ✅ - - 191-2: LoopBodyLocalInitLowerer の Pattern2 統合(init emission 位置は body 先頭)✅ - - 191-3: UpdateEnv 統合確認(ConditionEnv + LoopBodyLocalEnv 両方から解決)✅ - - 191-4: E2E テスト → 期待値 123 出力確認 ✅ - - 191-5: ドキュメント更新 ✅ - - **成果**: - - 対応済み init 式: 整数リテラル、変数参照、二項演算(`local digit = i + 1`) - - UpdateEnv 優先順位: ConditionEnv(高)→ LoopBodyLocalEnv(フォールバック) - - ValueId 二重割当問題を修正(空の LoopBodyLocalEnv を InitLowerer に委譲) - - **テスト**: phase191_body_local_atoi.hako → 123 ✅、退行なし - - [x] **Phase 192-impl: ComplexAddendNormalizer 実装** ✅ (2025-12-09) - - **目的**: `v = v * 10 + digits.indexOf(ch)` のような Complex addend パターンを、 - `temp = digits.indexOf(ch); v = v * 10 + temp` に正規化して NumberAccumulation に載せる - - 192-impl-1: ComplexAddendNormalizer 実装 ✅ - - `normalize_assign()` API 設計(NormalizationResult enum) - - 検出ロジック: `lhs = lhs * base + MethodCall(...)` - - 正規化ロジック: temp 変数生成 + 2-statement AST 出力 - - 5 unit tests 全 PASS(method call, simple variable, wrong LHS, no multiplication, subtraction) - - 192-impl-2: Pattern2 前処理統合 ✅ - - carrier update analysis 前に normalization ステップ挿入(line 243-279) - - `analysis_body` を LoopUpdateAnalyzer に委譲 - - trace 出力: `[pattern2/phase192] Normalized complex addend: temp='temp_result_addend'` - - 192-impl-3: E2E 検証 ✅ - - phase192_normalization_demo.hako → 123 ✅(AST レベル正規化確認) - - 退行なし: phase190_atoi_impl.hako → 12 ✅、phase190_parse_number_impl.hako → 123 ✅、phase191_body_local_atoi.hako → 123 ✅ - - 192-impl-4: ドキュメント更新 ✅ - - phase192-complex-addend-design.md Section 9 追加(実装完了報告) - - CURRENT_TASK.md(本項目追加) - - **成果**: AST レベル正規化インフラ完成、箱化原則(単一責任・再利用性・Fail-Fast)遵守 - - **制約(Phase 193+ 拡張)**: LoopBodyLocalInitLowerer は int/arithmetic のみ対応 - - MethodCall in temp init は Phase 186 limitation でエラー - - 拡張対象: `lower_init_expr()` に MethodCall/Call サポート追加 - - **設計原則検証**: - - ✅ 箱化: ComplexAddendNormalizer は純粋 AST transformer(emission なし) - - ✅ Fail-Fast: Unsupported patterns → NormalizationResult::Unchanged - - ✅ 再利用性: Phase 191 (body-local init) + Phase 190 (NumberAccumulation) 活用 - - ✅ 変更最小化: Emission ライン(CarrierUpdateEmitter, LoopBodyLocalInitLowerer)は変更なし - - [x] **Phase 193: LoopBodyLocalInit MethodCall Extension** (完了: 2025-12-09) - - **目的**: Phase 186 limitation 部分解除、MethodCall を init 式でサポート - - ✅ `emit_method_call_init()` 実装(~80行)、MethodCall → BoxCall 変換 - - ✅ String literal init サポート追加(Phase 186 拡張) - - ✅ Method whitelist(indexOf, get, toString)Fail-Fast 実装 - - ✅ E2E テスト: `i.toString()` 成功、退行なし - - **重要な設計判断**: ConditionEnv を「ループパラメータ専用」として維持 - - ✅ 対応: ループパラメータをレシーバーとする MethodCall (`i.toString()`) - - ⚠️ 保留: 外部ローカルをレシーバーとする MethodCall (`digits.indexOf(ch)`) - - **理由**: Phase 170-200 の 2-tier 境界設計(ConditionEnv/LoopBodyLocalEnv)を保持 - - **将来**: Phase 200+ で独立した箱として設計、または .hako リライト対応 - - [x] **Phase 194: JsonParser P1/P2/P5 実戦投入(検証フェーズ)** ✅ (2025-12-09) - - **目的**: Phase 170-193 インフラの実コード検証(Fail-Fast 戦略) - - 194-1: Loop inventory 作成 ✅ - - 4/10 ループ JoinIR 対応(_skip_whitespace, _trim x2, _match_literal) - - 6/10 ループ保留(明確な理由付き) - - 詳細: phase194-loop-inventory.md(10ループ完全分類) - - 194-2: Routing 確認 ✅ - - Structure-only mode 動作確認(whitelist 不要) - - 既存 whitelist に全4ループ登録済み - - 194-3: E2E 実行 ✅ - - 結果: Compilation Error(Expected - Fail-Fast 戦略成功) - - エラー: `digits.indexOf()` → ConditionEnv constraint - - 分析: function-scoped variables は Phase 193 非対応 - - 194-4: Regression tests ✅ - - phase190_atoi_impl.hako → 12 ✅ - - phase191_body_local_atoi.hako → 123 ✅ - - phase193_init_method_call.hako → RC:0 ✅ - - 194-5: ドキュメント更新 ✅ - - phase194-jsonparser-deployment.md(Implementation Status 完全記録) - - joinir-architecture-overview.md(Section 7.2 Phase 194 完了マーク) - - CURRENT_TASK.md(本項目追加) - - **成果**: インフラ品質検証完了、次 Phase への明確なロードマップ提示 - - ✅ P5 Trim pattern 実戦検証(_trim で動作確認) - - ✅ ConditionEnv 制約明確化(function-scoped variables 未対応) - - ✅ 退行なし(Phase 190-193 全テスト PASS) - - **技術的発見**: - 1. ConditionEnv constraint(function-scoped variables 非対応) - - 影響: _parse_number, _atoi(digits.indexOf 依存) - - 解決策案: Phase 200+ ConditionEnv 拡張 OR .hako リライト - 2. Complex carriers(多段フラグ) - - 影響: _parse_string, _unescape_string - - 解決策: Phase 195+ Pattern 3 拡張 - 3. Multiple MethodCalls(ループ body 内複数呼び出し) - - 影響: _parse_array, _parse_object - - 解決策: Phase 195+ MethodCall 拡張 - - **推奨ロードマップ**: - - Phase 195: Pattern 3 extension(if-in-loop + multi-flag carriers) - - Phase 200+: ConditionEnv expansion(function-scoped locals) - - Phase 201+: MethodCall extension(multiple calls in body) - - [x] **Phase 195: Pattern 3 拡張(設計 + Lowerer 実装完了)** (2025-12-09) - - **目的**: P3(If-Else PHI)を複数キャリア対応に拡張 - - **実装完了**: - - ✅ `loop_with_if_phi_minimal.rs`: multi-carrier PHI 生成(sum + count) - - ✅ `pattern3_with_if_phi.rs`: 単一/複数キャリアを動的処理 - - ✅ ExitLine / CarrierVar.join_id: **変更不要**(既存インフラ活用) - - ✅ テストファイル: `phase195_sum_count.hako` 作成 - - **設計判断の証明**: - - ✅ ExitLine 拡張で対応(PhiGroupBox は作らない - YAGNI 原則が正しかった) - - ✅ 両分岐での Carrier 定義確認(更新なし = 前の値使用) - - ❌ ConditionEnv 拡張なし(Phase 200+ 保留) - - **成果**: - - P3 Lowerer は複数キャリア対応完了 ✅ - - ExitLine/CarrierVar は既に対応済み(変更不要)✅ - - JoinIR→MIR bridge の Select バグは Phase 196 で修正 ✅ - - [x] **Phase 196: Select 展開/変換バグ調査&修正** ✅ (完了: 2025-12-09) - - **目的**: JoinIR→MIR の Select 展開処理バグを修正 - - **根本原因**: `instruction_rewriter.rs` での二重 remap バグ - - Line 304: `remap_instruction()` で PHI inputs を JoinIR→Host に remap 済み - - Line 328: `remap_value(*val)` で再度 remap → undefined ValueId 参照 - - **修正内容**: PHI の block ID のみを remap、ValueId は既に remap 済みなのでそのまま使用 - - **変更**: 1ファイル 1行(`instruction_rewriter.rs` line 331) - - **テスト結果**: - - ✅ phase195_sum_count.hako → 93(sum=9, count=3 で計算) - - ✅ loop_if_phi.hako → sum=9(単一キャリア P3) - - ✅ loop_min_while.hako → 0,1,2(Pattern 1) - - ✅ joinir_min_loop.hako → RC:0(Pattern 2) - - ✅ 退行なし、`[joinir/freeze]` なし - - **成果**: - - P3 multi-carrier が E2E で完全動作 ✅ - - 箱化原則遵守(新規構造体なし、最小限の変更)✅ - - ドキュメント完備(phase196-select-bug-analysis.md)✅ - - [x] **Phase 197: JoinIR 実戦適用(軽量ループ検証)** ✅ (完了: 2025-12-09) - - **目的**: Phase 196 までの安定基盤を実戦の小さいループで検証 - - **対象ループ(5本)**: - 1. `_match_literal` (P1) - JsonParser 単純 while ✅ - 2. `_skip_whitespace` (P2) - JsonParser break パターン ✅ - 3. `phase195_sum_count.hako` (P3 multi-carrier) ✅ - 4. `loop_if_phi.hako` (P3 single-carrier) ✅ - 5. `loop_min_while.hako` (P1 minimal) ✅ - - **実施内容**: - - 197-1: 対象ループ確定(3-5本)✅ - - 197-2: routing 確認(whitelist 既存)✅ - - 197-3: 構造トレース + E2E 実行 ✅ - - 197-4: ドキュメント更新 ✅ - - **成果**: - - 全ループで正しい Pattern 選択 ✅ - - 4/5 ループで E2E PASS、1/5 routing 確認 ✅ - - 退行なし(Phase 190-196 テスト全 PASS)✅ - - JsonParser/selfhost 実戦適用状況表作成 ✅ - - Coverage: 7/13 ループ JoinIR 対応済み(54%) - - **詳細**: phase197-lightweight-loops-deployment.md - - **次候補**: - - Phase 200+: ConditionEnv 拡張(_parse_number, _atoi) - - Phase 198+: JsonParser 残りループ個別対応 - - [x] **Phase 200-A: ConditionEnv 拡張インフラ(型と箱のみ)** ✅ (完了: 2025-12-09) - - **目的**: ConditionEnv を壊さずに関数スコープ "実質定数" を扱う基盤 - - **実施内容**: - - 200-A-1: CapturedVar / CapturedEnv 型導入 ✅ - - 200-A-2: FunctionScopeCaptureAnalyzer スケルトン ✅ - - 200-A-3: ConditionEnvBuilder v2 入口 ✅ - - 200-A-4: ParamRole enum 追加 ✅ - - 200-A-5: ドキュメント更新 ✅ - - **スコープ**: Infra only / Integration pending - - **成果**: - - 型と箱の定義完了 ✅ - - 既存ループの挙動変更なし ✅ - - Phase 200-B への準備完了 ✅ - - **次フェーズ**: Phase 200-B(digits 系ループへの適用) - - **詳細**: phase200-A-conditionenv-infra.md - - [x] **Phase 200-B: FunctionScopeCaptureAnalyzer 実装 & ConditionEnv 統合** ✅ (完了: 2025-12-09) - - **目的**: digits 等の関数ローカルを ConditionEnv から参照可能に - - **実装内容**: - - 200-B-1: capture 判定ロジック実装 ✅ - - 200-B-2: ConditionEnvBuilder v2 実装 ✅ - - 200-B-3: パイプライン組み込み(Pattern 2)✅ - - 200-B-4: digits ケース検証 ✅ - - 200-B-5: ドキュメント更新 ✅ - - **成果**: - - digits が CapturedEnv に捕捉される - - ConditionEnv.captured に登録される - - ParamRole::Condition として boundary に追加される - - **Pattern 2 統合**: - - TODO skeleton 追加済み(phase 200-B-3) - - 制限: fn_body (full function body AST) が Pattern 2 lowerer で未利用可能 - - 将来: LoopPatternContext に fn_body を追加予定 (Phase 200-C+) - - **テストファイル**: - - apps/tests/phase200_digits_atoi_min.hako - - apps/tests/phase200_digits_parse_number_min.hako - - **次フェーズ**: Phase 200-C(digits.indexOf E2E 連携) - - **詳細**: phase200-B-capture-impl.md - - [x] **Phase 200-C: digits.indexOf E2E 連携** ✅ (完了: 2025-12-09) - - **目的**: 200-A/B インフラを実際に Pattern 2 経路に統合 - - **実装内容**: - - 200-C-1: LoopPatternContext に fn_body 追加 ✅ - - MirBuilder に fn_body_ast フィールド追加 - - lower_method_as_function / lower_static_method_as_function で fn_body 保存 - - 200-C-2: Pattern 2 で capture 解析呼び出し ✅ - - analyze_captured_vars_v2() 新規追加(構造的ループ検索) - - ポインタ比較 → AST 構造比較に変更 - - 200-C-3: ConditionEnvBuilder v2 統合 ✅ - - 200-C-4: digits ケース検証 ⚠️ - - capture 検出: ✅ PASS(digits, s が CapturedEnv に捕捉) - - E2E 実行: ❌ BLOCKED(body-local 変数 `pos` が条件で使用 → Pattern 5+ 必要) - - 200-C-5: ドキュメント更新 ✅ - - **成果**: - - 構造的ループ検索(analyze_captured_vars_v2)実装完了 - - fn_body が Pattern 2 lowerer まで正しく渡される - - digits / s が CapturedEnv に正しく捕捉される - - **テストケース制約**: - - phase200_digits_atoi_min.hako: body-local `pos = digits.indexOf(ch)` を条件 `if pos < 0` で使用 - - phase200_digits_parse_number_min.hako: 同様に body-local `digit_pos` を条件で使用 - - → Pattern 5+ (body-local promotion) が必要 - - **次フェーズ**: Phase 200-D(シンプルな capture テストケース) - - **詳細**: phase200-C-digits-e2e.md - - [x] **Phase 200-D: digits capture "実戦 1 本" 検証** ✅ (完了: 2025-12-09) - - **目的**: capture 経路の E2E 検証(body-local なしのシンプルケース) - - **実装内容**: - - 200-D-1: body-local なし digits テスト作成 ✅ - - phase200d_capture_minimal.hako - - phase200d_capture_in_condition.hako - - phase200d_digits_simple.hako(substring 制限で BLOCKED) - - 200-D-2/D-3: E2E 検証 ⚠️ - - capture 検出: ✅ PASS(base, limit, n 等が正しく CapturedEnv に) - - ConditionEnv 統合: ✅ PASS(captured vars が ConditionEnv.captured に追加) - - 実行: ⚠️ 別の制約でブロック(キャリア更新式の型問題) - - **成果**: - - capture 経路(analyze_captured_vars_v2 → ConditionEnv → Pattern 2)が正常動作 - - 関数スコープ定数(base, limit, digits 等)が正しく検出・統合される - - host_id → join_id マッピングが ConditionEnv.captured に追加される - - **残課題**: - - E2E 実行は別の制約(substring 未対応、キャリア更新型問題)でブロック - - これらは Phase 200 スコープ外(キャリア更新強化は別フェーズ) - - **テストファイル**: - - apps/tests/phase200d_capture_minimal.hako - - apps/tests/phase200d_capture_in_condition.hako - - apps/tests/phase200d_digits_simple.hako - - apps/tests/phase200d_digits_accumulate.hako - - [x] **Phase 201: JoinValueSpace - 統一 ValueId 割り当てシステム** ✅ (完了: 2025-12-09) - - **目的**: ValueId 衝突問題の根本解決(Param/Local/PHI 領域分離) - - **実装内容**: - - 201-1: 設計ドキュメント作成 ✅ - - 201-2: JoinValueSpace box 実装 ✅(10 unit tests) - - 201-3: Param region migration ✅(ConditionEnvBuilder v2 API) - - 201-4: PHI reservation ✅(スキップ - lowerer が ConditionEnv の ValueId を直接使用) - - 201-5: Local region migration ✅(Pattern 2 lowerer 更新) - - 201-6: Testing ✅(821 tests PASS、E2E 検証成功) - - 201-7: Documentation ✅ - - **ValueId 空間レイアウト**: - - PHI Reserved (0-99): LoopHeader PHI dst 用の予約領域 - - Param Region (100-999): ConditionEnv, CarrierInfo, CapturedEnv - - Local Region (1000+): Pattern lowerers の中間値 - - **成果**: - - ValueId 衝突問題完全解決(領域分離により衝突不可能) - - phase200d_capture_minimal.hako → 30 ✅(110 ではない) - - 全テスト PASS、退行なし - - **設計判断**: - - 固定領域境界(100, 1000)採用(動的オフセットより単純) - - reserve_phi() はマーカーのみ(PHI dst は host 側から来る) - - value_id_ranges.rs とは相補的(モジュールレベル vs lowering 内部) - - **詳細**: phase201-join-value-space-design.md - - [x] **Phase 202: Pattern 1-4 JoinValueSpace 統一** ✅ (完了: 2025-12-09) - - **目的**: 全パターンを JoinValueSpace に移行(Phase 201 の Pattern 2 に続き) - - **実装内容**: - - **Phase 202-A: Pattern 1 (Simple While)** ✅ (commit `6e778948`) - - simple_while_minimal.rs: value_counter → JoinValueSpace.alloc_local() - - Local region (1000+) のみ使用(Param region 不要) - - テスト: 119 passed、loop_min_while.hako → "0 1 2" ✅ - - **Phase 202-B: Pattern 3 (If-PHI)** ✅ (commit `98e81b26`) - - loop_with_if_phi_minimal.rs: value_counter → JoinValueSpace.alloc_local() - - E2E テスト: loop_if_phi.hako, loop_if_phi_continue.hako PASS - - **Phase 202-C: Pattern 4 (Continue)** ✅ (commit `ae741d97`) - - loop_with_continue_minimal.rs: 二重カウンター → JoinValueSpace 統一 - - 旧: value_counter (0u32) + join_value_counter (manual increment) - - 新: JoinValueSpace (Param 100+ + Local 1000+) - - E2E テスト: loop_continue_pattern4.hako → 25, loop_continue_multi_carrier.hako → 100, 10 ✅ - - **成果**: - - 全パターン(P1/P2/P3/P4)で JoinValueSpace 統一完了 - - ValueId 衝突リスク完全排除(領域分離) - - 一貫性向上(単一の真実源) - - 保守性向上(手動カウンター管理不要) - - **統計**: - - Pattern 1: Local のみ(ConditionEnv なし) - - Pattern 2: Param + Local(ConditionEnv + 中間値) - - Pattern 3: Local のみ(PHI/Select 生成) - - Pattern 4: Param + Local(ConditionEnv + Select) - - **詳細**: phase202-a-pattern1-joinvaluespace.md - - [x] **Phase 203-A: JoinValueSpace 統一後のデッドコード削除** ✅ (完了: 2025-12-09, commit `de9fe3bf`) - - **目的**: Phase 201-202 で obsolete になったコードの削除 - - **削除内容**: - - v1 API `build_for_break_condition()` 削除(70行) - - 3つの unit test を v2 API (`build_for_break_condition_v2`) に変換 - - モジュールドキュメント更新(v2 が標準と明記) - - 未使用 import 2箇所削除 - - inline_boundary_builder.rs: 未使用 JoinValueSpace import - - loop_with_if_phi_minimal.rs: 未使用 ValueId import - - stub 関数ドキュメント化 - - lower_loop_with_break_to_joinir: router から呼ばれているため保持 - - Phase 203-A ドキュメント追加(stub 理由と移行オプション説明) - - **統計**: - - 4ファイル変更 - - 75行削減(117 deletions, 42 insertions) - - 全テスト PASS(821 passed) - - ビルドクリーン(0 errors) - - **成果**: - - コードベース整理完了 - - v2 API への完全移行 - - 保守性向上(デッドコード排除) - - [x] **Phase 204: JoinIR PHI Contract Verifier 強化** ✅ (完了: 2025-12-09) - - **目的**: Debug build での PHI 契約違反の早期検出 - - **実装内容**: - - 204-1: 設計ドキュメント作成 ✅ (phase204-phi-contract-verifier.md) - - 204-2: PHI dst overwrite 検出 ✅ - - `verify_no_phi_dst_overwrite()` 実装(SSA invariant 保証) - - `get_instruction_dst()` ヘルパー(全 MirInstruction 対応) - - 204-3: PHI inputs sanity checks ✅ - - `verify_phi_inputs_defined()` 実装(保守的閾値チェック) - - Full DFA verification は Phase 205+ に延期 - - 204-4: JoinValueSpace 領域検証 ⚠️ - - **延期理由**: LoopHeaderPhiInfo への JoinValueSpace 追加が必要(4+ ファイル変更) - - **代替策**: verify_phi_inputs_defined() で閾値チェック実装済み - - 204-5: 統合確認 ✅ - - `verify_joinir_contracts()` に全チェック統合 - - 全パターン(P1/P2/P3/P4)で有効化 - - 204-6: テスト実行 ✅ - - 821 tests PASS、退行なし - - 204-7: ドキュメント更新 ✅ - - **バグ修正**(Phase 204 作業中に発見): - - `entry_block_remapped` → `entry_block` (line 592) - - `HashMap` → `BTreeMap` mismatch (reconnector.rs line 174) - - **統計**: - - 変更ファイル: 3ファイル (+115 lines in mod.rs) - - コミット: `0175e62d` (Phase 204-2), `[pending]` (Phase 204-3/5/7) - - テスト: 821 passed, 0 failed - - **成果**: - - PHI dst 上書き検出完了(手動ミスの早期発見) - - PHI inputs sanity check 完了(保守的検証) - - Debug-only verification(リリースビルドコストゼロ) - - 設計原則遵守(Fail-Fast, 箱化, 最小変更) - - **延期項目**: - - Task 204-4: JoinValueSpace 領域検証(Phase 205+ で実装予定) - - 理由: 高影響チェック優先、Phase 201-202 で衝突既解決 - - **検証カバレッジ**: - - ✅ PHI exists (Phase 200-3) - - ✅ PHI dst match (Phase 200-3) - - ✅ PHI dst not overwritten (Phase 204-2 ✨) - - ✅ PHI inputs sanity (Phase 204-3 ✨) - - ⚠️ PHI inputs DFA (Phase 206+ 計画) - - ✅ ValueId regions (Phase 205 ✨) +### 2. JsonParser / Trim / selfhost への適用状況 - - [x] **Phase 205: JoinValueSpace & ValueId 領域契約の締め** ✅ (完了: 2025-12-09) - - **目的**: Box-First アプローチで ValueId 領域境界を完全確立 - - **実装内容**: - - 205-1: 設計ドキュメント作成 ✅ (phase205-valueid-regions-design.md) - - ValueId 領域契約の詳細定義 - - Box 境界設計(ValueIdAllocator, RegionVerifier) - - 205-2: 現状棚卸し ✅ - - Pattern1-4 の ValueId 使用箇所リストアップ - - 素の ValueId(..) 直接生成箇所の特定 - - 結果: Pattern1/2 統合済み、Pattern3/4 テストコードのみ - - 205-3: ValueIdAllocator Box 強化 ✅ - - 明示的領域定数追加(PHI_RESERVED_MIN/MAX, PARAM_MIN/MAX, LOCAL_MIN/MAX) - - 衝突検出(check_collision(), allocated_ids: HashSet) - - 領域検証(verify_region(id, expected_region)) - - 205-4: RegionVerifier Box 実装 ✅ - - verify_valueid_regions() 実装(merge/mod.rs) - - 検証項目: boundary.join_inputs(Param 領域), condition_bindings(Param 領域), carrier_phis dst(有効範囲内) - - 205-5: パターン統合監査 ✅ - - Pattern1-4 で raw ValueId(..) 使用がテストコードのみであることを確認 - - すべて alloc_param()/alloc_local() 経由の正規ルート使用確認 - - 205-6: テスト & ドキュメント更新 ✅ - - loop_min_while.hako (P1), loop_if_phi.hako (P3) 動作確認 - - joinir-architecture-overview.md に Phase 205 セクション追加 - - **統計**: - - 変更ファイル: 2ファイル (join_value_space.rs, merge/mod.rs) - - 新規ドキュメント: phase205-valueid-regions-design.md - - テスト: 全テスト PASS、退行なし - - **成果**: - - 衝突検出(debug-only)で二重割り当てを即座に検出 - - 領域検証で Param/Local 境界違反を即座に検出 - - RegionVerifier で merge 時の境界契約を自動検証 - - 明示的定数で領域境界が一目瞭然(デバッグ容易性向上) - - **Box-First 原則の実践**: - - 箱にする: ValueId 管理・検証ロジックを Box 化 - - 境界を作る: Param/Local 領域の境界を明確化(100, 1000) - - 戻せる: debug assertions で切替可能 - - 見える化: 領域違反を即座に検出 - - **Fail-Fast 実装**: - - 領域違反は即座に panic(デバッグモード) - - フォールバックやサイレント修正は一切なし - - エラーメッセージに修正ヒント含む - - **次フェーズへの引き継ぎ**: - - Phase 206: PHI inputs DFA 完全検証(予定) - - Phase 207: LoopUpdateSummary 完全統合(予定) +- Trim 系: + - `_trim` / `_skip_whitespace` の P5 パイプライン(LoopBodyLocal 昇格 → bool carrier → TrimLoopLowerer)は + JoinIR→MIR まで end‑to‑end で安定動作。 +- JsonParser: + - 11 ループ中、基本形(P1/P2/P5 相当)の 7 本は JoinIR インフラ上で理論的にカバー可能と確認済み。 + - すでに JoinIR で実戦投入できているのは `_skip_whitespace` / `_trim*` / `_match_literal` / `_atoi_min` / `_parse_number_min`。 + - 残りの複雑ループ(`_parse_array` / `_parse_object` / `_unescape_string` / 本体 `_parse_string` など)は + 「LoopBodyLocal + 複数 MethodCall + 複数フラグ」という組み合わせで、今後の拡張対象として整理済み。 +- selfhost (.hako): + - selfhost stage‑3 depth‑1(Rust→.hako)までは JoinIR 経路で代表ケースが緑。 + - depth‑2(.hako 側で JSON/MIR を読み、JoinIR/MIR/VM/LLVM に流すライン)は、JsonParser 側のループカバレッジ拡張が前提。 - - [x] **Phase 210: JsonParser JoinIR ミニ統合(ラウンド1)** ✅ (完了: 2025-12-09) - - **目的**: 既存 JoinIR インフラ(P1-P5/JoinValueSpace/PHI契約)で実戦ループ 2〜3 本を観測 - - **戦略**: 新機能実装なし、既存箱の実戦投入による観測フェーズ(Fail-Fast で制約発見) - - **対象ループ(3本)**: - 1. _atoi 最小版 (P2 Break, NumberAccumulation) - 2. _parse_number 最小版 (P2 Break, Multi-carrier) - 3. _match_literal 最小版 (P1 Simple) - - **実行結果**: - - ✅ **3本すべて完全成功** - JoinIR → MIR → Runtime まで到達 - - ✅ phase190_atoi_impl.hako → RC=12 (Pattern2, NumberAccumulation) - - ✅ phase190_parse_number_impl.hako → RC=123 (Pattern2, Multi-carrier) - - ✅ phase210_match_literal_min.hako → RC=1 (Pattern1, Simple) - - **観測ポイント全達成**: - - ✅ Pattern1 & Pattern2 自動ルーティング成功 - - ✅ NumberAccumulation: Mul + Add 2命令生成確認 - - ✅ Multi-carrier: 2 carrier 同時動作 & Exit PHI 正常配線 - - ✅ PHI Contract: LoopHeader PHI + Exit PHI 完璧に動作 - - ✅ ValueId Regions: Param (100-999) / Local (1000+) 正常分離 - - **重要な発見**: - - ✅ **予想を超える成功**: 「理論上いけるはず」を超えて「実戦でも完全動作」 - - ✅ Phase 190 (NumberAccumulation), 201 (JoinValueSpace), 204/205 (PHI Contract) の統合が完璧に機能 - - ❌ **制約発見ゼロ** - すべてのループが制約なく動作(Fail-Fast 発動せず) - - **成果物**: - - ドキュメント: phase210-jsonparser-mini-integration.md(設計・実行ログ・総合評価) - - テストハーネス: phase210_match_literal_min.hako(新規作成) - - **Phase 210 の結論**: - > **JoinIR インフラは実戦投入可能な成熟度に達している** ✨ - - **次フェーズへの接続**: - - Phase 211: JsonParser 残り8ループへの段階的展開(_parse_array, _parse_object, _unescape_string 等) - - Phase 212: MethodCall in condition / Complex addend 対応強化 +### 3. 直近で意識しておきたい設計の芯 - - [x] **Phase 211: JsonParser 次の 1 手(中規模ループ候補選定)** ✅ (完了: 2025-12-09) - - **目的**: Phase 210 成功を受け、中規模ループ 1 本を選定して既存 boxes 組み合わせを設計 - - **戦略**: コード実装なし、設計のみ(Phase 212 で実装) - - **候補選定**: 候補 B (`selfhost if-sum` パターン) を Phase 212 実装対象に選定 - - 理由: 既存 boxes で完全カバー可能 + ループ内 if の実戦検証価値が高い - - 候補 A (`_parse_string` 簡略版) は Phase 214 に延期(3-carrier を Phase 213 で先に確認) - - **Boxes マッピング**: - - Pattern 1 Simple + IfPHI + Multi-carrier(すべて Phase 210 で確認済み) - - 新規要素: IfPhiContext のループ内 if 適用(Phase 61 実装済みだが実戦未確認) - - **組み合わせ戦略設計**: - ``` - LoopPatternRouter → SimpleWhileMinimal → CarrierInfo (sum, i) - → IfPhiContext (ループ内 if の Merge PHI 生成) - → Header PHI back_edge 接続 → Exit PHI 配線 - ``` - - **Phase 212+ ロードマップ**: - - Phase 212: if-sum ハーネス実装・実行 - - Phase 213: 3-carrier テスト - - Phase 214: `_parse_string` 簡略版 - - Phase 215+: 残りの JsonParser ループ - - **成果物**: phase211-loop-candidate-selection.md(設計ドキュメント) - - - [x] **Phase 212: if-sum ミニ実装 & 実行フェーズ** ⚠️ **BLOCKED** (2025-12-09) - - **目的**: Phase 211 設計の if-sum パターンを既存 JoinIR インフラで実装・実行 - - **戦略**: Fail-Fast(問題があれば制約層を記録して中断) - - **テストファイル**: `apps/tests/phase212_if_sum_min.hako` - ```hako - loop(i < len) { - if i > 0 { - sum = sum + 1 // ← 条件付き更新 - } - i = i + 1 - } - ``` - - **実行結果**: ⚠️ **制約発見により中断** - - Pattern 1 (Simple While) が選ばれた(想定通り) - - Carrier は `i` のみ(`sum` が carrier になっていない) - - 期待: RC=2 / 実際: RC=0 - - **🚨 重大な発見**: **AST→MIR 変換層でループ内 if/else が消失** - - MIR ダンプで確認: if/else ブロックが MIR に存在しない - - `.hako` には `if i > 0 { sum = sum + 1 }` があるのに、MIR には `print(i)` と `i = i + 1` しかない - - `sum` 変数に関する処理(条件分岐・加算・PHI)が完全に消失 - - **制約の層**: - | 項目 | 内容 | - |-----|-----| - | **制約層** | AST → MIR 変換(Parser or MIR Builder) | - | **現象** | ループ内 if/else の代入文が MIR に変換されない | - | **影響範囲** | JoinIR Pattern 3 (IfPHI) が動作する以前の問題 | - | **エラーメッセージ** | なし(silent failure) | - | **再現性** | 100%(print 追加でも変わらず) | - - **Fail-Fast 成功**: Phase 211 では見えなかった制約を 1 回の実行で発見・層を特定 - - **Phase 213 への影響**: Phase 213 (3-carrier) も同じ問題に遭遇する可能性が高い - - **成果物**: phase212-if-sum-impl.md(観測レポート・制約詳細) - - **次のアクション**: ~~Phase 212.5(AST→MIR ループ内 if 修正)~~ ✅ **完了** (commit `aeb6282c`) - - - [x] **Phase 212.5: 構造ベース if 検出 for Pattern 3 Routing** ✅ (完了: 2025-12-09, commit `aeb6282c`) - - **目的**: Phase 212 で発見した「ループ内 if が Pattern 1 に誤ルーティング」問題を修正 - - **原因特定**: `has_if_else_phi = carrier_count > 1` ヒューリスティックの限界 - - 単一キャリアの if-update パターン(例: if-sum)を Pattern 1 に誤判定 - - **実装内容**: - 1. **AST Feature Extractor** (`ast_feature_extractor.rs`) - - `detect_if_in_body()` 関数追加(ANY if 文検出) - - `extract_features()` を構造ベース検出に更新 - 2. **Loop Pattern Classification** (`loop_pattern_detection/mod.rs`) - - Pattern 3: `carrier_count > 1` → `has_if && carrier_count >= 1` - - Pattern 1: `!has_if_else_phi` → `!has_if` - - **検証結果**: `phase212_if_sum_min.hako` - - ✅ Pattern 3 (If-Else PHI) に正しくルーティング - - ✅ MIR に PHI ノード生成: `%31 = phi [%25, bb9], [%29, bb10]` - - ✅ Carriers 検出: `i`, `sum`, `count` - - **制約発見**: Pattern 3 lowerer は **test-only PoC 実装** - - Loop condition: `i <= 5` (hardcoded) - - If condition: `i % 2 == 1` (hardcoded) - - Update logic: `sum + i` (hardcoded) - - → そのため RC=0(期待: RC=2) - - **成果**: Pattern routing は完全に成功、AST-based lowerer 汎用化は Phase 213 へ - - **ドキュメント**: phase212-5-implementation-complete.md - - - [x] **Phase 213-2: PatternPipelineContext + CarrierUpdateInfo 拡張** ✅ (2025-12-09) - - Task 213-2-2: `PatternPipelineContext` に Pattern 3 用フィールド追加 - - `loop_condition: Option` - ループ条件 AST 保存 - - `loop_body: Option>` - ループ本体 AST 保存 - - `loop_update_summary: Option` - キャリア更新情報 - - Task 213-2-3: `CarrierUpdateInfo` に then/else expression 追加 - - `then_expr: Option` - then 分岐更新式 - - `else_expr: Option` - else 分岐更新式 - - **成果**: Phase 213 AST-based generalization の基盤完成 - - - [x] **Refactoring 5.1: Pattern 3 Hardcoded ValueIds → ExitMeta化** ✅ (2025-12-09, commit `83940186`) - - **目的**: Pattern 3 lowerer を Pattern 4 と同じ ExitMeta ベースアーキテクチャに統一化 - - **変更対象**: - 1. `loop_with_if_phi_minimal.rs` - - 署名: `Option` → `Result<(JoinModule, JoinFragmentMeta), String>` - - ExitMeta 動的生成ロジック追加(k_exit parameters → exit_values HashMap) - 2. `pattern3_with_if_phi.rs` - - Hardcoded 定数削除(`PATTERN3_K_EXIT_SUM_FINAL_ID`, `PATTERN3_K_EXIT_COUNT_FINAL_ID`) - - Manual exit binding → `ExitMetaCollector::collect()` に置き換え - - **成果**: - - 19行削減(net)、42行の手動 exit binding コード削除 - - Pattern 3/4 アーキテクチャ統一完了 - - テスト全 PASS(3つの pre-existing failures は無関係) - - E2E 検証: `loop_if_phi.hako` → sum=9 ✅ - - **詳細ドキュメント**: - - refactoring-5-1-pattern3-exitmeta.md(実装計画) - - phase213-session-summary.md(セッション成果) - - - [x] **Phase 213: Pattern 3 AST-based If-Sum Lowerer** ✅ (2025-12-10) - - **目的**: Pattern 3 lowerer を AST-based に汎用化(dual-mode アーキテクチャ) - - **成果物**: - 1. `is_simple_if_sum_pattern()` ヘルパ追加(LoopUpdateSummary) - - 1 CounterLike + 1-2 AccumulationLike キャリア検出 - 2. Pattern3 lowerer dual-mode 分岐実装 - - `ctx.is_if_sum_pattern()` → if-sum mode / legacy mode 分岐 - 3. `loop_with_if_phi_if_sum.rs` 新規作成(AST-based lowerer, ~420行) - - AST から loop condition, if condition, updates を動的抽出 - - JoinIR 生成(main, loop_step, k_exit 3関数構成) - 4. AST 抽出ヘルパ群 - - `extract_loop_condition()`: `i < 3` → (var, op, limit) - - `extract_if_condition()`: `i > 0` → (var, op, value) - - `extract_then_update()`: `sum = sum + 1` → (var, addend) - - `extract_counter_update()`: `i = i + 1` → (var, step) - - **テスト結果**: - - AST 抽出: 成功 ✅ - - JoinIR 生成: 成功 ✅ - - E2E (RC=2): **未達成** - Pattern 3 JoinIR→MIR パイプライン既存バグ - - **既知の問題**: Pattern 3 全体(legacy 含む)で loop back branch が誤ったブロックを指す - - これは Phase 213 以前から存在する問題 - - `loop_if_phi.hako` も同様に RC=0 を返す - - **ドキュメント**: phase213-if-sum-implementation.md - - - [ ] **Phase 214: Pattern 3 JoinIR→MIR パイプライン修正** 🚧 **次フェーズ** - - **目的**: Pattern 3 の loop back branch を修正し、RC=2 達成 - - **前置**: Phase 213 で AST-based lowerer は完成 ✅ - - **スコープ**: - 1. Loop back branch target の調査 - - 現状: `bb14 → bb5` (誤り) - - 期待: `bb14 → bb4` (ループヘッダ PHI) - 2. JoinIRConversionPipeline の修正 - - tail recursion → branch 変換時のターゲット調整 - 3. E2E テスト - - `test_if_sum_minimal.hako` → RC=2 - - `loop_if_phi.hako` → RC=9 (sum of odd i from 1-5) - - **設計ドキュメント**: 作成予定 +- **Loop パターン空間**は有限で整理済み: + - P1: Simple While + - P2: Break + - P3: If‑PHI(単一/複数キャリア) + - P4: Continue(then/else‑continue 正規化込み) + - P5: LoopBodyLocal 昇格(Trim/JsonParser 用の部分適用) +- 「増やすべき」は新しい Pattern ではなく、既存 Pattern の前処理箱: + - BoolExprLowerer / ConditionEnv / LoopConditionScopeBox / LoopBodyCarrierPromoter / + TrimLoopHelper / ComplexAddendNormalizer / LoopBodyLocalEnv / UpdateEnv などで + 条件式とキャリア更新を吸収し、Pattern1–4 は「ループ骨格」に専念させる方針。 +- Fail‑Fast 原則: + - JoinIR 以外のループ lowering パスは存在しない(LoopBuilder は削除済み)。 + - 「わからないパターン」は必ず `[joinir/freeze]` 系の明示エラーにして、サイレントフォールバックはしない。 --- -### 2. Self‑Host depth‑2 / MIR JSON v0 / JoinIR Analyzer ライン +## ✅ 最近まとまった大きな塊(超要約) -- 現状 - - `.hako` から Program JSON v0 / MIR JSON を読み込む準備は整備済み(Phase 160 系)。 - - JsonParserBox / JsonParserBox.ProgramJSONBox / JsonParserBox.JsonParserBox 自体は箱として実装されている。 - - MIR/JoinIR Analyzer Box 群(MirAnalyzerBox, JoinIrAnalyzerBox)は基盤実装済み。 -- 直近の目的 - - JoinIR ループ基盤が安定した前提で、「selfhost depth‑2 の最小ループ」がどこまで回るかを再確認する。 - - JsonParserBox 側のループ制約(Pattern1–4 + 将来 Pattern5)と、Analyzer Box の入力形式を揃える。 -- 次にやる候補 - - [ ] Phase 161‑続き: MirAnalyzerBox / JoinIrAnalyzerBox に対する代表ケースの再実行 - (loop パターンが JoinIR 統一後も正しく認識できているか確認)。 - - [ ] Phase 166‑続き: Program JSON v0 / MIR JSON v1 を `.hako` 側で安全にパースできるか確認 - (JsonParserBox のループ制約と衝突しないかをチェック)。 +ここ半年くらいで終わっている主な塊だけをざっくり書くね。 +細かいタスク・バグ票・議論は `phase-XXX*.md` に全部残っているので、必要になったときだけそちらを読む想定。 + +- **LoopBuilder 削除ライン(Phase 180 前後)** + - LoopBuilder を dev‑only → hard freeze → 物理削除まで完了。 + - Loop lowering の SSOT を JoinIR に一本化。 +- **LoopPattern / Router ライン(Phase 170–179)** + - LoopFeatures / LoopPatternKind / PatternRouter / PatternPipelineContext を整備。 + - Pattern1–4 の検出・ルーティングを「構造ベース+AST features」で統一(関数名ベタ書き依存を除去)。 +- **Exit / Boundary / ValueId ライン(Phase 172–205)** + - ExitMeta / ExitLineReconnector / JoinInlineBoundary(+Builder) / LoopHeaderPhiBuilder を箱化。 + - JoinValueSpace(Param/Local 領域)+ PHI 契約 Verifier で ValueId 衝突と PHI 破損を根治。 +- **P5(Trim/JsonParser) ライン(Phase 171–176, 173–175, 190–193)** + - LoopBodyLocal 昇格パイプライン(Trim, `_skip_whitespace`, `_parse_string` 簡易版)を構築。 + - StringAppend / NumberAccumulation / Complex addend 正規化など、更新式まわりの箱を揃えた。 +- **P3 (If‑PHI) 汎用化ライン(Phase 195–196, 212–215)** + - multi‑carrier P3 の JoinIR 生成を整理。 + - Select 展開 / JoinIR→MIR ブリッジ側のバグ(PHI inputs, back‑edge, 二重 remap)を修正。 + - if‑sum 最小パターンを AST ベースで一般化し、ExprResult Exit 契約まで Pattern2 と揃えた。 + +このあたりが「JoinIR ループ基盤の芯」で、以降の Phase は JsonParser/selfhost の各ループへの適用フェーズ、という位置づけだよ。 --- -### 3. hako_check / MIR CFG / JoinIR 解析ライン +## 🧭 これからの候補(まだ「やる」とは決めていないメモ) -- 現状 - - HC019 / HC020(DeadCode / DeadBlocks)など、hako_check 側の Box は JoinIR/MIR CFG を読む経路に統一済み。 - - JsonParserBox による JSON パーサー共通ライブラリ化も進行中(Phase 170–172)。 -- 直近の目的 - - JoinIR / MIR ラインの変更(Pattern1–4, ExitLine, Boundary, ConditionScope)が hako_check に与える影響を最小に保ちつつ、 - 解析結果の精度を維持する。 -- 次にやる候補 - - [ ] Phase 155+ の MIR JSON v1 統合ラインを、最新の JoinIR/Loop 仕様に追随させるかどうかの判断。 - (今のところブロッカーではないので優先度は中〜低) +ここは「やることリスト」ではなく「今後やるとしたらこの辺」というメモにする。 +実際に着手するタイミングで、別途 Phase/タスクを切る想定だよ。 + +1. JsonParser 残りループへの JoinIR 展開 + - `_parse_array` / `_parse_object` / `_unescape_string` / 本体 `_parse_string` など。 + - 既存の P2/P3/P4+P5 パイプラインをどこまで延ばせるかを検証するフェーズ。 +2. selfhost depth‑2 ラインの再開 + - `.hako` 側で Program/MIR JSON を読んで JoinIR/MIR/VM/LLVM に流すライン。 + - JsonParser 側のカバレッジが上がったあとに、小さいループから順に移植する。 +3. JoinIR Verify / 最適化まわり + - すでに PHI/ValueId 契約は debug ビルドで検証しているので、 + 必要なら SSA‐DFA や軽い最適化(Loop invariant / Strength reduction)を検討。 --- -## ✅ 最近完了した主なフェーズ(抜粋) +## 📎 このファイルの運用ルール(自分向けメモ) -ここは「今の作業に強く関係する直近フェーズ」だけをざっくり残すよ。詳細は各 phase ドキュメントを参照。 +- 過去フェーズの詳細な ToDo/Done リストは **CURRENT_TASK には書かない**。 + 代わりに `phase-XXX*.md` と `joinir-architecture-overview.md` を SSOT として維持する。 +- CURRENT_TASK は「あくまで最新のフォーカスと次の候補だけ」に絞る。 + 目安として **このファイル自体は 2〜3画面程度(〜300行以内)** に収める。 +- 新しい大フェーズを始めたら: + 1. まず docs 配下に `phase-XXX-*.md` を書く。 + 2. CURRENT_TASK には「そのフェーズの一行要約」と「今のフォーカスかどうか」だけを書く。 -- **Phase 33‑16/20/21**: Loop header PHI / ExitLine / Boundary の SSOT 化 - → ループ変数の現在値と exit 値が header PHI / ExitLine 経由で一貫して伝播するようになった。 - -- **Phase 33‑18/19/20**: Pattern4(continue)・else‑continue 正規化・carrier フィルタリング - → continue 含みのループ(Pattern4)が JoinIR 統一ラインの中で動作。 - `ContinueBranchNormalizer` / `LoopUpdateAnalyzer` / `CarrierInfo` ラインが安定。 - -- **Phase 165**: JoinIR ループ Pattern1–4 代表ケースの完全検証 - → loop_min_while / joinir_min_loop / loop_if_phi / loop_continue_pattern4 で - `[joinir/freeze]` と SSA‑undef を全排除。 - -- **Phase 170‑D (+BugFix)**: LoopConditionScopeBox 実装&パラメータ誤分類バグ修正 - → ループ条件の変数スコープ分類(LoopParam / OuterLocal / LoopBodyLocal)が安定。 - JsonParserBox の `s`, `pos`, `len` など関数パラメータが正しく OuterLocal と見なされるようになった。 - -- **Phase 168–169**: BoolExprLowerer / condition_to_joinir 強化 - → `_trim` / `_skip_whitespace` の OR chain / AND / NOT を JoinIR/MIR に正しく落とせるようになった。 - (ただし LoopBodyLocal 条件をどう扱うかは Pattern5 設計の領域として切り出し済み) - ---- - -## 📌 このファイルの運用方針 - -- CURRENT_TASK.md には「直近 1〜2 週間で触っているライン」と「次にやる候補」だけを書く。 -- フェーズごとの詳細ログ・長文の議事録・実装メモは: - - `docs/development/current/main/10-Now.md` - - `docs/development/current/main/phaseXX*.md` - に移し、このファイルからはリンクまたは簡単な要約だけに留める。 -- もし CURRENT_TASK がまた肥大化してきたら、 - 古いセクションを phase ドキュメント側に逃して、このファイルを再度「現在地サマリ」に戻す。 diff --git a/docs/development/current/main/phase213-session-summary.md b/docs/development/current/main/phase213-session-summary.md index bf8d0abe..c87083e4 100644 --- a/docs/development/current/main/phase213-session-summary.md +++ b/docs/development/current/main/phase213-session-summary.md @@ -1,8 +1,8 @@ # Phase 213: セッション進捗サマリー **Date**: 2025-12-09 (Continuation Session) -**Status**: 🚧 進行中 -**Current Commit**: d7805e59 (Phase 213-2 & Refactoring計画) +**Status**: ✅ 完了(Phase 213-2 + Refactoring 5.1) +**Current Commit**: 83940186 (Refactoring 5.1 完了) --- @@ -50,24 +50,26 @@ --- -### 🚀 実装中: Refactoring 5.1 +### ✅ 実装完了: Refactoring 5.1 -**目標:** Pattern 3 を Pattern 4 と同じ ExitMeta ベースアーキテクチャに統一化 +**目標:** Pattern 3 を Pattern 4 と同じ ExitMeta ベースアーキテクチャに統一化 ✅ **変更対象:** 1. `loop_with_if_phi_minimal.rs` - - 署名: `Option` → `Result<(JoinModule, JoinFragmentMeta), String>` - - ExitMeta 動的生成ロジック追加 + - 署名: `Option` → `Result<(JoinModule, JoinFragmentMeta), String>` ✅ + - ExitMeta 動的生成ロジック追加 ✅ 2. `pattern3_with_if_phi.rs` - - Hardcoded 定数削除(`PATTERN3_K_EXIT_*_ID`) - - Manual exit binding → ExitMetaCollector に置き換え + - Hardcoded 定数削除(`PATTERN3_K_EXIT_*_ID`)✅ + - Manual exit binding → ExitMetaCollector に置き換え ✅ -**期待効果:** -- ✅ Hardcoded ValueIds 完全削除 -- ✅ Pattern 3/4 アーキテクチャ統一化 -- ✅ 42行削減(pattern3_with_if_phi.rs の22%) -- ✅ Phase 213 AST-based generalization の基盤強化 +**達成効果:** +- ✅ Hardcoded ValueIds 完全削除(`PATTERN3_K_EXIT_SUM_FINAL_ID`, `PATTERN3_K_EXIT_COUNT_FINAL_ID`) +- ✅ Pattern 3/4 アーキテクチャ統一化(同一の ExitMeta パターン) +- ✅ 19行削減(net)、42行の手動ロジック削除 +- ✅ Phase 214 AST-based generalization の基盤強化 +- ✅ テスト全 PASS(E2E: `loop_if_phi.hako` → sum=9) +- ✅ Commit: `83940186` --- @@ -106,25 +108,29 @@ Pattern 3 Builder ## 📝 次のステップ(推奨順) -### Step 1: Refactoring 5.1 完了待機 (進行中) -- Task エージェント実装中 -- Build & Test 確認待ち +### ✅ Step 1: Refactoring 5.1 完了 (完了) +- ✅ Task エージェント実装完了 +- ✅ Build & Test 確認完了(全テスト PASS) +- ✅ Commit: `83940186` -### Step 2: Refactoring 5.1 統合 & コミット -- 実装結果確認 -- 既存テスト合格確認 -- コミット & ドキュメント更新 +### ✅ Step 2: Refactoring 5.1 統合 & コミット (完了) +- ✅ 実装結果確認(19行削減、42行ロジック削除) +- ✅ 既存テスト合格確認(E2E: loop_if_phi.hako → sum=9) +- ✅ コミット & ドキュメント更新 -### Step 3: Refactoring 5.2 実装(選択的) +### 🚧 Step 3: Refactoring 5.2 実装(HIGH PRIORITY - 次のステップ) - Dummy count backward compat 削除 - Single-carrier テスト廃止 or 更新 - Multi-carrier の完全化 +- 推定時間: 2-3時間 +- 削減予定: 20行 -### Step 4: Phase 213 本体進行(Phase 214に延期予定) +### 📋 Step 4: Phase 214 本体進行(Phase 213 から繰り上げ) - Pattern3IfAnalyzer 実装 - AST-based condition lowering - AST-based update expression lowering -- ExitMeta による exit binding 統一化 +- ExitMeta による exit binding 統一化(完了済み) +- 目標: `phase212_if_sum_min.hako` → RC=2 達成 --- @@ -195,5 +201,5 @@ Pattern 3 Builder --- -**Status**: Phase 213 の基盤構築完了 ✅ -**Next**: Refactoring 5.1 の結果確認 & 統合 +**Status**: Phase 213 完全完了 ✅(Phase 213-2 + Refactoring 5.1) +**Next**: Refactoring 5.2(推奨)または Phase 214 本体(AST-based lowerer) diff --git a/docs/development/current/main/phase215-expr-result-exit-contract.md b/docs/development/current/main/phase215-expr-result-exit-contract.md new file mode 100644 index 00000000..72ca8bde --- /dev/null +++ b/docs/development/current/main/phase215-expr-result-exit-contract.md @@ -0,0 +1,311 @@ +# Phase 215: ExprResult Exit Contract + +## Overview + +Phase 215 establishes a unified ExprResult Exit Contract to properly propagate loop computation results from JoinIR lowerers through to the final MIR return statement. + +**Problem**: Loop computations (e.g., `sum=9` in if-sum pattern) execute correctly but return RC=0 instead of the expected value because `expr_result` gets discarded at the final return statement. + +**Goal**: Make `expr_result` with `ParamRole::ExprResult` propagate consistently from JoinIR lowerers → ExitMeta → Boundary → ExitLine → MIR return statement. + +## Current State Analysis + +### Investigation Results (Phase 215 Task Agent) + +#### Pattern 1 (Simple While) +- **File**: `src/mir/join_ir/lowering/simple_while_minimal.rs` +- **Return Type**: `Option` (no JoinFragmentMeta) +- **expr_result Support**: ❌ None +- **Status**: Intentionally simple, no value propagation needed + +#### Pattern 2 (Loop with Break) +- **File**: `src/mir/join_ir/lowering/loop_with_break_minimal.rs` +- **Return Type**: `(JoinModule, JoinFragmentMeta)` +- **expr_result Creation**: ✅ Line 502 + ```rust + let fragment_meta = JoinFragmentMeta::with_expr_result(i_exit, exit_meta); + ``` +- **Boundary Passing**: ✅ Line 447 + ```rust + .with_expr_result(fragment_meta.expr_result) + ``` +- **Final Return**: ❌ Lines 461-468 - **DISCARDS expr_result** + ```rust + // Phase 188-Impl-2: Return Void (loops don't produce values) + // The subsequent 'return i' statement will emit its own Load + Return + let void_val = crate::mir::builder::emission::constant::emit_void(self); + trace::trace().debug("pattern2", &format!("Loop complete, returning Void {:?}", void_val)); + Ok(Some(void_val)) + ``` +- **Root Cause**: Design assumes loops update `variable_map` and subsequent statements read from it + +#### Pattern 3 (If-PHI) +- **File**: `src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs` +- **Return Type**: `(JoinModule, JoinFragmentMeta)` +- **expr_result Creation**: ❌ Line 427 - **Uses carrier_only()** + ```rust + let fragment_meta = JoinFragmentMeta::carrier_only(exit_meta); + ``` +- **Boundary Passing**: ❌ No `.with_expr_result()` call (lines 176-180) +- **Final Return**: ❌ Lines 192-196 - Returns Void + ```rust + let void_val = crate::mir::builder::emission::constant::emit_void(self); + trace::trace().debug("pattern3/if-sum", &format!("Loop complete, returning Void {:?}", void_val)); + Ok(Some(void_val)) + ``` +- **Status**: **Primary target for Phase 215 fix** + +#### Pattern 4 (Loop with Continue) +- **File**: `src/mir/join_ir/lowering/loop_with_continue_minimal.rs` +- **Return Type**: `(JoinModule, ExitMeta)` (no JoinFragmentMeta - **inconsistent API**) +- **expr_result Support**: ❌ None +- **Status**: API inconsistency, but not primary target + +## Data Flow Diagram + +### Current Flow (RC=0 Problem) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ JoinIR Lowerer (Pattern 3) │ +│ │ +│ lower_loop_with_if_phi_pattern() │ +│ └─> JoinFragmentMeta::carrier_only(exit_meta) │ +│ ├─> exit_meta: ExitMeta { │ +│ │ exit_values: {"sum" → ValueId(1008)} │ +│ │ } │ +│ └─> expr_result: None ← ❌ PROBLEM HERE │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Pattern3 Dispatcher (pattern3_with_if_phi.rs) │ +│ │ +│ lower_pattern3_if_sum() / lower_pattern3_legacy() │ +│ └─> JoinInlineBoundaryBuilder::new() │ +│ ├─> .with_inputs(join_inputs, host_inputs) │ +│ ├─> .with_exit_bindings(exit_bindings) │ +│ └─> ❌ NO .with_expr_result() call │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ JoinIRConversionPipeline │ +│ │ +│ execute(builder, join_module, boundary, ...) │ +│ └─> exit_line_reconnector::reconnect_exit_lines() │ +│ └─> ExitLineReconnector::run() │ +│ └─> Updates variable_map with exit PHIs │ +│ {"sum" → ValueId(r456)} ← Correct! │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Pattern3 Final Return (pattern3_with_if_phi.rs) │ +│ │ +│ let void_val = emit_void(self); │ +│ Ok(Some(void_val)) ← ❌ DISCARDS expr_result! │ +│ │ +│ Result: RC=0 (Void type) │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Target Flow (Phase 215 Goal) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ JoinIR Lowerer (Pattern 3) │ +│ │ +│ lower_loop_with_if_phi_pattern() │ +│ └─> ✅ JoinFragmentMeta::with_expr_result( │ +│ sum_final_value, ← "sum" carrier final value │ +│ exit_meta │ +│ ) │ +│ ├─> exit_meta: ExitMeta { │ +│ │ exit_values: {"sum" → ValueId(1008)} │ +│ │ } │ +│ └─> expr_result: Some(ValueId(1008)) ← ✅ FIX 1 │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Pattern3 Dispatcher (pattern3_with_if_phi.rs) │ +│ │ +│ lower_pattern3_if_sum() / lower_pattern3_legacy() │ +│ └─> JoinInlineBoundaryBuilder::new() │ +│ ├─> .with_inputs(join_inputs, host_inputs) │ +│ ├─> .with_exit_bindings(exit_bindings) │ +│ └─> ✅ .with_expr_result(fragment_meta.expr_result) │ +│ ← FIX 2: Pass expr_result to boundary │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ JoinIRConversionPipeline │ +│ │ +│ execute(builder, join_module, boundary, ...) │ +│ ├─> Merge blocks (allocates PHI nodes) │ +│ │ └─> exit_phi_result_id = Some(ValueId(r999)) │ +│ │ ↑ │ +│ │ └─ This is the merged expr_result PHI! │ +│ │ │ +│ └─> exit_line_reconnector::reconnect_exit_lines() │ +│ └─> ExitLineReconnector::run() │ +│ ├─> Updates variable_map with exit PHIs │ +│ │ {"sum" → ValueId(r456)} │ +│ │ │ +│ └─> ✅ Returns exit_phi_result_id │ +│ Some(ValueId(r999)) ← FIX 3 │ +└─────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Pattern3 Final Return (pattern3_with_if_phi.rs) │ +│ │ +│ let loop_result = JoinIRConversionPipeline::execute(...)?; │ +│ if let Some(result_id) = loop_result { │ +│ ✅ Ok(Some(result_id)) ← FIX 4: Return expr_result! │ +│ } else { │ +│ let void_val = emit_void(self); │ +│ Ok(Some(void_val)) │ +│ } │ +│ │ +│ Result: RC=2 (Integer value) │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Where expr_result Gets Discarded + +### Primary Discard Points + +1. **Pattern 3 JoinIR Lowerer** (Line 427) + - File: `src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs` + - Code: `JoinFragmentMeta::carrier_only(exit_meta)` + - Effect: Sets `expr_result = None`, losing the loop result ValueId + +2. **Pattern 3 Boundary Builder** (Lines 176-180) + - File: `src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs` + - Missing: `.with_expr_result()` call + - Effect: Boundary doesn't know about expr_result + +3. **Pattern 3 Final Return** (Lines 192-196, 312-316) + - File: `src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs` + - Code: `let void_val = emit_void(self); Ok(Some(void_val))` + - Effect: Discards merge result, returns Void + +### Secondary Discard Points + +4. **Pattern 2 Final Return** (Lines 461-468) + - File: `src/mir/join_ir/lowering/loop_with_break_minimal.rs` + - Code: Same Void return pattern + - Note: Pattern 2 correctly creates expr_result but also discards it + +## Implementation Plan + +### Task 215-2: Unify expr_result in Lowerers + +**Pattern 3 Changes**: +1. Change `JoinFragmentMeta::carrier_only()` to `with_expr_result()` in both: + - `loop_with_if_phi_minimal.rs` (legacy lowerer) + - `loop_with_if_phi_if_sum.rs` (if-sum lowerer) +2. Identify which carrier represents the loop result (e.g., "sum" in if-sum pattern) +3. Pass that carrier's ValueId as expr_result + +**Pattern 1/2 Audit**: +- Pattern 1: No changes needed (intentionally simple) +- Pattern 2: Already correct, use as reference implementation + +### Task 215-3: Unify Boundary/ExitLine Handling + +**Boundary Changes** (`pattern3_with_if_phi.rs`): +```rust +let boundary = JoinInlineBoundaryBuilder::new() + .with_inputs(join_inputs, host_inputs) + .with_exit_bindings(exit_bindings) + .with_loop_var_name(Some(ctx.loop_var_name.clone())) + .with_expr_result(fragment_meta.expr_result) // ← ADD THIS + .build(); +``` + +**ExitLine Changes** (if needed): +- Verify `ExitLineReconnector` already handles expr_result correctly +- Current implementation returns `Option` from merge +- Should propagate `exit_phi_result_id` when expr_result exists + +**Final Return Changes** (`pattern3_with_if_phi.rs`): +```rust +// Replace Void return with conditional expr_result return +let merge_result = JoinIRConversionPipeline::execute(...)?; + +if let Some(result_id) = merge_result { + // Loop produced a value (expr-position) + Ok(Some(result_id)) +} else { + // Loop only updates variable_map (statement-position) + let void_val = emit_void(self); + Ok(Some(void_val)) +} +``` + +### Task 215-4: Testing + +**Primary Target**: +- `phase212_if_sum_min.hako` → Expected: RC=2 (sum value) + +**Regression Tests**: +- `loop_if_phi.hako` → Expected: sum=9 in variable_map (statement-position) +- Multi-carrier tests → Expected: All carriers updated correctly +- Pattern 1/2/4 tests → Expected: No behavioral changes + +**Verification**: +- MIR dump: Check final return uses correct ValueId +- JoinIRVerifier: Ensure no contract violations +- VM execution: Verify correct RC values + +### Task 215-5: Documentation + +**Update Files**: +1. `phase212-if-sum-impl.md` - Mark Phase 215 as complete +2. `joinir-architecture-overview.md` - Add ExprResult flow section +3. `CURRENT_TASK.md` - Record Phase 215 completion + +## Design Contracts + +### JoinFragmentMeta Contract + +```rust +pub struct JoinFragmentMeta { + pub expr_result: Option, // Loop result for expr-position + pub exit_meta: ExitMeta, // Carrier exit values +} +``` + +**Usage Rules**: +- `carrier_only(exit_meta)`: Statement-position loops (updates variable_map only) +- `with_expr_result(value_id, exit_meta)`: Expr-position loops (returns value) + +### ParamRole Contract + +```rust +pub enum ParamRole { + LoopParam, // Loop variable (e.g., i) + Condition, // Loop condition result + Carrier, // Carrier value (e.g., sum) + ExprResult, // Final expression result ← New role +} +``` + +**Usage Rules**: +- `Carrier`: Updates `variable_map` via `exit_bindings` +- `ExprResult`: Returns from loop expression via merge result + +### ExitLineReconnector Contract + +**Input**: `JoinInlineBoundary` with optional `expr_result` +**Output**: `Option` (merge result for expr-position loops) + +**Behavior**: +1. Update `variable_map` with all `exit_bindings` (Carrier role) +2. If `expr_result` exists, return `exit_phi_result_id` (ExprResult role) +3. Distinguish "carrier to variable_map" vs "expr_result to return" + +## References + +- **Phase 213**: AST-based if-sum lowering (dual-mode architecture) +- **Phase 214**: Dynamic join_inputs generation fix +- **Phase 188**: Original JoinIR pipeline design +- **Phase 33-16**: LoopHeaderPhi integration diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs index 365dd75a..ddaa7ff8 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs @@ -173,15 +173,26 @@ impl MirBuilder { ) ); - let boundary = JoinInlineBoundaryBuilder::new() + // Phase 215-2: Pass expr_result to boundary + let mut boundary_builder = JoinInlineBoundaryBuilder::new() .with_inputs(join_inputs, host_inputs) .with_exit_bindings(exit_bindings) - .with_loop_var_name(Some(ctx.loop_var_name.clone())) - .build(); + .with_loop_var_name(Some(ctx.loop_var_name.clone())); + + // Add expr_result if present + if let Some(expr_id) = fragment_meta.expr_result { + trace::trace().debug( + "pattern3/if-sum", + &format!("Passing expr_result={:?} to boundary", expr_id) + ); + boundary_builder = boundary_builder.with_expr_result(Some(expr_id)); + } + + let boundary = boundary_builder.build(); // Execute JoinIR conversion pipeline use super::conversion_pipeline::JoinIRConversionPipeline; - let _ = JoinIRConversionPipeline::execute( + let merge_result = JoinIRConversionPipeline::execute( self, join_module, Some(&boundary), @@ -189,11 +200,23 @@ impl MirBuilder { debug, )?; - // Return Void (loop doesn't produce values) - use crate::mir::builder::emission::constant; - let void_val = constant::emit_void(self); - trace::trace().debug("pattern3/if-sum", &format!("Loop complete, returning Void {:?}", void_val)); - Ok(Some(void_val)) + // Phase 215-2: Return expr_result if present (expr-position loop) + if let Some(expr_val) = merge_result { + trace::trace().debug( + "pattern3/if-sum", + &format!("Loop complete, returning expr_result {:?}", expr_val) + ); + Ok(Some(expr_val)) + } else { + // Statement-position loop (carrier-only) + use crate::mir::builder::emission::constant; + let void_val = constant::emit_void(self); + trace::trace().debug( + "pattern3/if-sum", + &format!("Loop complete, returning Void {:?}", void_val) + ); + Ok(Some(void_val)) + } } /// Phase 188-195: Legacy PoC lowerer (hardcoded conditions) diff --git a/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs b/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs index 11b2de33..890a5151 100644 --- a/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs +++ b/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs @@ -306,11 +306,15 @@ pub fn lower_if_sum_pattern( exit_values.push(("count".to_string(), count_final)); let exit_meta = ExitMeta::multiple(exit_values); - let fragment_meta = JoinFragmentMeta::carrier_only(exit_meta); + + // Phase 215-2: Use with_expr_result to propagate sum as loop result + // sum_final is the k_exit return value - this is what `return sum` should use + let fragment_meta = JoinFragmentMeta::with_expr_result(sum_final, exit_meta); eprintln!("[joinir/pattern3/if-sum] Generated AST-based JoinIR"); eprintln!("[joinir/pattern3/if-sum] Loop: {} {:?} {}", loop_var, loop_op, loop_limit); eprintln!("[joinir/pattern3/if-sum] If: {} {:?} {}", if_var, if_op, if_value); + eprintln!("[joinir/pattern3/if-sum] Phase 215-2: expr_result={:?}", sum_final); Ok((join_module, fragment_meta)) }