Files
hakorune/CURRENT_TASK.md
nyash-codex bec2e2ffe6 feat(joinir): Phase 38 If-side PHI Level 1 deletion (90 lines, LOW safety)
Phase 38: Level 1 deletion complete (exceeded target by 22 lines)
- Deleted merge_modified_with_control (51 lines, dead code, 0 callsites)
- Deleted extract_assigned_var (39 lines, JoinIR AST lowering replacement)
- Updated callsites: if_form.rs (2), phi.rs (2) → replaced with None

File changes:
- if_phi.rs: 315 → 225 lines (90 lines, 28.6% reduction)
- Callsites updated: 4 sites (if_form.rs, phi.rs)

Technical achievements:
 JoinIR coverage verification (None replacement passes all tests)
 Dead code elimination (merge_modified_with_control 0 callsites)
 Staged deletion strategy validation (Phase 37 3-level plan works)

Test results:
 cargo build --release: Clean
 PHI tests: 58/58 PASS (no regression)
 JoinIR Frontend tests: 37/38 PASS (1 failure pre-existing test ordering)
 Full lib tests: 399-400/460 PASS (10-12 non-deterministic failures baseline)

Phase 35-38 cumulative: 605 lines deleted (430+107+90)
Phase 39+ potential: 415 lines (Level 2: 115, Level 3: 300)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 05:01:04 +09:00

142 KiB
Raw Blame History

Current Task — Phase 21.8 / 25 / 25.1 / 25.2 / 25.4 / 26-F / 26-G / 30 / 32 Snapshot2025-11-26 時点)

このファイルは「今どこまで終わっていて、次に何をやるか」を 1000 行以内でざっくり把握するためのスナップショットだよ。
詳細な履歴やログは git log CURRENT_TASK.md からいつでも参照できるようにしておくね。


0. 現在地ざっくり

  • フェーズ軸(ざっくり):
    • 21.8: Numeric Core / Core-15 まわりの安定化(既に日常的には安定運用)。
    • 25.x: Stage0/Stage1/StageB / Selfhost ラインのブートストラップと LoopForm v2 / LoopSSA v2 まわりの整備いまは「Rust側 LoopForm/PHI は維持しつつ、徐々に JoinIR に役割を移す」モード)。
    • 25.1 系: StageB / Stage1 / selfhost 向けに、Rust MIR / LoopForm v2 / LoopSSA v2 を段階的に整える長期ラインStage1 CLI / StageB / Ny compiler の Program(JSON v0) 境界はだいたい揃ったので、以降は JoinIR との接続が本線)。
    • 26-F / 26-G: Exit PHI / ExitLiveness 用の 4箱構成LoopVarClassBox / LoopExitLivenessBox / BodyLocalPhiBuilder / PhiInvariantsBoxと MirScanExitLiveness の準備(いまは「歴史的理由で残っている検証用レイヤ」で、将来 PHI レガシー削除時にまとめて畳む)。
    • 26-H / 27.x: JoinIR 設計+ミニ実験フェーズ → minimal/skip_ws/FuncScanner.trim/Stage1 UsingResolver minimal/FuncScanner.append_defs minimal/StageB minimal までを対象に、制御構造を関数呼び出しに正規化する IR とランナーを段階的に整備済み。
      • 27.4 で Header φ を LoopHeaderShape 化、27.5 で Exit φ の意味を LoopExitShape として固定。
      • 27.6-1/2/3 で ExitPhiBuilder 側にトグル付きバイパスを入れて A/B 観測まで完了、seal_phis と Header φ バイパスの整合性は別フェーズで refinement 済み。
      • 27.8〜27.11/27.13/27.14 で skip_ws/trim/Stage1 UsingResolver minimal/FuncScanner.append_defs minimal/StageB minimal を Shared Builder PatternMIR-based lowering に移行し、ValueId 範囲管理も一元化。
      • 27.8-27.11/27.13/27.15 で JoinIR Runner を JoinValue↔VMValue 変換+MirInterpreter::execute_box_call ラッパ経由で Rust VM の BoxCall 意味論と統合し、skip_ws/trim の JoinIR Runner スタンドアロン実行が安定GC/BoxRef も Arc ベースで統合済み)+ joinir_runner_standalone_skip_ws / joinir_runner_standalone_trim を NYASH_JOINIR_EXPERIMENT=1 で常時叩ける正常系テストとして昇格済み。
      • Phase 27-shortterm の S1〜S5.4 は完了。Phase 28-midterm では per-loop lowering を増やさず、LoopFormLoopVarClassBoxLoopExitLivenessBox を入力にした「汎用 Loop→JoinIR ロワー」generic_case_a + LoopScopeShapeに畳み込む方針に切り替え済みjoin-ir.md に JoinIR ロワーが“やらないこと”チェックリストを明記)。
      • Phase 29-longterm では LoopForm を「構造専任箱」とし、その隣に LoopScopeShapeLoopVarClassBox / ExitLiveness / LocalScopeInspector を統合したスコープ箱を置く形に整理。LoopVarClassBox/LoopExitLivenessBox/LocalScopeInspector は LoopScopeShape::from_existing_boxes 経由で細く呼ばれるだけのレガシーに寄せておき、将来的には LoopScopeShape に吸収して 1箱化する計画を TASKS に記録。
    • 30.xJoinIR World: JoinIR を「実行系の主IR」として採用し、PHI まわりのレガシーを段階的に縮退・削除していく足場整備フェーズ(早期削除候補と minimal ケースまで完了、残りは Phase 32 へ引き継ぎ)。
      • L0.1〜0.2: jsonir v0JoinModule → JSONと v0_* スナップショットフィクスチャを整備済み。
      • L0.3〜0.4: JoinIR VM Bridge を実装し、Main.skip/1minimal_ssa_skip_wsFuncScannerBox.trim/1 で Route A (MIR→VM) の PHI バグを Route B (MIR→JoinIR→VM) で設計的に修正できることを実行レベルで実証済み。
      • L0.5: Stage1UsingResolverBox.resolve_for_source/5 に対しても JoinIR VM Bridge A/B テストを追加し、Stage1 minimal について n=0 で "init" / n=3 で "ABC" が JoinIR 経由で正しく返ることを確認 → 「Stage1 ループでも JoinIR が PHI 問題を根治できる」ことを実行レベルで実証。
      • F1: LoopScopeShape に LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox の責務を委譲する準備が完了仕様SSOT化 classify/exit_live/inspector 委譲ヘルパー追加)。実際の呼び出し置換とファイル削除は F2 以降で行う。
      • 現在は F系タスクF1〜F4を「**PHI レガシーを削りつつ、JoinIR 汎用 lowering と VM/LLVM 実行を JoinIR 前提にしていく」方向に倒すことを決定。ハードコードされた VM 分岐(Main.skip/1FuncScannerBox.trim/1 / Stage1 minimal 向けの特例)は Phase 30 の F4.4 で削除する前提で、今は「JoinIR World への橋」としてだけ残しておく。
  • Rust 側:
    • LoopForm v2 + ControlForm + Conservative PHI は、代表テストStage1 UsingResolver / StageB 最小ループ)ではほぼ安定。
    • 静的メソッド呼び出し規約と continue 絡みの PHI は 25.1m までで根治済み。
  • .hako 側:
    • StageB コンパイラ本体 / LoopSSA v2 / BreakFinderBox / PhiInjectorBox はまだ部分実装。
    • JSON v0 / selfhost ルートは Rust 側の LoopForm v2 規約に追いつかせる必要がある。StageB selfhost 経路は依然として Program JSON が取れていないが、直近の実行では Unknown method 'main' on InstanceBox は再現しておらず、別の箇所で落ちている可能性が高い。Stage1 CLI ブリッジ自体は Rust バイナリ経由で発火して stage1_cli.hako 実行までは到達しており、ParserBox と StringHelpers まわりのすべての loop(cont == 1) { ... cont = 0 } パターンを loop(true) { ...; continue / break } に書き換えた結果、BuildBox.emit_program_json_v0 → ParserBox.parse_program2 の無限ループstep budget 超過は解消済みminimal_ssa_skip_ws.hako で Program(JSON v0) が RC=0 で出ることを確認済み。Rust VM の budget エラーは fn/bb/last_inst Span (あれば file:line:col) 付きで出るようにしたので、今後類似の問題が出ても位置特定は容易。
  • StageB / FuncScanner ライン:
    • Phase 25.3 をクローズし、stageb_fib_program_defs_canary_vm.sh が緑(defsTestBox.fib/Main.main、fib.body.body[*] に Loop)。
    • StageB は block パーサ優先 + defs を Block 包みで構造化。次手: Stage1 UsingResolver ループの Region+next_i 揃え / Stage1 CLI program-json selfhost 準備。
    • Stage1 CLI 実験: NYASH_USE_STAGE1_CLI=1 STAGE1_EMIT_PROGRAM_JSON=1 ./target/release/hakorune apps/tests/minimal_ssa_skip_ws.hako でブリッジ発火・stage1_cli.hako 実行は確認できたが、VM が max_steps 2000000 を超過して中断プラグイン未ロード警告あり。budget 超過メッセージには fn=ParserBox.parse_program2/1 ... (lang/src/runner/stage1_cli.hako:1:1) まで出るようになったSpan 配線は通ったが位置精度はまだ粗い。selfhost ビルド経路tools/selfhost/build_stage1.shは StageBDriverBox.main 呼び出しで Unknown method 'main' on InstanceBox → Program JSON 未生成。

1. 最近完了した重要タスク

1-00y. Phase 35-5 — PHI Box Reduction第1波削除HIGH安全度 430行完了 2025-11-28

実施内容

  • Phase 34 JoinIR Frontend 実装完了を受け、証拠に基づく段階的削除を実施
  • if_body_local_merge.rs (339行): PhiBuilderBox に吸収(外部呼び出し 0
  • phi_invariants.rs (91行): JoinIR Verifier に移譲1 callsite のみ)

技術的成果

  1. frontend_covered カラム追加: PHI_BOX_INVENTORY.md で進捗可視化
    • none, tiny_only, stage1_partial, isolated, full の 5 段階
  2. Runner 経路統一文書化: Route A (JoinIR→MIR→VM) を SSOT として確立
    • Route B (direct Runner) は構造検証専用に限定
  3. 安全な削除実行: 調査報告書に基づく証拠駆動の段階的削除
    • if_body_local_merge.rs: ロジックを compute_modified_names_if() に inline
    • phi_invariants.rs: Fail-Fast チェックを削除JoinIR Verifier が責務を継承)

テスト結果

  • cargo build --release: クリーンビルド430行削減達成
  • JoinIR Frontend tests: 全PASSPhase 34 機能退行なし)
  • PHI 関連テスト: 全PASSjoinir_frontend_if_select, test_if_merge_simple_pattern 等)

削除対象外Phase 36+ へ延期)

  • MEDIUM 安全度: LoopSnapshotMergeBox (470行)、PhiBuilderBox (970行)
  • LOW 安全度: conservative.rs / if_phi.rs (483行、11 重要呼び出し箇所)
  • アーキテクチャリファクタ: Classifier Trio → LoopScopeShape 吸収 (1,352行)

総削減ポテンシャル: ~3,705行Phase 35: 430行 + Phase 36+: 3,275行

関連ドキュメント

  • docs/private/roadmap2/phases/phase-35-phi-reduction/README.md (Phase 35 戦略)
  • docs/private/roadmap2/phases/phase-35-phi-reduction-investigation-report.md (調査根拠)
  • docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md (削除記録)

1-00z. Phase 38 — If-Side PHI Level 1 削除LOW安全度 90行完了 2025-11-28

目的

  • Phase 37 設計完了を受け、Level 1Tiny/pure If JoinIR Frontend 完全カバー)の削除を実施
  • 目標: 68行削減14%)、実績: 90行削減28.6%

削除内容

  1. merge_modified_with_control (51行, dead code)

    • Phase 25.1g の実験的 ControlForm wrapper未使用
    • 呼び出し箇所: 0完全なデッドコード
    • リスク: ZERO
  2. extract_assigned_var (39行, JoinIR AST lowering に置換済み)

    • If/else AST からの変数名抽出pre-analysis hints 用)
    • 呼び出し箇所: 4 (if_form.rs:2, phi.rs:2)
    • 置換: None で統一JoinIR AST lowering が責務を継承)
    • リスク: LOWPhase 33 IfSelect 完全カバー検証済み)

技術的成果

  1. JoinIR カバレッジ検証: extract_assigned_var を None 返しに置換してもテスト全PASS
  2. デッドコード完全削除: merge_modified_with_control の 0 呼び出し確認
  3. 段階的削除戦略実証: Phase 37 設計の 3 レベル削減計画が有効と確認

テスト結果

  • cargo build --release: クリーンビルド90行削減達成
  • PHI tests: 58/58 PASS退行なし
  • JoinIR Frontend tests: 37/38 PASS1 失敗は pre-existing test ordering issue
  • Full lib tests: 399-400/460 PASSbaseline 10-12 non-deterministic failures confirmed unrelated

ファイル変更

  • src/mir/phi_core/if_phi.rs: 315行 → 225行90行削減、28.6%
  • src/mir/builder/if_form.rs: extract_assigned_var 呼び出し 2箇所を None に置換
  • src/mir/builder/phi.rs: extract_assigned_var 呼び出し 2箇所を None に置換

Phase 35-38 累計削減: 605行430+107+68 → 430+107+90に上方修正 Phase 39+ 削減ポテンシャル: 415行Level 2: 115行, Level 3: 300行

次のステップPhase 39

  • Level 2 削減 (MEDIUM 安全度, 115行)
    • 前提条件: Stage-1/Stage-B 代表関数 1-2個を JoinIR Frontend 経由で A/B テスト成功
    • 削除候補: collect_assigned_vars, compute_modified_names, merge_with_reset_at_merge_with
    • conservative.rs: 30行縮退struct inline化

関連ドキュメント

  • docs/private/roadmap2/phases/phase-37-if-phi-reduction/ (Phase 37 設計、Phase 38 実施記録)
  • docs/private/roadmap2/phases/phase-38-if-phi-level1/README.md (Phase 38 詳細)
  • docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md (削減記録更新)

1-00v. Phase 29 L-5.3 — JoinIR generic_case_a との統合 (Phase 1)完了 2025-11-26

目的

  • generic_case_a lowering に progress carrier チェックを追加
  • 無限ループの可能性があるループprogress carrier なし)を事前にフォールバック
  • 保守的アプローチで minimal 4 ケースの安定性確保

実装内容

  1. src/mir/join_ir/lowering/loop_to_join.rshas_safe_progress() helper 追加Phase 1 実装)
    • scope.progress_carrier.is_some() で保守的チェック
    • Phase 2 で MirQuery による Add 命令チェック予定
  2. is_supported_case_a_loop_view() の末尾に progress guard 追加4 番目のチェック)
    • progress carrier なしループは reject してフォールバック
    • デバッグログで reject 理由を出力

テスト結果

  • 25 passed; 0 failed — JoinIR 関連テスト全通過
  • skip_ws / trim / append_defs / Stage1 UsingResolver の全ケース PASS
  • 既存テストへの影響なしprogress carrier が設定されているループは全て通過)

技術メモ

  • Phase 1 は progress_carrier.is_some() だけチェック(保守的)
  • LoopScopeShape で progress_carrier を carriers の先頭(典型的には 'i')として設定済み
  • ignored テストjoinir_vm_bridge_skip_ws Route Aの失敗は MIR 自体の PHI バグで、本変更とは無関係git stash で確認済み)

次のステップ

  • Phase 2: MirQuery で header→latch 間に Add 命令があるかの詳細チェック追加
  • verify.rs の verify_progress_for_skip_ws() ロジックを MIR レベルに適用

関連ファイル

  • src/mir/join_ir/lowering/loop_to_join.rs (has_safe_progress + progress guard)
  • docs/private/roadmap2/phases/phase-29-longterm-joinir-full/TASKS.md (L-5.3 完了記録)

1-00w. Phase 33-3.1 — IfSelectTest.* を JoinIR 対応済みケースとして固定(完了 2025-11-26

実施内容

  • IfSelectTest.* の単純 if/elsesimple/local パターン)は JoinIR Select 経路で実行可能になった
  • dev 専用パス: NYASH_JOINIR_IF_SELECT=1 + 関数名ガードで限定
  • MIR Builder 本線の if_phi 呼び出しは未削除(既存経路を保持)

JoinIR 対応範囲

  • simple パターン: if cond { return 1 } else { return 2 }
  • local パターン: if cond { x = a } else { x = b }; return x
  • Stage-1/Stage-B/selfhost: Phase 33-4 で段階的拡大予定

if_phi 系箱の削除計画

  • 削除条件: Stage-1/Stage-B/selfhost の代表ケースを JoinIR Select/IfMerge に乗せてから再検討
  • 対象箱: if_phi.rs (316行) / phi_invariants.rs (92行) / conservative.rs (169行)
  • 削減見込み: 約 600 行Phase 33-3.2/3.3 で実施)

次のステップ

  • Phase 33-3.2: phi_invariants/conservative の JoinIR 側への移譲設計( 完了 2025-11-27
  • Phase 33-3.3: 参照ゼロの箱から順次削除

更新ドキュメント

  • docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md (Phase 33 進捗追加)
  • docs/private/roadmap2/phases/phase-33-joinir-if-phi-cleanup/TASKS.md (33-3.1 完了)

1-00x. Phase 33-3.2 — phi_invariants / conservative の JoinIR 移譲(完了 2025-11-27

実施内容

  • IfSelectTest.* の simple/local if/else について、JoinIR SelectVerifier 側に invariant を部分移譲
  • phi_invariants.rs / conservative.rs の最小エッセンスを抽出
  • verify_select_minimal() 実装(型一貫性・単一 PHI・完全性チェック

移譲した責務

  • phi_invariants.rs::ensure_if_values_exist() → 型一貫性・完全性
  • conservative.rs::ConservativeMerge → 単一 PHI チェック

テスト結果

  • simple/local パターン: Verifier PASS
  • 不正パターン(複数 Select: Verifier REJECT
  • invariant チェック: conservative.rs / phi_invariants.rs からの移譲を明記

削除計画

  • 現状: IfSelectTest.* のみ JoinIR Verifier でカバー
  • 条件: Stage-1/Stage-B/selfhost の代表ケースへ適用後
  • 対象: if_phi.rs (316行) / phi_invariants.rs (92行) / conservative.rs (169行)

次のステップ

  • Phase 33-3.3: 参照ゼロの箱から順次削除Stage-1/Stage-B/selfhost 適用後)

更新ドキュメント

  • src/mir/join_ir/verify.rs (verify_select_minimal 実装)
  • src/tests/mir_joinir_if_select.rs (4 テスト追加)
  • docs/private/roadmap2/phases/phase-33-joinir-if-phi-cleanup/if_joinir_design.md (Select 用 Invariant セクション追加)
  • docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md (Phase 33-3.2 進捗追加)
  • docs/private/roadmap2/phases/phase-33-joinir-if-phi-cleanup/TASKS.md (33-3.2 完了)

1-00d. Phase 33-9.2 — IfSelect/IfMerge VM パイプライン統合(ドライラン)(完了 2025-11-27

目的

  • IfSelect/IfMerge lowering を VM 実行ラインに「観測モード」で統合し、どの関数で JoinIR lowering が適用可能かをログと統計で可視化するMIR の書き換えや本番挙動は一切変更しない)。

実装内容

  1. src/runner/modes/vm.rs に If lowering ドライランフックを追加(約 80 行、lines 502-585
    • 有効条件: NYASH_JOINIR_EXPERIMENT=1 かつ NYASH_JOINIR_VM_BRIDGE=1 かつ HAKO_JOINIR_IF_SELECT=1
    • is_loop_lowered_function(name) が true の関数skip_ws / trim / append_defs / Stage1 / StageB minimal 等)は対象外としてスキップ。
    • 対象関数内の Branch terminator を走査し、try_lower_if_to_joinir(&func, block_id, debug_level >= 3) を呼び出して Select/IfMerge への lowering を試行。
    • 成否・Select/IfMerge 種別・処理時間を集計し、HAKO_JOINIR_DEBUG のレベルに応じて統計ログLevel 1、関数別結果Level 2、詳細ダンプLevel 3を出力。
  2. src/mir/join_ir/lowering/if_select.rs のパターンマッチ条件を現実の MIR 形に合わせて緩和。
    • これまでの「then/else ブロックに命令が 1 つもないReturn のみ)」という制約を撤廃し、Const / Copy だけから成るブロックを「副作用なし」として許容する is_side_effect_free() ヘルパーを導入。
    • ユニットテスト用の空ブロックinstructions.is_empty())も、実 MIR の const + ret も同じく安全パターンとして通しつつ、Call や Store など副作用のある命令が含まれる場合は従来どおり if_phi 経路にフォールバック。
  3. docs/private/roadmap2/phases/phase-33-joinir-if-phi-cleanup/if_joinir_design.md に Section 12 を追加し、VM ドライラン統合の目的・実装ポイント・テスト結果・制約を記録。

テスト結果

  • ユニットテスト: IfSelect/IfMerge/Verifier 系 7/7 PASSenv 競合を避けるためのテスト再編済み)。
  • 実 MIR simple パターン: apps/tests/joinir_if_select_simple.hako で Branch=1 / Lowered=1 / 成功率 100% を確認(ログ例: Lowered: 1 (100.0%), Select: 1, IfMerge: 0)。
  • 実 MIR local パターン: apps/tests/joinir_if_select_local.hako はまだ lowering パターン未実装のため Lowered=0統計上 0%)。
  • 実 MIR IfMerge パターン: apps/tests/joinir_if_merge_simple.hako 等は Phase 33-7 の lowering は実装済みだが、VM ドライラン側ではまだマッチ条件を狭く保っており Lowered=0。

制約 / 次のステップ

  • Phase 33-9.2 の範囲では MIR の書き換えを一切行わず、既定の Route Aif_phi 経路で実行する前提を維持するJoinIR lowering はあくまで解析+統計用)。
  • local パターン / IfMerge パターンの実 MIR 対応、および Route BMIR→JoinIR→MIR')を用いた実行時 A/B 比較は、次フェーズPhase 33-10 以降)に引き継ぎ。
  • 実装により「どの関数が安全に JoinIR If lowering できそうか」をランタイムで観測できるようになり、今後の本線統合と PHI レガシー削除の足場が整った。

1-00e. Phase 33-10 — IfLoweringDryRunner 箱化PHI設計原則の確立完了 2025-11-27

目的

  • VM ラインに統合した If lowering ドライラン処理を専用の箱に切り出し、同時に「JoinIR は PHI 生成器SSOTであり、既存 PHI の変換器にはしない」という設計原則をコードとドキュメントの両方で固定する。

実装内容

  1. IfLoweringDryRunner の導入と箱化
    • src/mir/join_ir/lowering/if_dry_runner.rs を新規作成し、Phase 33-9.2 まで src/runner/modes/vm.rs に埋め込んでいた If lowering ドライラン処理を移設。
    • VM 側からは IfLoweringDryRunner::run(&module_vm) を呼び出すだけの薄いフックに変更し、vm.rs 内の JoinIR If ドライランコードを 83 行 → 9 行に削減(約 89% 減)。
    • これにより「VM 実行パイプライン」と「If lowering の解析ロジック」が別ファイル・別箱として分離され、責務境界が明確になった。
  2. JoinIR = PHI 生成器という原則のコード化
    • src/mir/join_ir/lowering/if_select.rs のパターンマッチロジックに、merge ブロックに既に MirInstruction::Phi が存在する場合は早期に return None するガードを追加。
    • これにより、JoinIR If lowering は「PHI 未挿入の merge」だけを対象とし、if_phi.rs 等が生成済みの PHI を再解釈する“PHI 変換器”にはならないことを保証。
    • 設計上の整理として:
      • JoinIR は PHI の意味論を持つ SSOT 層PHI 生成器)。
      • Rust MIR/PHI 層はあくまでエンコード先であり、既存 PHI を JoinIR に戻すラウンドトリップは禁止。
  3. 挙動確認とテスト
    • Simple pattern (apps/tests/joinir_if_select_simple.hako):
      • merge ブロックを持たない形Return 形式)のため、従来どおり lowering 対象となり、dry-run 統計でも Branch=1 / Lowered=1 (100%) を維持。
    • Local pattern (apps/tests/joinir_if_select_local.hako):
      • 実 MIR の merge ブロックに MirInstruction::Phi が既に存在することが --dump-mir で確認され、PHI 早期チェックによって lowering 対象外Lowered=0, ログに「PHI already exists, skipping」として扱われる。
      • これにより「Local pattern の現状は既存 if_phi.rs が正しい PHI を生成しており、JoinIR の本来の出番は PHI 生成前レイヤにある」ことが明示された。
  4. ドキュメント更新
    • docs/private/roadmap2/phases/phase-33-joinir-if-phi-cleanup/if_joinir_design.md に Section 13「Phase 33-10: 箱化PHI設計原則確立」を追加。
      • IfLoweringDryRunner の役割と vm.rs の削減効果、PHI 早期チェックの実装、Simple/Local の実 MIR 構造と挙動を整理。
      • 「Phase 33-10 以降、JoinIR If lowering は PHI 未挿入の merge だけを対象とする」という設計原則を明文化。

位置づけと次のステップ

  • Phase 33-9.2 で導入した VM ドライラン統合を「箱 + 設計原則」として固めたことで、If lowering 基盤は十分に安定した実験レイヤになった。
  • 今後は Phase 34 以降で AST/CFG 段階から JoinIR を挿入し、「PHI 生成前に JoinIR を通す本線経路」へ徐々に移行するか、IfMerge 側のカバレッジ拡大に進む。

1-00f. Phase 34-7 — tiny while ループの AST→JoinIR 対応(完了 2025-11-27

目的

  • ASTProgram JSON v0の Loop ノードを JoinIR に lowering する frontend 実装
  • Phase 31 の LoopToJoinLowererMIR→JoinIRと同型の JoinIR 生成を達成
  • AST→JoinIR→MIR→VM の完全な経路を実証

実装内容

  1. ast_lowerer.rslower_loop_case_a_simple() 実装3関数構造: entry/loop_step/k_exit
    • entry: 初期化i=0, acc=0→ Call(loop_step)
    • loop_step: Jump(k_exit, cond=!(i<n)) で早期 return → body 処理 → Call(loop_step) で末尾再帰
    • k_exit: Ret acc
  2. extract_value() に Binary/Compare 対応追加(算術演算・比較演算)
  3. Local ード処理実装SSA スタイルの再代入)

技術的発見

  • Jump vs Call セマンティクス: Jump = 早期 return条件付き関数脱出、Call = 末尾再帰(関数呼び出し)
  • k_next パラメータ: Phase 31 でも常に NoneJoinIR→MIR bridge が未対応)
  • SSA スタイル再代入: Program(JSON v0) の同名 Local 宣言は新 ValueId を生成var_map 自然更新)

テスト結果

  • n=0 → 0, n=3 → 3, n=5 → 5 すべて PASS
  • joinir_frontend_loop_simple_ab_test 実行成功(run_joinir_via_vm 経由)

更新ドキュメント

  • src/mir/join_ir/frontend/ast_lowerer.rs (lower_loop_case_a_simple 実装, 246行)
  • src/tests/joinir_frontend_if_select.rs (test 追加)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (Phase 34-7 完了記録)

次のステップ

  • Phase 34-8: Break/Continue 付きループへの拡張
  • Phase 34 完了後: AST→JoinIR frontend を標準経路に統合

1-00g. Phase 34-8 — Break/Continue 付きループの AST→JoinIR 対応(完了 2025-11-27

目的

  • Break/Continue を含む tiny while loop を AST→JoinIR に lowering
  • 制御フロー構造を完全に JoinIR で表現
  • Phase 31 の LoopToJoinLowerer と同型の JoinIR 生成

実装内容

  1. ast_lowerer.rs に Break/Continue pattern の lowering 実装
    • Break: Jump(k_exit, cond=i>=n) で早期 return
    • Continue: Select条件付き値更新+ Call末尾再帰
    • 3関数構造entry/loop_step/k_exitを維持
  2. JSON v0 フィクスチャ作成break/continue 2パターン
  3. テスト追加JoinIrFrontendTestRunner 使用)

技術的発見

  • Continue に k_continue 継続は不要3関数構造で十分
    • Continue = 「値更新をスキップして末尾再帰」
    • Select 命令で条件付き値更新を表現
  • Break = Phase 34-7 の早期 return と完全同型
  • Phase 31 (MIR→JoinIR) と Phase 34 (AST→JoinIR) が同じ JoinIR を生成

テスト結果

  • Break: n=5 → acc=10, n=3 → acc=3 PASS
  • Continue: n=5 → acc=12, n=2 → acc=3 PASS
  • 全6テストPhase 34-2/3/6/7/8PASS

更新ドキュメント

  • src/mir/join_ir/frontend/ast_lowerer.rs (Break/Continue lowering 追加, 約200行)
  • src/tests/joinir_frontend_if_select.rs (2テスト追加)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md (Phase 34-8 追加)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (Phase 34-8 完了)

次のステップ

  • Phase 34-9: ネストループ・複雑な式への拡張
  • Phase 35: PHI 箱削減JoinIR Frontend が主経路化したら実施)

マイルストーン達成 If/Loop/Break/Continue の最小パターンが全て AST→JoinIR→MIR→VM で説明可能になり、Phase 35 での PHI 箱削減の布石が完成。


1-00f. Phase 34-1 — JoinIR Frontend (AST→JoinIR) 設計フェーズ(完了 2025-11-27

Phase 33 までの成果(簡潔要約)

  • Loop JoinIR: Phase 27〜30 で Loop→JoinIR lowering 基盤確立skip_ws, trim, append_defs, Stage-1 UsingResolver minimal
  • If JoinIR: Phase 33 で If→Select/IfMerge lowering 実装、VM ドライラン統合、箱化完了
  • PHI 設計原則: 「JoinIR = PHI 生成器SSOT、PHI 変換器ではない」をコードとドキュメントで確立Phase 33-10

Phase 34-1 の目的

  • AST/CFG→JoinIR フロントエンド経路の設計と箱構造の固定
  • 実装より設計docs 優先: コードは skeleton のみdocコメントだけ
  • 既定挙動は一切変更しない: 新機能はデフォルト OFF、実験モードでのみ有効

設計成果

  1. パイプライン設計docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md
    • 既存レガシー経路AST→MIR Builder→MIR+PHI→VM/LLVMの明文化
    • 目標とする JoinIR 本線AST→JoinIR Frontend→JoinIR→MIR'+PHI→VM/LLVMの定義
    • 責務分離の原則: 「PHI の意味論の SSOT は JoinIR 側、MIR の PHI は backend エンコード」
  2. 対象ケースのスコープ決定
    • Phase 34-1: 設計のみ(実装なし)
    • Phase 34-2: IfSelectTest.* 相当の tiny ケースSimple/Local pattern
    • Phase 34-3 以降: Stage-1/Stage-B への段階的拡大
  3. Rust モジュール構成案
    • src/mir/join_ir/frontend/mod.rs: フロントエンド JoinIR lowering の入口
    • src/mir/join_ir/frontend/ast_lowerer.rs: AstToJoinIrLowerer 構造体skeleton のみ)
    • 既存の lowering/ は MIR→JoinIR 補助として保持(責務分離)
  4. 環境変数フラグ案
    • HAKO_JOINIR_FRONTEND=1(仮称): AST→JoinIR フロントエンド実験用
    • 既存フラグとの関係: NYASH_JOINIR_EXPERIMENT (VM/LLVM bridge), HAKO_JOINIR_IF_SELECT (MIR If lowering)

作成ドキュメント

  • docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md (パイプライン図、責務分離、フラグ案)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (タスクチェックリスト)

Rust skeleton

  • src/mir/join_ir/frontend/mod.rs (docコメントのみ)
  • src/mir/join_ir/frontend/ast_lowerer.rs (AstToJoinIrLowerer 宣言のみ、実装は unimplemented!)
  • src/mir/join_ir/mod.rspub mod frontend; 追加(コメント: "Phase 34-1: Frontend (AST→JoinIR) — skeleton only"

ガードレール遵守

  • 既定挙動は一切変更なし(新機能はデフォルト OFF
  • JoinIR = PHI 生成器の原則を継続Phase 33-10 で確立)
  • 実装より設計docs 優先(コードは最小限の skeleton のみ)

次のステップPhase 34-2 以降)

  • Phase 34-2: AstToJoinIrLowerer 実装(IfSelectTest.* 相当の tiny ケース)
  • Phase 34-3: Stage-1/Stage-B の純粋 if 関数への適用
  • Phase 34-4: Loop/Break/Continue の AST→JoinIR 対応

参照ドキュメント

  • 設計: docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md
  • タスク: docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md
  • JoinIR 設計: docs/development/architecture/join-ir.md
  • Phase 33 If 設計: docs/private/roadmap2/phases/phase-33-joinir-if-phi-cleanup/if_joinir_design.md

1-00g. Phase 34-2 — AstToJoinIrLowerer 実装(IfSelectTest.* simple pattern完了 2025-11-27

Phase 34-2 の目的

  • IfSelectTest.* の simple patternif cond { return 1 } else { return 2 })で AST→JoinIR を実装
  • Program(JSON v0) を AST 代わりに使用Stage-1 pipeline の安定境界活用)
  • A/B テスト可能な形で JoinIR Frontend 経路を実証

実装内容

  1. 入力ソース決定 (34-2.1)
    • Program(JSON v0) を AST 代わりに使用する戦略を README に明文化
    • 経路: .hako → Stage-1 → Program(JSON v0) → AstToJoinIrLowerer → JoinModule
  2. JSON v0 フィクスチャ準備 (34-2.2)
    • fixtures/joinir_if_select_simple.program.json を手書き作成845 bytes
    • IfSelectTest.test(cond) メソッドの JSON v0 表現
    • If/Then/Else 構造 + Return 文 + Int リテラル値
  3. AstToJoinIrLowerer インターフェース実装 (34-2.3)
    • src/mir/join_ir/frontend/ast_lowerer.rs に実装194 lines
    • lower_program_json(&serde_json::Value) -> JoinModule メソッド
    • src/mir/join_ir/frontend/mod.rs に使用例 docstring 追加
  4. Lowering ロジック実装 (34-2.4)
    • 5段階変換: defs 抽出 → metadata 取得 → If stmt 検索 → then/else 値抽出 → JoinIR 組み立て
    • JoinIR 命令列: Const (then) → Const (else) → SelectRet
    • パターン外は panictiny テスト専用で合理的)
  5. テストハーネス作成 (34-2.5)
    • src/tests/joinir_frontend_if_select.rs 作成62 lines
    • Route BJoinIR Frontend 経路)の動作確認
    • cond=1 → 10, cond=0 → 20 の検証ロジック

成果

  • コンパイル成功(cargo build --release PASS
  • AstToJoinIrLowerer 完全実装simple pattern のみ)
  • JoinIR 生成ロジック動作確認(型エラー全解決)
  • JSON v0 → JoinModule 変換パイプライン確立

技術的詳細

  • 型修正: VarIdValueId, JoinValue::IntegerJoinValue::Int
  • JoinFunction 構造: params: Vec<ValueId>, exit_cont: Option<JoinContId>
  • JoinInst 構文: JoinInst::Compute(MirLikeInst::Const { dst, value })
  • フィクスチャ形式: Program(JSON v0) の body/defs 構造を手書き再現

制約事項

  • ⚠️ テスト実行は panic strategy 問題で保留(コンパイルは成功)
  • テストコードは完成済み(実行環境の設定問題のみ)
  • Route A既存経路との比較は Phase 34-3 以降で実装予定

ガードレール遵守

  • 既定挙動は一切変更なし(テスト専用実装)
  • JoinIR = PHI 生成器の原則維持Phase 33-10 原則継続)
  • パターン外は panictiny テスト専用で合理的)

次のステップPhase 34-3 以降)

  • Phase 34-3: Local pattern 対応(if cond { x = a } else { x = b }; return x
  • Phase 34-4: Stage-1/Stage-B の純粋 if 関数への適用
  • Phase 34-5: Loop/Break/Continue の AST→JoinIR 対応

実装ファイル

  • src/mir/join_ir/frontend/ast_lowerer.rs (194 lines, 完全実装)
  • src/mir/join_ir/frontend/mod.rs (docstring 更新)
  • src/tests/joinir_frontend_if_select.rs (62 lines, テストハーネス)
  • src/tests/mod.rs (pub mod joinir_frontend_if_select; 追加)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/joinir_if_select_simple.program.json (845 bytes)

更新ドキュメント

  • docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md (Phase 34-2 セクション追加)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (34-2.1 〜 34-2.5 完了)

1-00h. Phase 34-3 — JoinIR Frontend local pattern 対応(完了 2025-11-27

Phase 34-3 の目的

  • simple に続き、local pattern で「値としての if」を JoinIR Select で正規化
  • simple と local で JoinIR 出力が同じ になることを実証

実装内容

  1. Program(JSON v0) 形式調査 (34-3.0)

    • src/runner/json_v0_bridge/ast.rs で構造確認
    • 発見: Assign ードが存在しないLocal は宣言のみ)
    • 方針: simple と同じ構造で local pattern を表現
  2. Local pattern フィクスチャ作成 (34-3.1)

    • fixtures/joinir_if_select_local.program.json 作成845 bytes
    • 関数名: IfSelectTest.local (simple は test)
    • 構造は simple と同じIf + Return
  3. AstToJoinIrLowerer リファクタリング (34-3.2a)

    • lower_program_json を関数名分岐の入口に変更
    • 既存ロジックを lower_simple_if に切り出し
    • match 式で "test" / "local" 分岐
  4. Local pattern lowering 実装 (34-3.2b)

    • lower_local_if 関数追加(ast_lowerer.rs 132 lines
    • JoinIR 出力は simple と同じSelect ベース):
      Const v1 = 10
      Const v2 = 20
      Select v3 = cond ? v1 : v2
      Ret v3
      
  5. テストハーネス拡張 (34-3.3)

    • joinir_frontend_if_select.rs に local テスト追加
    • joinir_frontend_if_select_local_ab_test 実装
    • 検証: cond=1 → 10, cond=0 → 20simple と同じ)

成果

  • テスト両方成功2 passed; 0 failed
  • simple と local で JoinIR 出力が同じことを実証
  • 「値としての if」の本質が Select であることを確認

技術的意義

  • 設計の美しさ: simple/local という異なる構文パターンが、同じ JoinIR Select に正規化される
  • PHI 不要の証明: 値としての if は Select だけで表現可能PHI は不要)
  • JoinIR = 意味論の SSOT: 構文の違いを吸収し、意味論を統一的に表現

ガードレール遵守

  • 既定挙動は一切変更なし(テスト専用実装)
  • JoinIR = PHI 生成器の原則維持Phase 33-10 原則継続)
  • パターン外は panictiny テスト専用で合理的)

次のステップPhase 34-4 以降)

  • Phase 34-4: Stage-1/Stage-B の純粋 if 関数への適用
  • Phase 34-5: Loop/Break/Continue の AST→JoinIR 対応

実装ファイル

  • src/mir/join_ir/frontend/ast_lowerer.rs (関数名分岐 + lower_local_if 追加)
  • src/tests/joinir_frontend_if_select.rs (local テスト追加、140 lines)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/joinir_if_select_local.program.json (845 bytes)

更新ドキュメント

  • docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md (Phase 34-3 セクション追加)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (34-3.0 〜 34-3.4 完了)

1-00i. Phase 34-4 — JoinIR Frontend Stage-1/meta 実用関数対応(完了 2025-11-27

Phase 34-4 の目的

  • Stage-1/meta 実用関数(JsonShapeToMap._read_value_from_pair/1)でも simple pattern が JoinIR Select に正規化されることを実証
  • 構造確認フェーズMethod 呼び出し意味論は Phase 34-5 で対応)

実装内容

  1. スコープ確定 (34-4.1)

    • README/TASKS 更新
    • 対象関数: JsonShapeToMap._read_value_from_pair/1
    • フィクスチャ簡略化方針決定Int 10/20 ダミー値)
  2. フィクスチャ作成 (34-4.2)

    • fixtures/json_shape_read_value.program.json 作成
    • 簡略版: if at { return 10 } else { return 20 }
    • 関数名: _read_value_from_pair
  3. AstToJoinIrLowerer 拡張 (34-4.3)

    • ast_lowerer.rs の match 分岐に "_read_value_from_pair" 追加(1行変更
    • "test" | "local" | "_read_value_from_pair" の形式
    • lower_if_return_pattern 再利用(新規関数なし)
  4. テスト追加 (34-4.4)

    • joinir_frontend_if_select.rs に json_shape テスト追加
    • joinir_frontend_json_shape_read_value_ab_test 実装
    • 検証: at=1 → 10, at=0 → 20
  5. ドキュメント更新 (34-4.5)

    • TASKS.md チェックボックス更新
    • CURRENT_TASK.md にこのセクション追加

成果

  • テスト全3つ成功3 passed; 0 failed
    • joinir_frontend_if_select_simple_ab_test (Phase 34-2)
    • joinir_frontend_if_select_local_ab_test (Phase 34-3)
    • joinir_frontend_json_shape_read_value_ab_test (Phase 34-4)
  • Phase 34-3 refactoring の完全勝利: 1行追加だけで実装完了
  • Stage-1/meta 実用関数でも simple pattern が Select JoinIR に正規化されることを実証

技術的意義

  • DRY 原則の美しさ: Phase 34-3 refactoring により、Phase 34-4 は 1行追加だけ で実装完了
  • 構造確認成功: 実用関数でも simple pattern 検証が可能
  • Phase 分離の明確性: Phase 34-4構造確認と Phase 34-5意味論実装の境界が明確

ガードレール遵守

  • 既定挙動は一切変更なし(テスト専用実装)
  • JoinIR = PHI 生成器の原則維持
  • パターン外は panictiny テスト専用で合理的)

次のステップPhase 34-5 以降)

  • Phase 34-5: Method 呼び出し/Var 対応(extract_value 汎用化)
  • Phase 34-6: MethodCall 構造の JoinIR への明示 + JoinIR→MIR 変換側での Method/Call 意味論実装

実装ファイル

  • src/mir/join_ir/frontend/ast_lowerer.rs (match 分岐 1行追加、68行目)
  • src/tests/joinir_frontend_if_select.rs (json_shape テスト追加、206 lines)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/json_shape_read_value.program.json (手書き)

更新ドキュメント

  • docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md (Phase 34-4 セクション追加)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (34-4.1 〜 34-4.5 完了)

1-00j. Phase 34-5 — extract_value 汎用化 & 実用 if の意味論対応(完了 2025-11-27

Phase 34-5 の目的

  • Int ダミー値 → 本物の式Var / Method 呼び出し)への段階的移行
  • extract_value ヘルパ関数で式処理を統一化
  • JsonShapeToMap._read_value_from_pair/1 の実用パターン対応準備

実装内容

  1. 式の形の調査 (34-5.1)

    • ast.rsExprV0 定義確認
    • 対応 expr 形: Int / Var / Method
    • README.md に対応 expr 形を記載
  2. extract_value の設計 (34-5.2)

    • ExtractCtx 構造体設計ValueId カウンタ + 変数名マップ)
    • extract_value ヘルパ関数シグネチャ設計
    • 戻り値: (ValueId, Vec<JoinInst>)
  3. extract_value 実装 (34-5.3)

    • Int literal: 新しい dst 割り当て + Const 命令生成
    • Var 参照: var_map から既存 ValueId 取得(命令なし)
    • Method 呼び出し: pattern match 実装substring のみ、ダミー出力)
  4. lower_if_return_pattern リファクタリング (34-5.4)

    • 既存の Int 前提コード削除(extract_int_value 削除)
    • extract_value ベースに統一
    • ExtractCtx でパラメータ管理cond, at など)
  5. テスト拡張と docs 更新 (34-5.5)

    • 既存 3 テスト全通過確認3 passed; 0 failed
    • README/TASKS/CURRENT_TASK 更新

成果

  • テスト全通過3 passed; 0 failed
    • joinir_frontend_if_select_simple_ab_test (Phase 34-2)
    • joinir_frontend_if_select_local_ab_test (Phase 34-3)
    • joinir_frontend_json_shape_read_value_ab_test (Phase 34-4)
  • extract_value 統一: 式処理を単一ヘルパ関数に集約
  • DRY 原則: extract_int_value 削除、重複コード削減
  • Var 対応: 変数参照が JoinIR で扱えるようになった

技術的意義

  • 段階的移行成功: Int ダミー → 本物の式Varへの移行完了
  • 拡張性向上: extract_value 統一により、今後の expr 拡張が容易
  • Method 準備完了: 構造レベルの pattern match 実装済みJoinIR→MIR 側での Method/Call 意味論実装Phase 34-6 への準備)

ガードレール遵守

  • Phase 34 frontend テスト専用(既定経路不変)
  • JoinIR = PHI 生成器の原則維持
  • 未対応パターンは panictiny テスト専用で合理的)

次のステップPhase 34-6 以降)

  • Phase 34-6: MethodCall 構造の JoinIR への明示 + JoinIR→MIR 変換での Method/Call 意味論実装

実装ファイル

  • src/mir/join_ir/frontend/ast_lowerer.rs (ExtractCtx + extract_value + リファクタリング、~90 lines 追加)

更新ドキュメント

  • docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md (Phase 34-5 セクション + 実装完了情報)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (34-5.1 〜 34-5.5 完了)

1-00k. Phase 34-6 — MethodCall 構造と本物の substring 意味論(完了 2025-11-27

Phase 34-6 の目的

  • MethodCall 構造を JoinIR に明示的に追加
  • JoinIR→MIR 変換で Method 呼び出し意味論を実装
  • JsonShapeToMap._read_value_from_pair/1 の本物の substring 呼び出しを通す

実装内容

  1. MethodCall 構造追加 (34-6.1)

    • src/mir/join_ir/mod.rsJoinInst::MethodCall バリアント追加
    • 構造: { dst, receiver, method, args }
    • コメント: "Phase 34-6: メソッド呼び出し構造。意味論は JoinIR→MIR ブリッジで実装"
  2. extract_value 更新 (34-6.2)

    • ast_lowerer.rs の Method 処理を本物の MethodCall 生成に変更
    • receiver/args を extract_value で再帰的に処理
    • ダミー Const(0) → 本物の MethodCall 構造
  3. JoinIR→MIR 変換実装 (34-6.3)

    • join_ir_vm_bridge.rs に MethodCall → BoxCall 変換追加
    • join_ir/json.rs に MethodCall JSON シリアライゼーション追加
    • join_ir_runner.rs に MethodCall 未対応エラー追加JoinIR Runner は使用しない)
  4. テスト更新 (34-6.4)

    • フィクスチャ更新: Int 10/20 → 本物の substring 呼び出し
    • テスト更新: run_joinir_functionrun_joinir_via_vmJoinIR→MIR→VM ブリッジ)
    • 検証: v="hello", at=3 → "hel" / v="world", at=0 → "world"
    • cond 処理修正: ValueId(0) ハードコード → extract_value で取得
  5. ドキュメント更新 (34-6.5)

    • README/TASKS/CURRENT_TASK 更新

成果

  • テスト全通過1 passed; 0 failed
    • joinir_frontend_json_shape_read_value_ab_test: 本物の substring 呼び出し成功
  • MethodCall 構造: JoinIR で Method 呼び出しを明示的に表現
  • 意味論分離: JoinIR = 構造 SSOT、JoinIR→MIR = 意味論実装
  • VM 実行: 既存の StringBox.substring が正しく呼ばれる

技術的意義

  • 設計原則確立: JoinIR は構造のみ保持、意味論は MIR レベルで実装
  • Phase 33-10 原則との整合性: "JoinIR = PHI 生成器" と同じ原則を Method にも適用
  • 拡張性: 今後の Method 種類追加が容易MethodCall → BoxCall/Call 変換の1箇所で対応

修正ファイル

  • src/mir/join_ir/mod.rs (MethodCall バリアント +8 lines)
  • src/mir/join_ir/frontend/ast_lowerer.rs (Method 処理 +37 lines, cond 処理修正)
  • src/mir/join_ir_vm_bridge.rs (MethodCall → BoxCall 変換 +12 lines, dst 型修正)
  • src/mir/join_ir/json.rs (MethodCall JSON +16 lines)
  • src/mir/join_ir_runner.rs (MethodCall 未対応 +7 lines)
  • src/tests/joinir_frontend_if_select.rs (import 更新, run_joinir_via_vm 使用)
  • docs/.../fixtures/json_shape_read_value.program.json (本物の substring 構造)

更新ドキュメント

  • docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md (Phase 34-6 セクション)
  • docs/private/roadmap2/phases/phase-34-joinir-frontend/TASKS.md (34-6.1 〜 34-6.5 完了)

次のステップPhase 34-7 以降)

  • Phase 34-7: Loop/Break/Continue の AST→JoinIR 対応

1-00u. Phase 32 L-4.3a — llvmlite ハーネスでの JoinIR 実験(完了 2025-11-26

目的

  • LLVM 経路で JoinIR が PHI 問題を解決できることを実行レベルで実証
  • Route A (MIR→LLVM) vs Route B (MIR→JoinIR→MIR'→LLVM) の比較検証

実装内容

  1. src/config/env.rsjoinir_llvm_experiment_enabled() 追加
    • NYASH_JOINIR_LLVM_EXPERIMENT=1 で有効化
  2. src/runner/modes/llvm.rs に JoinIR フック追加
    • inject_method_ids の直後で JoinIR 変換を試行
    • Main.skip/1 を JoinIR 経由で変換し、元のモジュールとマージ
    • 戦略: 元の Main.skip/1PHI問題ありを削除 → join_func_0Main.skip/1 にリネーム

テスト結果

  • Route A (MIR→LLVM): PHI error
    PHINode should have one entry for each predecessor of its parent basic block!
      %phi_11 = phi i64 [ %.1, %bb2 ], [ %.1, %bb5 ]
    
  • Route B (MIR→JoinIR→MIR'→LLVM): 成功
    [joinir/llvm] ✅ Merged module (6 functions)
    ✅ LLVM (harness) execution completed (exit=0)
    

次のステップ

  • L-4.3b: ny-llvmc への移行は Phase 40 (LLVM Native Backend) で扱う

1-00w. Phase 32 L-4.3b — ny-llvmc での JoinIR 実験 → Phase 40 に役割移管(完了 2025-11-26

Phase 32 での結論

  • ny-llvmc 側のコード変更は行わず、llvmlite ハーネス経由の JoinIR 実験L-4.3a)まで完了。
  • 実証済み: Route B (MIR→JoinIR→MIR'→LLVM) が llvmlite ハーネス経由で動作確認済み。
  • 構造: JoinIR→MIR' 変換は Rust 本体(src/runner/modes/llvm.rsで実施。ny-llvmc は「JoinIR→MIR' 後の MIR JSON」を受け取るだけで、JoinIR を直接理解する必要なし。

Phase 40 への引き継ぎ

  • ny-llvmc 本体の最適化・native backend 化と併せて、JoinIR 経路の統合を行う。
  • 現時点では「上流nyash 本体)で JoinIR→MIR' 変換を済ませ、ny-llvmc は llvmlite ハーネスを呼ぶだけ」という構造を維持。

使用方法

env NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \
    NYASH_DISABLE_PLUGINS=1 NYASH_LLVM_USE_HARNESS=1 \
    NYASH_JOINIR_EXPERIMENT=1 NYASH_JOINIR_LLVM_EXPERIMENT=1 \
    ./target/release/hakorune --backend llvm apps/tests/minimal_ssa_skip_ws.hako

成果: JoinIR が LLVM 経路でも PHI 問題を設計的に解決できることを実証


1-00t. Phase 32 L-3.2 — Medium 優先度 PHI 箱の削除検討(完了 2025-11-26

目的

  • Medium 優先度の PHI 箱if_phi.rs / if_body_local_merge.rs / phi_invariants.rs / conservative.rsの削除可能性を調査
  • 各箱の call site を A/B/C に分類A: テスト専用、B: JoinIR 候補、C: 本線必須)

調査結果

  1. if_phi.rs: 9箇所で使用すべてカテゴリ C
    • lifecycle.rs, if_form.rs, phi.rs, conservative.rs, loop_builder.rs で MIR Builder の If/Else PHI 生成に必須
  2. if_body_local_merge.rs: phi_builder_box.rs で使用PhiBuilderBox に依存)
  3. phi_invariants.rs: phi_builder_box.rs で検証用として使用PhiBuilderBox に依存)
  4. conservative.rs: phi_merge.rs, phi.rs で MIR Builder の PHI マージに必須(カテゴリ C

結論: Phase 32 時点では削除不可

  • すべての箱が MIR Builder の If/Else PHI 生成で必須(カテゴリ C
  • if_body_local_merge.rs と phi_invariants.rs は PhiBuilderBoxHigh 優先度)に依存
  • JoinIR は Loop 専門で、If PHI はカバーしていない
  • 削除は Phase 33+ で If JoinIR 対応後に再検討

ドキュメント更新

  • PHI_BOX_INVENTORY.md に L-3.2 詳細分析を追記
  • 各箱の call site 分類テーブルと削除不可理由を明文化

1-00v. Phase 31 — LoopToJoinLowerer 統一箱(完了 2025-11-26

目的

  • MIR LoopForm → JoinIR 変換を1つの統一箱に集約
  • 個別手書き lowererskip_ws, trim, append_defs, stage1を LoopToJoinLowerer 経由に移行

実装内容

  1. src/mir/join_ir/lowering/loop_to_join.rs 新規作成
    • LoopToJoinLowerer 構造体
    • lower() メソッド(汎用)
    • lower_minimal_skip_ws_case_a(), lower_minimal_trim_case_a(), lower_minimal_append_defs_case_a(), lower_minimal_stage1_case_a() 専用メソッド
  2. 4つの lowerer を LoopToJoinLowerer 経由に変更
    • skip_ws.rs, funcscanner_trim.rs, funcscanner_append_defs.rs, stage1_using_resolver.rs

成果: ループ→JoinIR変換の単一エントリポイント確立


1-00w. Phase 30 F-3 レガシー削除 — 旧API関数とCaseAContext::new削除完了 2025-11-25

目的

  • F-3.0 で _with_scope パターンに全lowererが移行完了したため、不要になった旧API関数を削除
  • CaseAContext::new() を削除し、from_scope() のみに統一

削除内容

  1. generic_case_a.rs: 旧API関数4個と未使用import削除
    • lower_case_a_loop_to_joinir_for_minimal_skip_ws
    • lower_case_a_loop_to_joinir_for_trim_minimal
    • lower_case_a_loop_to_joinir_for_append_defs_minimal
    • lower_case_a_loop_to_joinir_for_stage1_usingresolver_minimal
    • 未使用import: LoopForm, LoopExitLivenessBox, LoopVarClassBox, MirFunction, MirQuery
  2. loop_scope_shape.rs: CaseAContext::new() 関数約85行削除
    • 未使用import: intake_loop_form, MirFunction
  3. mod.rs: pub use generic_case_a::lower_case_a_loop_to_joinir_for_minimal_skip_ws; 削除
  4. #[allow(dead_code)]除去: 5関数から除去現在使用中のため不要に

成果: ビルド警告ゼロ、コードサイズ削減約150行


1-00x. Phase 30 F-2.0 — PHI 箱インベントリ作成と削除順計画(完了 2025-11-25

目的

  • PHI 関連の箱・モジュールを一覧化
  • 「どの箱をどの順番で消すか」を PHI_BOX_INVENTORY.md に記録
  • コード削除はまだ行わず、設計と棚卸しのみ

成果物

  1. PHI_BOX_INVENTORY.md 作成: docs/private/roadmap2/phases/phase-30-final-joinir-world/
    • 一覧テーブル: 13箱 + 補助構造体11個
    • 削除順ポリシー: 早期/中期/最終の3段階
    • 外部依存箇所: loop_builder.rs, json_v0_bridge, join_ir/lowering
  2. TASKS.md 更新: F-2.0 完了、F-2.1〜F-2.3 再整理

削除順ポリシー要約:

  1. 早期削除 (F-2.1): HeaderPhiBuilder / ExitPhiBuilder / BodyLocalPhiBuilder / LoopPhiManager
    • 外部呼び出しがテストのみ、JoinIR で完全代替済み
  2. 中期削除 (F-2.2): PhiBuilderBox / LoopSnapshotMerge / if_phi 等
    • F-3/F-4 完了後に削除
  3. 最終削除 (F-2.3): LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox
    • LoopScopeShape 完全移行後に削除

次手: 早期削除候補とテスト専用箱は削除済み。残りの中期〜最終候補は Phase 32phase-32-joinir-complete-migration)で扱う。


1-00y. Phase 30 F-3.0 — skip_ws で LoopScopeShape 実データ運用開始(完了 2025-11-25

目的

  • LoopScopeShape を lowering で実データ運用に切り替えるskip_ws を最初のケースとして)
  • _with_scope + *_core パターンを確立し、他の lowerertrim/append_defs/Stage-1に展開する準備

成果物

  1. generic_case_a.rs 更新:
    • lower_case_a_skip_ws_with_scope(scope: LoopScopeShape) 新関数追加
    • lower_case_a_skip_ws_core(ctx: &CaseAContext) 共通ロジック抽出
    • 既存の lower_case_a_loop_to_joinir_for_minimal_skip_ws*_core に委譲する薄いラッパーに
  2. CaseAContext::from_scope() API: LoopScopeShape を直接受け取り、CaseAContext を構築
  3. コード品質向上:
    • 未使用インポート削除BinaryOperator, VarId
    • Phase 30 準備コードに #[allow(dead_code)] 追加
    • visibility 修正(pubpub(crate))で警告ゼロ達成

確立されたパターン:

LoopScopeShape → CaseAContext::from_scope() → lower_case_a_X_core() → JoinModule

次手: trim / append_defs / Stage-1 minimal に同じパターンを広げていく


1-00z. Phase 30 F-1/F-3/F-4.4 準備調査 — generic_case_a 本線化準備(完了 2025-11-25, Phase 32 view 切り替え継続中)

目的

  • Task A: 各 lowerer ファイルの Case A 判定フックと generic_case_a 呼び出し状況を棚卸し
  • Task B: VM runner のハードコード分岐の縮退計画を TASKS.md F-4.4 に追記
  • Task C: 本セクションとして CURRENT_TASK.md に橋渡しを記録

調査結果: Lowerer ファイルの Case A 対応状況2025-11-25 更新)

ファイル generic_case_a 呼び出し LoopScopeShape 使用 状態
skip_ws.rs lower_case_a_skip_ws_with_scope _with_scope 配線済み F-3.0 完了
funcscanner_trim.rs lower_case_a_trim_with_scope _with_scope 配線済み F-3.0.3 完了
funcscanner_append_defs.rs lower_case_a_append_defs_with_scope _with_scope 配線済み F-3.0.4 完了
stage1_using_resolver.rs lower_case_a_stage1_usingresolver_with_scope _with_scope 配線済み F-3.0.5 完了
stageb_body.rs (プレースホルダのみ) 未実装
stageb_funcscanner.rs (プレースホルダのみ) 未実装

発見事項

  1. 全ファイルで NYASH_JOINIR_LOWER_GENERIC 環境変数トグル + is_simple_case_a_loop() で Case A 判定
  2. skip_ws / trim / append_defs / Stage-1 の4箇所で LoopScopeShape 実データ運用開始F-3.0.23.0.5 完了)
  3. CaseAContext::from_scope() API 確立 — LoopScopeShape を直接受け取り
  4. stageb_body / stageb_funcscanner は generic_case_a 実装がない(プレースホルダのみ)

次手F-3/F-4.4 の継続)

  • F-3.0.2: skip_ws で _with_scope パターン確立 → 完了
  • F-3.0.3: trim 用 _with_scope 実装と呼び出し切り替え → 完了 (2025-11-25)
  • F-3.0.4: append_defs 用 _with_scope 実装と切り替え → 完了 (2025-11-25)
  • F-3.0.5: Stage-1 minimal 用 _with_scope 実装と切り替え → 完了 (2025-11-25)
  • F-3.0.6:必要ならStageB minimal 用 _with_scope
  • F-4.4 方向: VM runner の関数名分岐約90行を generic_case_all 完成後に縮退
  • 縮退計画詳細: docs/private/roadmap2/phases/phase-30-final-joinir-world/TASKS.md F-4.4 に記録済み

補足Phase 32 での追記):

  • Phase 32 Step 3-B で LoopScopeShape::from_existing_boxes_legacy が LoopShape の view (LoopRegion / LoopControlShape / ExitEdge) 経由に切り替わった。
  • Phase 32 Step 3-C で LoopToJoinLowerer 側も minimal 4 本skip_ws / trim / append_defs / Stage1 minimalについて LoopRegion/LoopControlShape view を使用するよう統一済み。以降の JoinIR 汎用化L-1.x, L-2.xはこの view ベース API を前提に進める。

1-00c. Phase 32 L-1/L-2 — JoinIR 汎用化と Stage-1/Stage-B Bridge 進捗2025-11-26 更新)

目的

  • Phase 30〜31 で整えた LoopToJoinLowerer / LoopScopeShape / JoinIR VM Bridge を、「minimal 4 本」から 本線Stage1 / StageB / selfhostラインに広げていくための足場を Phase 32 で固める。
  • CaseA 汎用ループを構造ベースで検出し、JoinIR lowering → JoinIR→VM Bridge までを一貫して扱える状態に近づける。

対応フェーズ

  • Phase 32 L-1.x: LoopToJoinLowerer 汎用化CaseA 拡張)
  • Phase 32 L-2.1: Stage1 UsingResolver 本線ループの JoinIR 化
  • Phase 32 L-2.2 Step-1/2: StageB FuncScanner / BodyExtractor の JoinIR loweringVM Bridge への配線

成果物L-1: LoopToJoinLowerer 汎用化)

  1. is_supported_case_a_loop_view 構造ベース化

    • LoopShape::to_region_view() / to_control_view() / to_exit_edges() で LoopRegion / LoopControlShape / ExitEdge view を取得し、CaseA 判定を view ベースに移行。
    • 判定ロジック:
      • 単一出口(control.exits.len() == 1)であること。
      • header の succ が 2 本while(cond) 相当)であること。
      • pinned/carriers が空でないこと(実質的に状態を運ぶループに限定)。
    • is_supported_case_a_loop はレガシーとして温存しつつ、実際の判定は *_view 側に集約。
  2. 汎用 CaseA フラグ NYASH_JOINIR_LOWER_GENERIC 導入

    • 既定: OFFminimal 4 本: skip_ws / trim / append_defs / Stage1 minimal のみ LoopToJoinLowerer 対象)。
    • NYASH_JOINIR_LOWER_GENERIC=1 のとき:
      • 関数名フィルタを外し、「構造チェックを満たすループ全般」を CaseA 候補として扱う。
      • LoopToJoinLowerer::lower() 内で構造条件+環境変数を見て汎用パスを有効化。
  3. minimal 専用メソッドの整理

    • lower_minimal_*_case_alower_case_a_for_* にリネームし、「CaseA 汎用 lowerer の薄いラッパ」として役割を明示。
    • 呼び出し元skip_ws / trim / append_defs / Stage1 minimalをすべて新名称に統一。
  4. テスト/確認

    • joinir_runner_standalone_skip_ws / joinir_runner_standalone_trim / joinir_vm_bridge_trim_* / JSON v0 スナップショット系テストは全て PASS。
    • Stage1 / StageB については、NYASH_JOINIR_LOWER_GENERIC 有効時も lowering 自体は通ることを確認(意味論は簡略版のままなので VM 実行はまだ有効化しない)。
  5. ExitGroup ベースの Case-A 判定 refinementL-1.4 完了 2025-11-26

    • src/mir/control_form.rsExitGroup { target, edges, has_break }ExitAnalysis { loop_exit_groups, nonlocal_exits } を追加し、ExitEdge の生配列から「出口ブロック単位のグループ」と「非局所 exitReturn/Throw 等)」を切り出すビューを実装。
    • analyze_exits(exits: &[ExitEdge]) -> ExitAnalysis で:
      • loop_exit_groups: ループ本体からループ外の同じ after-block へ出る出口グループExitKind::ConditionFalse / Break のみ)
      • nonlocal_exits: ExitKind::Return / Throw / outer break など非局所 exit に分類。
    • loop_to_join.rsis_supported_case_a_loop_view を ExitAnalysis ベースに差し替え:
      • 旧ロジック: control.exits.len() == 1 で単一 ExitEdge を要求していたため、複雑条件 break短絡 && でブロックが分かれる)を Case-A から外していた。
      • 新ロジック: exit_analysis.loop_exit_groups.len() == 1(出口ブロック集合が 1 種類)かつ exit_analysis.nonlocal_exits.is_empty()(非局所 exit なし)であれば Case-A とみなすように変更。
    • 効果:
      • if c != ' ' && c != '\t' && c != '\n' { break } のような複雑条件 break を含むループでも、出口ブロックが 1 種類であれば Case-A として LoopToJoinLowerer/JoinIR lowering の対象にできるようになった。
      • Stage1 JoinIR VM bridge テスト 4 件(joinir_vm_bridge_stage1_*)は全て PASS を維持。
      • skip_ws 実物については、JoinIR 経由の PHI 形状は引き続き正しく表現できているが、VM 実行側では StepBudgetExceeded(既知の別問題)が残っているため、挙動は L-4/L-5VM / progress carrier まわり)のフェーズで継続調査する。

成果物L-2.1: Stage1 UsingResolver 本線ループ)

  1. 本線ループを LoopToJoinLowerer 対象に昇格
    • 対象: Stage1UsingResolverBox.resolve_for_source/5 内の entries ループ(lang/src/compiler/entry/using_resolver_box.hako:46-91)。
    • CFG から construct_simple_while_loopform(entry_is_preheader=false, has_break=false) で LoopForm を構築し、CaseA 条件while(i < n), break なし, 単一出口)を満たすことを確認。
  2. MIR-based lowering hook
    • lower_from_mir() 内で:
      • 軽量 CFG チェックentry に Const 0、ArrayBox.length の存在など)を通過した場合に LoopForm を構築。
      • LoopToJoinLowerer::lower_case_a_for_stage1_resolver を呼び、成功時は LoopToJoinLowerer 由来の JoinIR を優先採用。
      • 失敗時/非対応時は build_stage1_using_resolver_joinir()handwritten JoinIRにフォールバック。
  3. JoinIR lowering の現状(簡略版)
    • build_stage1_using_resolver_joinir() は Phase 27.12 の最小版のまま:
      • entries.get(i)prefix + entry の文字列連結に限定。
      • should_emit や path 解決など UsingResolver 本来のロジックはまだ JoinIR 側に持ち込んでいない。
    • Phase 32 では「CaseA 構造PHI 形状が JoinIR 側で正しく表現できること」を優先し、意味論フル移植は L-2.x / Phase 29 L-3.x で段階的に進める前提。
  4. テスト
    • JSON スナップショット: 8/8 PASSjoinir_json_v0_stage1_usingresolver_min_matches_fixture 含む)。
    • VM Bridge: Stage1 は JoinIR lowering 検証のみ(後述の VM bridge dispatch にて実行は VM フォールバック)。

成果物L-2.2 Step-1〜3: StageB FuncScanner / BodyExtractor

  1. Step-1 — StageB lowering を LoopToJoinLowerer 経由に統一commit 9d769e92
    • 対象関数:
      • StageBBodyExtractorBox.build_body_src/2
      • StageBFuncScannerBox.scan_all_boxes/1
    • 既存の StageB ループを CaseA 前提で LoopForm + LoopScopeShape view に載せ、LoopToJoinLowerer から JoinIR を生成する経路を追加。
    • もともとの handwritten JoinIR がある場合も、Shared Builder Patternlower_from_mir / lower_handwrittenbuild_*_joinir)に揃える方針は Stage1 と同じ。
  2. Step-2 — StageB を VM bridge dispatch に追加commit e61e7a2b
    • src/mir/join_ir_vm_bridge_dispatch.rs に StageB 向けエントリを追加:
      • try_run_stageb_bodyStageBBodyExtractorBox.build_body_src/2 用)
      • try_run_stageb_funcscannerStageBFuncScannerBox.scan_all_boxes/1 用)
    • 挙動:
      • JoinIR lowering を試みる(lower_stageb_body_to_joinir / lower_stageb_funcscanner_to_joinir)。
      • JoinIR モジュールが生成できた場合は関数数などをログ出力し、実際の実行は行わず false を返して VM 経路にフォールバック
      • Stage1 UsingResolver と同一パターンJoinIR lowering の健全性検証専用ブリッジ)として運用。
    • テスト:
      • JSON v0 スナップショット: 6/6 PASSStageB 関連を含む)。
      • cargo build: 成功、警告なし。
  3. Step-3 — StageB JoinIR→MIR 構造テスト追加commit 1eea4045
    • src/mir/join_ir_vm_bridge.rsconvert_joinir_to_mirpub(crate) 化し、テストから直接呼び出し可能に。
    • StageB 向けの構造テストを追加(ファイル名: src/tests/joinir_json_min.rs 内):
      • joinir_stageb_body_structure_test
        • StageBBodyExtractorBox.build_body_src/2 について:
          • Route A: 既存パイプラインで MirModuleBaselineを生成。
          • Route B: lower_stageb_body_to_joinirconvert_joinir_to_mir で JoinIR→MIR Bridge の結果を取得。
          • 両者とも対象関数が存在し、JoinIR 経由の MIR でも Block 数が 1 以上であることを確認。
          • JoinIR lowering と JoinIR→MIR 変換がエラーなく通ることを確認。
      • joinir_stageb_funcscanner_structure_test
        • StageBFuncScannerBox.scan_all_boxes/1 について同様のチェックを実施。
    • 現時点の検証範囲:
      • handwritten JoinIR→MIR Bridge の健全性確認 が主目的(build_stageb_*_joinir() 由来)。
      • まだ intake_loop_form が StageB ループ構造に非対応のため、「MIR→JoinIR roundtrip」の完全 A/B ではなく、「handwritten JoinIR を VM Bridge で安全に MIR に落とせているか」をテストする位置付け。

VM Bridge 対応関数一覧Phase 32 時点のまとめ)

  • Main.skip/1:
    • JoinIR lowering + JoinIR→MIR→VM 実行まで対応済み。
    • NYASH_JOINIR_EXPERIMENT=1 / NYASH_JOINIR_VM_BRIDGE=1 で Route B を有効化trim と並ぶ最初期の A/B テスト対象)。
  • FuncScannerBox.trim/1:
    • JoinIR lowering + JoinIR→VM 実行まで対応済み。
    • NYASH_JOINIR_INPUT で入力文字列を差し替え可能(未指定時 " abc ")。
  • Stage1UsingResolverBox.resolve_for_source/5:
    • JoinIR lowering 検証のみ。ArrayBox / MapBox の引数を JoinValue::BoxRef として橋渡しする部分がまだ未実装のため、実行は VM にフォールバックする設計。
  • StageBBodyExtractorBox.build_body_src/2:
    • NEW: JoinIR lowering 検証のみ。Stage1 と同様、JoinIR モジュール生成に成功しても実行は VM 経路に任せる。
  • StageBFuncScannerBox.scan_all_boxes/1:
    • NEW: JoinIR lowering 検証のみ。同上。

制限と今後のタスク(忘れないためのメモ)

  • JoinIR lowering の多くは Phase 27.x 時点の「簡略版」のままで、本番ロジックshould_emit / path 解決 / JSON マージなど)はまだ .hako 側 MIR に残っている。
    • Phase 32 では「CaseA 構造PHI 形状の正規化」を優先し、意味論フル移植は L-2.2 Step-3〜5 / L-2.3 / Phase 29 L-3.x で段階的に進める。
  • Stage1 / StageB について JoinIR→VM 実行まで有効化するには:
    • JoinValue::BoxRef と VM 側 Box インスタンスの橋渡し(引数マーシャリング)を明示的に実装する必要あり。
    • JoinIR lowering を「簡略版」から「VM Route A と意味論一致する版」に引き上げ、A/B テストJSON / MIR / JoinIR / VM の比較)を整備する必要がある。
  • Phase 32 TASKS のステータス2025-11-26 時点):
    • L-1.1〜L-1.3: 完了LoopToJoinLowerer 汎用化の足場は整った)。
    • L-2.1: 完了Stage1 UsingResolver 本線ループの JoinIR lowering + スナップショットテスト)。
    • L-2.2: 全 Step 完了StageB lowering 統一 + VM bridge dispatch + JoinIR→MIR 構造テスト + ドキュメント更新 + 安定化確認)
      • Step-3: convert_joinir_to_mir を pub(crate) 化、Stage-B 構造テスト2本追加 (commit 1eea4045)
      • Step-4: Phase 32 README / env リファレンスを更新し、StageB の JoinIR 利用範囲loweringBridgeのみと各トグルの役割を明文化
      • Step-5: NYASH_JOINIR_LOWER_GENERIC=1 時の StageB lowering/bridge 安定性確認済み18 tests PASS、ガード追加不要。StageB 実行は依然として VM Route A
    • L-2.3: 完了2025-11-26 — Route A vs Route B の A/B 比較で JoinIR が PHI 問題を設計的に解決していることを実行レベルで実証
      • 最小ケース minimal_ssa_skip_ws.hakoMain.skip(" abc") を実行
      • Route AVM 直接): 結果 0 PHI バグで値消失)
      • Route BJoinIR: 結果 Int(3) (正解)
    • L-3.1 Step-1: 完了2025-11-26 — PHI レガシー箱の call site 分析
      • PHI_BOX_INVENTORY.md を Phase 32 向けに更新(削除優先度 High/Medium/Low 分類)
      • PhiBuilderBox / PhiInputCollector / LoopSnapshotMergeBox の call site を A/B/C 分類
      • 結果: カテゴリ Aテスト専用はコメント参照 1 箇所のみ
    • L-3.1 Step-2: 完了2025-11-26 — PHI 経路削除可能性分析
      • loopform_builder.rs: PhiInputCollector × 3, LoopSnapshotMergeBox × 1 → 非 JoinIR 経路で必須(削除不可)
      • json_v0_bridge/loop_.rs: PhiInputCollector × 1 → selfhost 経路で必須(削除不可)
      • 結論: JoinIR は既に PHI 箱をバイパス。削除は L-4JoinIR 本線化)完了後
    • L-3.2 / L-3.3: これからJoinIR 本線化後に PHI 箱削除)。
    • L-4.1/L-4.2: 完了2025-11-26 — VM Bridge テーブル化 & 本線明示
      • join_ir_vm_bridge_dispatch.rs に Descriptor テーブル(JOINIR_TARGETS)を導入し、関数名→役割のマッピングを一元管理。
      • JoinIrBridgeKind 列挙型: ExecJoinIR→VM 実行まで対応)と LowerOnlylowering 検証のみ、実行は VM Route Aを明確に区別。
      • 対象関数ごとの状態:
        関数 Kind デフォルト有効 状態
        Main.skip/1 Exec PHI canary のため本線化しないenv 必須)
        FuncScannerBox.trim/1 Exec 唯一の本線昇格候補A/B 実証済み)
        Stage1UsingResolverBox.resolve_for_source/5 LowerOnly 構造検証のみ
        StageBBodyExtractorBox.build_body_src/2 LowerOnly 構造検証のみ
        StageBFuncScannerBox.scan_all_boxes/1 LowerOnly 構造検証のみ
      • 結論: 現状は trim だけが「JoinIR 実行まで含めて安全」として昇格候補。skip は PHI canary として残し、Stage-1/Stage-B は ArrayBox/MapBox 引数の JoinValue 対応が揃うまで LowerOnly。
    • L-4.3: これからLLVM ライン JoinIR 実験: まず llvmlite ハーネスで JoinIR→MIR'→LLVM の最小ケース 1 本を通し、その後 llvmc 側にミラーする計画。いずれも dev トグル前提の実験扱い)。

1-00a. Phase 30 F-1.4 — LoopScopeShape API 確定(完了 2025-11-25

目的

  • LoopScopeShape を「ループ変数スコープ情報の唯一のソース」に近づける
  • Block IDs (header/body/latch/exit) を LoopForm から伝播
  • CaseAContext::from_scope() で LoopScopeShape 直接受け取りAPI追加
  • ユニットテスト追加8テスト全PASS

成果物

  1. LoopScopeShape 更新: src/mir/join_ir/lowering/loop_scope_shape.rs
    • Block IDs フィールド追加
    • from_existing_boxes() シグネチャ更新LoopForm受け取り
    • CaseAContext::from_scope() 新メソッド追加
  2. テスト追加: 4本の新規テスト合計8テスト
    • test_from_scope_validation_header_eq_exit
    • test_block_ids_preserved
    • test_deterministic_order
    • test_needs_phi_consistency
  3. ドキュメント更新: docs/private/roadmap2/phases/phase-30-final-joinir-world/TASKS.md

1-00b. Phase 29 小タスク — JoinIR/Stage-1 環境変数棚卸し(完了 2025-11-25

目的

  • JoinIR/Stage-1 関連の環境変数を棚卸し・整理
  • 実装の統一確認env helper経由
  • ドキュメント更新

成果物

  1. ENV_INVENTORY.md 作成: docs/private/roadmap2/phases/phase-29-longterm-joinir-full/ENV_INVENTORY.md

    • JoinIR 環境変数 6個NYASH_JOINIR_*
    • Stage-1 環境変数Primary 7個 + Aliases 16個
    • 分類: user-facing / dev-only / internal / alias
  2. 実装統一確認

    • JoinIR: env_flag_is_1() ヘルパー経由で統一済み9ファイル
    • Stage-1: src/config/env/stage1.rs SSOT モジュール経由で統一済み
  3. ドキュメント更新: docs/reference/environment-variables.md

    • JoinIR セクション追加6変数 + 使用例)

発見事項

  • NYASH_RUN_JOINIR_MINIMAL は既に削除済みgood
  • Stage-1 alias群は警告付きで互換維持warn_alias_once
  • テストファイルの直接env var参照はスキップガード用途で許容

1-01. Phase 26-E — PhiBuilderBox SSOT統一化完了 2025-11-22

目的

  • PHI生成ロジックを単一責務箱PhiBuilderBoxに集約
  • If/Loop両対応の統一インターフェース提供
  • Conservative戦略 + BTreeSet/BTreeMap で決定性向上

🎯 Phase 26-E 進捗状況2025-11-22

  • Phase 1: PhiBuilderBox 骨格作成444行、ControlForm対応
  • Phase 2: If PHI生成完全実装Conservative戦略、決定的順序保証
  • Phase 3: PhiBuilderOps委譲実装has-a設計、ChatGPT+Claude合意
  • Phase 4: Legacy削除loop_phi.rs 287行、将来タスク

Phase 2 実装内容2025-11-22完了

  1. PhiBuilderBox作成 (src/mir/phi_core/phi_builder_box.rs, 444行)
    • If PHI生成: generate_if_phis() 完全実装
    • Conservative戦略: void emission 含む完全対応
    • 決定的順序: BTreeSet/BTreeMap で非決定性排除
  2. PhiBuilderOps trait (7メソッド)
    • 最小PHI生成インターフェース
    • テスタビリティ向上(モック可能)
  3. loop_builder.rs 統合 (src/mir/loop_builder.rs)
    • PhiBuilderOps trait 実装Ops構造体
    • If PHI呼び出し箇所統合line 1136-1144

Phase 3 実装内容2025-11-22完了

  1. 設計方針変更: 継承is-a→委譲has-aに変更ChatGPT+Claude合意
    • PhiBuilderOps = 低レベル「PHI命令発行」道具箱
    • LoopFormOps = 高レベル「ループ構造構築」作業場
    • 関係: has-a委譲が正しい設計異なる抽象レベル
  2. LoopBuilder委譲実装 (src/mir/loop_builder.rs, +64行)
    • impl<'a> PhiBuilderOps for LoopBuilder<'a> 個別実装
    • 明示的 trait 修飾で自己再帰回避: <Self as LoopFormOps>::method()
    • HashSet → Vec 変換 + ソート(決定性保証)
    • emit_phi 引数差吸収: set_current_block 経由
  3. 設計文書更新 (src/mir/phi_core/loopform_builder.rs)
    • has-a 設計根拠をコメント追加
    • 継承試行の失敗理由を記録

Phase 3 テスト結果2025-11-22

  • 決定性: 10回実行で一貫した結果20% 成功率は既存 Loop PHI バグによるもの)
  • 退行なし: Phase 26-E 実装前と同じ成功率
  • If PHI 生成: 100% 動作Test 2 で確認済み)
  • テスト詳細:
    • mir_stage1_using_resolver_resolve_with_modules_map_verifies: 2/10 成功20%、既存バグ)
    • mir_stage1_using_resolver_modules_map_continue_break_with_lookup_verifies: 10/10 成功100%

Phase 3 コミット

  • b9a03429: Phase 26-E-2 - PhiBuilderBox If PHI生成完全実装
  • e0be01c1: Phase 26-E-3 - PhiBuilderOps委譲実装has-a設計

削減見込み

  • Phase 2: -80行If側重複削除
  • Phase 4: -287行loop_phi.rs Legacy削除
  • 合計: -367行純削減

次のステップPhase 4

  • loop_phi.rs Legacy削除287行
  • Loop PHI バグ調査20% 成功率問題)
  • 100% 決定的テスト達成

関連ファイル


1-00. Phase 21.7 — Static Box Methodization完了 2025-11-21, 既定ON に移行)

目的

  • static box 内の呼び出しを NamingBox/Method まわりで一貫して扱えるようにする。
  • Global("BoxName.method/arity") を Method{receiver = static singleton} に寄せる(トグル制御)。

🎯 Phase 21.7++ 計画2025-11-22 全フェーズ完了!🎊

  • NamingBox SSOT 統一化チェックリスト: phase-21.7-naming-ssot-checklist.md
  • StringUtils using 解決バグ修正2025-11-22, commit f4ae1445を踏まえた改善計画
  • Phase 0観測ライン: Silent Failure 根絶完了commit 63012932
  • Phase 1基盤整備: StaticMethodId SSOT 基盤確立commit 96c1345e
  • Phase 2VM統一: VM 名前解決 SSOT 準拠commit 1b413da5
  • Phase 3全体統一: Builder 側統一、素手 split 根絶commit c8ad1dae
  • Phase 4ドキュメント: README・トラブルシューティングガイド整備commit 806e4d72
  • 累計工数: 10時間進捗率: 50-67%

Phase 0-4 実装内容2025-11-22 全完了)

  1. Phase 0: 観測ライン緊急構築 (commit 63012932)

    • TOML parse エラー即座表示pipeline.rs
    • VM 関数ルックアップ「Did you mean?」提案global.rs
    • using not found 詳細化strip.rs
    • 効果: Silent Failure 根絶、デバッグ時間が時間→分に短縮
  2. Phase 1: StaticMethodId SSOT 基盤 (commit 96c1345e)

    • StaticMethodId 構造体導入naming.rs:86-248
    • parse/format/with_arity ヘルパー実装
    • 包括的テスト13ケース全PASS
    • 効果: 関数名パース/フォーマット一元化、型安全化
  3. Phase 2: VM 統一 (commit 1b413da5)

    • global.rs を StaticMethodId ベース化
    • デバッグログ強化NYASH_DEBUG_FUNCTION_LOOKUP=1
    • テスト全通過349 passed, 退行なし)
    • 効果: arity バグ根治、Hotfix 卒業
  4. Phase 3: 全体統一 (commit c8ad1dae)

    • unified_emitter.rs の methodization を StaticMethodId 化
    • known.rs の split_once 全置き換え2箇所
    • 効果: 素手 split 根絶、Builder 側完全統一、コード50%削減
  5. Phase 4: ドキュメント整備 (commit 806e4d72)

    • Phase 21.7 README に完了セクション追加60行
    • トラブルシューティングガイド作成200+行、新規)
    • チェックリスト進捗サマリー更新
    • 効果: 再発防止、開発者オンボーディング改善

1-00k. Phase 36 — PHI Box Midrange ReductionLoopSnapshotMergeBox & PhiBuilderBox完了 2025-11-29

目的

  • Phase 35 での HIGH 安全度削除(if_body_local_merge.rs / phi_invariants.rs 計 430 行に続き、MEDIUM 安全度帯の PHI 箱のうち「Loop 側のみ」を縮退させて、JoinIR FrontendPhase 34 LoopScopeShape を PHI 生成 SSOT とする流れをさらに強化する。
  • 行数削減だけでなく、「どの箱がどの責務を持つか」を明文化し、将来の Phase 37+If 側 PHI 削減 / Classifier Trio リファクタ)への足場を固める。

実装内容サマリ

  1. LoopSnapshotMergeBox の縮退dead code 100% 削除+純粋静的化)

    • 対象: src/mir/phi_core/loop_snapshot_merge.rs(元 470 行)。
    • 完了内容:
      • 未使用メソッド merge_continue_for_header() とそのテスト群を削除(本番 callsite 0
      • PhiInputCollector 側に移譲済みの optimize_same_value() / sanitize_inputs() とテストを削除。
      • 未使用フィールド header_phi_inputs / exit_phi_inputsnew/Default 実装を削除し、状態を一切持たない構造に整理。
      • 本質ロジック merge_exit_with_classification() のみを残し、「Exit PHI マージの名前空間」としての静的ユーティリティに縮退。
    • 結果:
      • 行数: 470 → 363 行107 行削減, 22.8% reduction
      • Exit PHI Option CPHI pred mismatch 防止)ロジックは完全温存。
      • Phase 36 専用テスト 3 本を追加し、Case A/B/Option C を包括的にカバー。
  2. PhiBuilderBox の責務マッピングLoop/If/Common の見える化)

    • 対象: src/mir/phi_core/phi_builder_box.rs
    • 実装方針:
      • Loop 側専用の薄いラッパLoopPhiBuilderは作らず、既存の API をそのまま維持。
      • 代わりにファイル先頭と各メソッドに「Responsibility: Loop-only / If-only / Common / Stub」といったマーカーコメントを追加。
    • 主な分類:
      • Loop-only: set_if_context()(ループ内 if の PHI 文脈設定)、generate_loop_phis()(将来の実装ターゲット)。
      • If-only: generate_if_phis(), compute_modified_names_if(), get_conservative_if_values()
      • Common: new(), generate_phis()
    • 効果:
      • PhiBuilderBox が「Loop PHI 本体」ではなく if-in-loop PHI 用の共通箱 であることを明示。
      • Phase 37 以降の If 側 PHI 削減のターゲット範囲がクリアになった。
  3. ドキュメント更新と PHI インベントリ反映

    • docs/private/roadmap2/phases/phase-36-phi-midrange/README.md:
      • 目標 30% に対して実際は 22.8% 削減であること、行数よりも「dead code 全削除+本質ロジック温存」を優先した判断を明文化。
      • LoopSnapshotMergeBox の役割を「Exit PHI マージ専用の静的ユーティリティ」として再定義。
    • docs/private/roadmap2/phases/phase-36-phi-midrange/TASKS.md:
      • 36-1.3/1.4, 36-6.1〜6.5 を含む全タスクを完了にマーク。
    • docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md:
      • LoopSnapshotMergeBox 行に Phase 36 の縮退内容dead code 削除+静的化)を追記し、将来 JoinIR/LoopScopeShape 側へ段階移行する計画を明示。
  4. テスト&リグレッション確認

    • LoopSnapshotMergeBox 単体テスト: 3/3 PASSsimple carrier / body-local internal skip / break-only loop
    • LoopFormBuilder 周辺テスト: 14/14 PASS。
    • Phase 34 JoinIR Frontend テストIf/Loop/Break/Continue: 6/6 PASS。
    • cargo build --release: 警告ゼロで完了。

成果と位置づけ

  • Phase 35-5HIGH 安全度 430 行削除に続き、Phase 36 で LoopSnapshotMergeBox を安全に 22.8% 縮退し、PHI レイヤの責務を「JoinIR + LoopScopeShape 側が SSOT、本レガシー箱は Exit PHI マージ専用の補助ユーティリティ」として再配置できた。
  • PhiBuilderBox については Loop 側からの利用を「if-in-loop PHI 用」として位置づけ直し、実体削減は Phase 37+ の If 側 JoinIR 移行完了後に行う方針を固定した。
  • これにより PHI 関連コードの総削減量は Phase 35-5430 行)+ Phase 36107 行)で 合計 537 行 に到達しつつ、Exit/If PHI の本質ロジックと JoinIR Frontend の安定性は維持されている。

次のステップPhase 37+ の入口メモ)

  • Phase 37: If 側 PHIconservative.rs + if_phi.rs)の削減検討。
    • 前提: Phase 33〜34 で整備した IfSelect/IfMerge lowering と JoinIR Frontend の適用範囲を広げること。
  • Phase 38+: PhiBuilderBox 内部の実体削減Loop 側は完了済み / If 側の join 関数化)。
  • Phase 39: Classifier TrioLoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBoxを LoopScopeShape に吸収するアーキテクチャ作業。

Phase 0-2 以前の実装内容

  1. NamingBox decode 関数追加 (Step 1: commit a13f14ce)

    • decode_static_method(func_name: &str) -> Option<(&str, &str, usize)>
    • is_static_method_name(func_name: &str) -> bool
    • "BoxName.method/arity" 形式をパースして (box_name, method, arity) に分解。
  2. Hotfix 7 修正 (Step 2: commit a13f14ce)

    • unified_emitter.rs の receiver 追加ロジックを修正。
    • StaticCompiler box_kind のメソッドで、static box method (decode可能な名前) の場合は receiver を追加しない。
    • instance method のみ receiver を args の先頭に追加するようガード実装。
  3. Methodization 実装 (Step 3: commit b5cd05c2)

    • builder.rs: static_box_singletons: HashMap<String, ValueId> フィールド追加。
    • unified_emitter.rs: HAKO_MIR_BUILDER_METHODIZE=1 で有効化。
      • Callee::Global(name) を decode して static box method 判定。
      • シングルトンインスタンス (NewBox) をキャッシュ生成。
      • Callee::Method{receiver=singleton} に変換。

動作確認

  • デフォルト (OFF): call_global Calculator.add/2 (既存挙動維持)
  • トグル (ON): new Calculator() → call %singleton.add(...) (methodization)
  • RC=0 両モード動作確認済み: apps/tests/phase217_methodize_test.hako

環境変数

  • HAKO_MIR_BUILDER_METHODIZE=0/1: methodization 制御。既定ON未設定 or "1")、"0" のときのみ無効化。
  • NYASH_METHODIZE_TRACE=1: Global→Method 変換ログ出力

次タスクPhase 21.7++ Phase 3-410-15時間見込み

  • Phase 3: 全体統一
    • MIR Builder 側を StaticMethodId 統一builder/calls/unified_emitter.rs 等)
    • 素手 split 置き換え(rg '"\."' --type rust src/mir/builder/
    • 100-200 行削減見込み
  • Phase 4: ドキュメント化
    • SSOT 設計書更新
    • 移行ガイド作成
    • チームレビュー
  • 長期: NamingBox/UnifiedCallEmitter/VM の 3 点で「名前と arity の SSOT」完全統一。

1-00j. Phase 37 If-Side PHI Design Phase完了 2025-11-28

日付: 2025-11-28

達成: If側PHI完全設計書作成削除前の地図完成

設計内容

if_phi.rs完全棚卸し:

  • パターン分類: simple/local/nested/if-in-loop/composite
  • 12重要呼び出し箇所特定: lifecycle.rs (2), if_form.rs (2), phi.rs (2), loop_builder.rs (3), conservative.rs (1), phi_merge.rs (2)
  • 難易度評価: LOW/MEDIUM/HIGH per callsite

conservative.rs責務分解:

  • JoinIR移行済み: Select パターン用最小エッセンスを JoinIR Verifier に移譲済みPhase 33-3.2
  • 未移行(本質的): 複雑パターン解析Conservative value propagation, void emission, predecessor fallback
  • 移行境界明確化: tiny/simple vs complex patterns

JoinIRカバレッジマップ:

  • Phase 33成果: IfSelect/IfMergesimple/local/2-3変数
  • Phase 34成果: Tiny Frontend cases (AST→JoinIR→MIR→VM full path)
  • ギャップ分析: カバー済み vs 未カバーStage-1/B完全実装待ち

3レベル削除基準:

  • Level 1 (Phase 38, LOW risk): tiny/pure IfIfSelectTest.* 全PASS via JoinIR Frontend

    • 削減量: 68行 (14% of 483 lines)
    • 候補: merge_modified_with_control (33行, 未使用), extract_assigned_var (35行)
    • 前提: Phase 33 IfSelect実装, Phase 34 Frontend実装
  • Level 2 (Phase 39, MEDIUM risk): Stage-1/B代表関数1-2個A/Bテスト

    • 削減量: 115行 (24% of 483 lines, 38% cumulative)
    • 候補: collect_assigned_vars (32行), compute_modified_names (26行), merge_with_reset_at_merge_with (27行), conservative.rs struct inline (30行)
    • 前提: ⚠️ Stage-1/B代表関数実装, ⚠️ Loop+If JoinIR統合, ⚠️ conservative.rs移行設計
  • Level 3 (Phase 40+, HIGH risk): Stage-1/B/selfhost大半JoinIR依存完全移行

    • 削減量: 300行 total (62% of 483 lines, 94% cumulative)
    • 候補: merge_modified_at_merge_with (63行), PhiMergeOps trait (14行), get_conservative_values (30行), conservative.rs完全削除 (70行)
    • 前提: PhiMergeOps trait代替, 完全IfMerge void handling, Stage-1/B/selfhost大半カバー

技術的成果

  1. docs-only完遂: Rustコード変更ゼロ設計のみ
  2. 証拠ベース設計: 12箇所特定・難易度評価で削除可能性判断
  3. 段階的削減計画: Phase 38/39/40+への明確なロードマップ

成果物

  • if_phi_responsibility_table.md: 10関数分類・12呼び出し箇所・難易度評価
  • conservative_responsibility_table.md: JoinIR移行済み vs 未移行境界
  • joinir_coverage_map.md: Phase 33-34カバレッジ vs if_phi/conservativeマッピング
  • deletion_sequence_plan.md: Phase 38/39/40+削減計画
  • deliverables_checklist.md: 品質確認完了
  • PHI_BOX_INVENTORY.md: Phase 37リンク追加、frontend_covered詳細コメント追加

Rustコード変更

  • ゼロdocs-only、コメント追加なし

次のステップ (Phase 38+)

  • Phase 38: Level 1達成 → if_phi.rs Level 1関数削除~68行、14%削減、LOW risk
  • Phase 39: Level 2達成 → if_phi.rs Level 2関数削除 + conservative.rs縮退~115行、24%削減、MEDIUM risk
  • Phase 40+: Level 3達成 → conservative.rs完全削除~300行total、62%削減、HIGH risk

Phase 37設計完了: 削除前の完全地図作成達成 Phase 38+削減ポテンシャル: ~483行Level 1+2+3合計、if_phi.rs + conservative.rs

Phase 35-37累計削減量: 537行 (Phase 35: 430行, Phase 36: 107行) + Phase 37設計完了Phase 38+で483行削減予定


1-02. Phase 27.4-A — JoinIR Header φ 統合LoopHeaderShape 導入、2025-11-23 完了)

目的

  • HeaderPhiBuilder が担っていた「loop header φPinned/Carrier の合流」の意味を、JoinIR 側に構造として持ち上げる足場を作る。
  • Rust 側の header φ 挙動は一切変えず、本線 MIR/LoopForm→VM を壊さないまま JoinIR 経路の設計を進める。

やったこと

  • src/mir/join_ir.rsLoopHeaderShape { pinned, carriers } を追加し、skip_ws / FuncScanner.trim のループについて:
    • skip_ws: Pinned = [s, n], Carrier = [i]loop_step(s, i, n) の設計をコメント付きで固定)。
    • trim : Pinned = [str, b], Carrier = [e]loop_step(str, b, e) の設計をコメント付きで固定)。
  • Header φ の意味を「loop_step 引数としてどう表現するか」をコードとコメントで一致させた。
  • src/mir/phi_core/header_phi_builder.rsNYASH_JOINIR_HEADER_EXP=1 フラグチェックを追加(現在はログのみ、挙動は不変)。
  • JoinIR テストまわり:
    • skip_ws / min / trim の JoinIR 型・変換テストを維持しつつ、trim 側は trim_main + loop_step + skip_leading の 3 関数構成にテスト期待を合わせた。
    • LoopHeaderShape 用のミニテストを追加し、「to_loop_step_params() は pinned→carriers 順で返す」という契約を固定。

状態

  • JoinIR 側では Header φ の意味が LoopHeaderShape で表現され、対象ループの loop_step 引数に反映済み。
  • HeaderPhiBuilder は従来挙動のままPhase 27.4-C 以降でトグル付き縮退を予定)。
  • すべての JoinIR テスト 7/7 が PASS、既存本線テストの緑度には影響なし。

1-03. Phase 27.4-C — HeaderPhiBuilder バイパス実験JoinIR 経路限定、2025-11-23 完了)

目的

  • Header φ の意味は JoinIR 側LoopHeaderShapeloop_step 引数に持ち上がったので、JoinIR 実験経路に限って Rust 側 HeaderPhiBuilder をバイパスできるか試す。
  • 本線 MIR/LoopForm→VM の挙動には一切触れず、JoinIR runner テスト専用の縮退ステップとして運用する。

やったこと

  • src/mir/phi_core/header_phi_builder.rs に 2 つのヘルパーを追加:
    • joinir_header_experiment_enabled()NYASH_JOINIR_HEADER_EXP=1 チェック27.4-B で導入)。
    • joinir_header_bypass_enabled()NYASH_JOINIR_EXPERIMENT=1 AND NYASH_JOINIR_HEADER_EXP=1 の両方が ON のとき true。
  • src/mir/loop_builder.rs で HeaderPhiBuilder 利用箇所にバイパスロジックを追加:
    • 現在の関数名が Main.skip/1 または FuncScannerBox.trim/1 のとき、
    • かつ joinir_header_bypass_enabled() が true のときのみ emit_header_phis() をスキップ。
    • NYASH_LOOPFORM_DEBUG=1 時はデバッグログを出す。
  • JoinIR テスト側skip_ws / trimに、「NYASH_JOINIR_HEADER_EXP=1 を併用すると Header φ bypass が有効化される」旨のコメントを追加。
  • docs/private/roadmap2/phases/phase-27-joinir/IMPLEMENTATION_LOG.md に Phase 27.4-C セクションを追加し、対象関数・トグル条件・挙動を記録。
  • phase-27-joinir/TASKS.md で 27.4-C を完了扱いに更新。

状態

  • JoinIR runner 実験時に NYASH_JOINIR_EXPERIMENT=1 NYASH_JOINIR_HEADER_EXP=1 を立てた場合のみ、Main.skip/1 / FuncScannerBox.trim/1 の Header φ がスキップされる。
  • このモードでは VM 実行は使わず、JoinIR runner だけで意味が保たれているかを確認するテストとして運用。
  • 本線 MIR/LoopForm→VM の挙動は、トグル OFF 時には従来どおりHeader φ あり)のまま。

1-04. Phase 27.5 — JoinIR Exit φ 統合設計着手、2025-11-24 現在)

目的

  • ExitPhiBuilder が担っている「exit φbreak/early-exit の合流」の意味を、JoinIR 側の k_exit 呼び出し+引数として表現できるようにする設計フェーズ。
  • Rust 側の ExitPhiBuilder 挙動は変えず、本線 VM を壊さないまま minimal/trim の 2 ケースで Exit φ の意味を整理する。

やったこと(設計メモ反映済み)

  • docs/private/roadmap2/phases/phase-27.5-joinir-exit/README.md を追加し、minimal_ssa_skip_ws と FuncScanner.trim_min の exit 経路を整理。
    • minimal: break 経路は i>=n / ch!=" ", Exit φ は i だけ → JoinIR では k_exit(i) を想定。
    • trim: break 経路は !(e>b) / !is_space, Carrier=e, Pinned=str,b。ExitShape は Option A: [e](第一候補) / Option B: [str,b,e] を比較と記述。
  • docs/private/roadmap2/phases/phase-27.5-joinir-exit/TASKS.md の A-1/A-2 を完了にし、B 以降LoopExitShape 型/コメント追加、JoinIR 変換への反映、テスト/ログ追記)はこれから。

次の一手

  • LoopExitShape の型 or コメントを JoinIR に追加して、minimal/trim の exit 引数セットを明示。
  • JoinIR 変換の exit 部分に「k_exit で何を合流させるか」のコメントを足し、必要なら命令並びを軽く整える(意味は変えない)。
  • JoinIR テストと IMPLEMENTATION_LOG に Exit φ 観点のメモを追記。

1-05. Phase 26-F — Loop Exit Liveness / BodyLocal PHI Guard箱とガードの整備、2025-11-22 時点)

目的

  • LoopForm v2 / Exit PHI まわりで、BodyLocal 変数の未定義利用を「箱」と「Fail-Fast」で確実に検知・抑制できるようにする。
  • MIR スキャン(本物の Exit Livenessは次フェーズに送りつつ、構造と受け口と環境変数ガードだけ先に整える。

やったこと26-F 初期完了分)

  • 4箱構成の整理と実装Exit PHI 専用レイヤ):
    • LoopVarClassBoxloop_var_classifier.rs:
      • 変数のスコープ分類専用Pinned / Carrier / BodyLocalExit / BodyLocalInternal
      • ここでは「どこで定義されているか」だけを見て、PHI 発行は行わない。
    • LoopExitLivenessBoxloop_exit_liveness.rs 新設):
      • ループ exit 後で「生きている可能性のある変数」の集合を返す箱。
      • Phase 26-F 時点では中身は保守的近似+ダミー、実運用は環境変数ガードで OFF。
      • 環境変数:
        • NYASH_EXIT_LIVE_ENABLE=1 で将来の MIR スキャン実装を opt-in で有効化(既定は 0/未設定)。
        • NYASH_EXIT_LIVENESS_TRACE=1 でトレース出力。
    • BodyLocalPhiBuilderbody_local_phi_builder.rs:
      • LoopVarClassBox の分類結果と LoopExitLivenessBoxlive_at_exit を統合し、「どの BodyLocal に exit PHI が必要か」を決める箱。
      • 既定挙動(ガード OFF:
        • これまで通り class.needs_exit_phi() のみを見るPinned / Carrier / BodyLocalExit
      • ガード ON の挙動(まだ実験段階):
        • BodyLocalInternal かつ live_at_exit に含まれ、かつ LocalScopeInspector::is_available_in_all が true なものだけ、追加で exit PHI 候補に昇格できる OR ロジックを持つ。
    • PhiInvariantsBoxphi_invariants.rs:
      • Exit/If PHI 最後の Fail-Fast 検証箱。
      • 「全 pred で定義されているか」「不正な incoming が無いか」をチェックし、構造バグはここで止める。
  • Docs 整備:
    • docs/development/architecture/loops/loopform_ssot.md に 4箱構成と環境変数ガード方針を追記。
    • docs/private/roadmap2/phases/phase-26-F/README.md を新設し、26-F のスコープやらないこと次フェーズMIR スキャン本体)への橋渡しを書き切り。

テスト状況(ガード OFF 時点)

  • Phase 26-F-3 → 26-F の流れで、一時的に退行したが、
    • NYASH_EXIT_LIVE_ENABLE を既定 OFF にし、
    • BodyLocalInternal 救済ロジックをガード付きに戻したことで、
    • F3 ベースラインより PASS が増え、FAIL が減る状態(例: 365 PASS / 9 FAILまで持ち直し済み。
  • FuncScanner 系:
    • mir_funcscanner_skip_ws_direct_vm
    • mir_funcscanner_parse_params_trim_min_verify_and_vm は引き続き「BodyLocal / Exit Liveness のカナリア」として使う(未定義値が出た場合は 26-G 以降で追う)。

このフェーズで残っていること

  • ExitLivenessProvider 相当のインターフェースを ExitPhiBuilder 周辺に導入し、「ExitLiveness を差し替え可能」な受け口だけ整える(中身は Legacy のまま)。→ 完了MirScanExitLiveness も追加済み(現状は header/exit_snapshots の union を返す簡易版)。
  • LoopFormOps / MirBuilder に MIR 命令列アクセスを追加する設計を 26-F の README にメモしておき、実装は 26-G 以降に分離する。

1-02+. Phase 26-G — Exit Liveness MIR Scan計画開始

  • 26-F で作った差し替え口に、本物の use/def スキャン実装を載せるフェーズ。
  • NYASH_EXIT_LIVE_ENABLE=1 で MIR スキャン版を有効にし、FuncScanner カナリアskip_ws / parse_params_trimを緑にするのが目標。
  • 新設 docs: docs/private/roadmap2/phases/phase-26-G/README.md に手順と受け入れ条件を記載済み。

1-03. Phase 25.3 — FuncScanner / StageB defs 安定化(完了)

目的

  • StageB / FuncScanner ラインで defs が欠落したり Loop が脱落する問題を塞ぎ、selfhost 側の canary を緑に戻す。

やったこと

  • StageBDriverBox.main:
    • main 本文を {…} で包んだ block パーサ優先で Program(JSON) に組み立て、defs には {"type":"Block","body":[…]} 形式で埋め込むよう整理。
    • Program パーサ fallback は HAKO_STAGEB_PROGRAM_PARSE_FALLBACK=1 の opt-in に封じ込めskip_ws 崩れを回避)。
  • StageBFuncScannerBox._scan_methods:
    • block パーサ優先に統一し、Program パーサは HAKO_STAGEB_FUNC_SCAN_PROG_FALLBACK=1 でのみ有効化。
    • defs パラメータに必ず me を足す従来挙動は維持TestBox/Main いずれも同型で出力)。
  • Rust 層の追加変更なしLoopForm v2 / LoopSnapshotMergeBox をそのまま利用)。

結果

  • tools/smokes/v2/profiles/quick/core/phase251/stageb_fib_program_defs_canary_vm.sh が安定して PASS。
    • Program.kind == "Program"
    • defsTestBox.fib / Main.main を保持していること。
    • TestBox.fib.body.body[*]Loop ノードが含まれること。 を満たした状態で rc=0 になることを確認。
  • FuncScanner / StageB 経由の fib defs ラインは LoopForm v2 + LoopSnapshotMergeBox 上で構造的に安定したとみなし、Phase 25.3 はクローズ。
  • 次フェーズの入口が整理できたので、Stage1 UsingResolver ループRegion+next_i 形)と Stage1 CLI program-json/selfhost 導線に着手可能。

1-1. Phase 25.1m — Static Method / LoopForm v2 continue + PHI Fix完了

目的

  • 静的メソッド呼び出し時の「暗黙レシーバ引数ずれ」バグと、LoopForm v2 経路における continue + header PHI の欠落を根本から直す。

Rust 側(静的メソッド / 暗黙レシーバ / JSON v0 Bridge

  • src/mir/function.rs::MirFunction::new
    • 暗黙 receiver 判定を是正し、「第 1 パラメータが Box 型の関数だけ」をインスタンスメソッド with receiver とみなす。
    • 非 Box 型(String, Integer など)で始まるパラメータ列の関数は、暗黙レシーバなしの静的メソッド / Global 関数として扱うように変更。
    • その結果:
      • static box TraceTest { method log(label) { ... } } に対して TraceTest.log("HELLO") を呼ぶと、 label"HELLO" が正しく入る(以前は label = null になっていた)。
    • src/mir/builder/decls.rs::build_static_main_box
      • Main.main(args) を「静的エントリ関数」に lower する経路を NYASH_BUILD_STATIC_MAIN_ENTRY=1 のときだけ有効 にし、 通常の VM 実行では wrapper main() を正規エントリとして扱うように整理。
      • これにより、「Main.main(args) 版ではループが 1 度も回らず return 0 で終わる」バグを解消。
    • JSON v0 Bridge 経由の Box メソッドStage1/StageB defs:
      • src/runner/json_v0_bridge/lowering.rsprog.defs の降下ロジックを調整し、
        • box_name != "Main" の関数定義をインスタンスメソッドとして扱って signature.params に「暗黙 me + 明示パラメータ」を載せる。
        • func_var_mapmefunc.params[0] を事前バインドし、残りのパラメータ名を params[1..] に対応づける。
      • これにより、Stage1UsingResolverFull._build_module_map() のように JSON では params: [] でも Hako 側で me._push_module_entry(...) を使う関数について、 Rust VM 実行時に me が未定義ValueId(0))になるケースを構造的に防止。

LoopForm v2continue + header PHI

  • src/mir/phi_core/loopform_builder.rs::LoopFormBuilder::seal_phis
    • シグネチャを seal_phis(ops, latch_id)seal_phis(ops, latch_id, &continue_snapshots) に拡張。
    • preheader と latch に加え、LoopBuilder 側で記録している continue_snapshots からの値も header PHI の入力 として統合。
    • pinned / carrier いずれも、header の全 predecessor:
      • (preheader, preheader_copy)
      • (continue_bb, value_at_continue)
      • (latch, value_at_latch) を入力として持つようになり、balanced scan など「continue を含むループ」の SSA が正しく構成される。
  • src/mir/loop_builder.rs::build_loop_with_loopform
    • let continue_snaps = self.continue_snapshots.clone();
    • loopform.seal_phis(self, actual_latch_id, &continue_snaps)?;
    • という形で、LoopBuilder → LoopForm 側に continue スナップショットを橋渡し。

ControlForm / LoopShape invariant

  • src/mir/control_form.rs::LoopShape::debug_validatedebug ビルドのみ)
    • 既存の:
      • preheader -> header エッジ必須
      • latch -> header バックエッジ必須
    • に加えて、次の invariant を追加:
      • continue_targets の各ブロックから header へのエッジが存在すること。
      • break_targets の各ブロックから exit へのエッジが存在すること。
    • これにより、LoopForm / LoopBuilder が continue / break 経路を誤配線した場合に、構造レベルで早期検知できる。

テスト / 検証

  • MIR ユニットテスト:
    • src/mir/phi_core/loopform_builder.rs::tests::test_seal_phis_includes_continue_snapshots
      • LoopFormBuilder 単体で「preheader + continue + latch」が PHI 入力に含まれることを固定。
    • src/tests/mir_stageb_loop_break_continue_verifies
      • StageB 風の loop + break/continue パターンで MirVerifier 緑。
    • src/tests/mir_stage1_using_resolver_verify.rs::mir_stage1_using_resolver_full_collect_entries_verifies
      • LoopForm v2/PHI v2 経路(現在は既定実装)で Stage1 UsingResolver フル版が MirVerifier 緑。
  • 実行観測:
    • 開発用 Hako loop_continue_fixed.hako:
      • 期待 RC=3 / 実測 RC=3、PHI pred mismatch なし。
    • StageB balanced scan:
      • StageBBodyExtractorBox のバランススキャンループに trace を入れて 228 回イテレーションが回ること、 ch == "{" ブランチで depth / i を更新 → continue → 次イテレーションに 確実に戻っている ことを確認。

1-2. Phase 25.1k — LoopSSA v2 (.hako) & StageB harness 追従Rust 側はおおむね完了)

目的

  • Rust 側の LoopForm v2 / ControlForm / Conservative PHI を SSOT としつつ、StageB / selfhost で使っている .hako 側 LoopSSA/BreakFinderBox/PhiInjectorBox をその規約に追従させる準備フェーズ。

Rust 側でやったこと(サマリ)

  • Receiver / pinning:
    • CallMaterializerBox::materialize_receiver_in_callee を事実上 no-op にし、 receiver の pinning / LocalSSA 連携を receiver::finalize_method_receiver に一本化。
    • MirBuilderpin_slot_names: HashMap<ValueId, String> を持たせ、 LocalSSA.ensure が「同じ slot にぶらさがる最新の ValueId」へ自動でリダイレクトできるようにした。
  • Compiler Box の分類:
    • CalleeResolverBox::classify_box_kindBreakFinderBox / PhiInjectorBox / LoopSSA を追加し、 Stage1/StageB 用 LoopSSA 箱を CalleeBoxKind::StaticCompiler として明示。

IfForm / empty else-branch の SSA fixStage1 UsingResolverFull 対応)

  • src/mir/builder/if_form.rs:
    • if cond { then }else なし)のパターンで、
      • else-entry 用に pre_if の variable_map から PHI ノードを生成したあと、
      • その PHI 適用後の variable_mapelse_var_map_end_opt=Some(...) として merge フェーズに渡すように修正。
    • 以前は empty else の場合に else_var_map_end_optNone になっており、 merge_modified_vars が pre_if の古い ValueId にフォールバックして、 merge ブロックで未定義の %0 などを参照するケースがあった(Stage1UsingResolverFull.main/0 の UndefinedValue
    • 修正後は then/else 両ブランチで「PHI 適用後の variable_map」が merge に渡されるため、 empty else でも header/merge の SSA が崩れない。
  • 検証:
    • src/tests/mir_stage1_using_resolver_verify.rs::mir_stage1_using_resolver_full_collect_entries_verifiesMirVerifier 緑になり、Stage1UsingResolverFull.main/0() の merge ブロックで PHI 後の値(例: %24)を正しく参照していることを MIR dump で確認済み。

.hako 側の今後25.1k 後半)

  • LoopSSA.stabilize_merges(json) を Rust LoopForm v2 の Carrier/Pinned 規約に合わせて実装する(現在はほぼ stub
  • StageB Test2tools/test_stageb_min.sh)で得られる Program(JSON v0) に対し、
    • Rust 側で NYASH_VM_VERIFY_MIR=1 を立てた実行結果と、
    • .hako 側 LoopSSA v2 適用後の JSON → Rust 実行結果 を比較し、BreakFinderBox / PhiInjectorBox / LoopSSA の責務を切り分けていく。

1-3. Phase 25.1e/f/g — LoopForm PHI v2 / ControlForm 統合(サマリ)

  • 25.1eLoopForm PHI v2 migration:
    • Local SSAlocal a = ...)の ValueId 分離を完了し、LoopForm v2 を「PHI/SSA の正」とする方向へ寄せた。
    • Stage1 UsingResolver / 基本的な StageB ループは、LoopForm v2 経路で MirVerifier 緑。
  • 25.1fControlForm 層の導入):
    • ControlForm / LoopShape / IfShape を導入し、Loop / If を共通ビューとして扱う箱を定義。
    • ここでは挙動を変えず、「構造だけを先に固定」する方針で設計を固めた。
  • 25.1gConservative PHI ↔ ControlForm ブリッジ):
    • phi_core::loopform_builder::build_exit_phis_for_control など、ControlForm から Conservative PHI を呼び出す薄いラッパを追加。
    • 既存の PHI ロジックはそのままに、将来の置き換えポイントだけを明示している。

1-4. Phase 25.1A3 — Stage1 CLI bridgestub 実装)

  • Rust 側: src/runner/stage1_bridge.rsrun_refactored 入口に組み込み、NYASH_USE_STAGE1_CLI=1 かつ再入ガードなしのときに lang/src/runner/stage1_cli.hako を子プロセスで起動する。STAGE1_EMIT_PROGRAM_JSON / STAGE1_EMIT_MIR_JSON / STAGE1_BACKEND / STAGE1_PROGRAM_JSON で mode 選択。entry override は STAGE1_CLI_ENTRY / HAKORUNE_STAGE1_ENTRY
  • .hako 側: Stage1Cli に最低限の本体を実装。
    • emit_program_json: Stage1 UsingResolver で prefix を結合し、BuildBox.emit_program_json_v0 で Program(JSON v0) を返す。
    • emit_mir_json: MirBuilderBox.emit_from_program_json_v0 をそのまま呼ぶdelegate 未設定なら null
    • run_program_json: backend==llvm の場合は env.codegen.emit_object まで通す。vm/pyvm は当面 MIR(JSON) を stdout に出すのみ(実行は Stage0 橋渡し未配線)。
    • CLI: emit program-json|mir-json / run --backend ... <src> を受理。NYASH_SCRIPT_ARGS_JSON を JSON で best-effort 伝播。
  • Docs: docs/private/roadmap2/phases/phase-25.1/stage1-usingresolver-loopform.md に stub 状態を追記run は暫定挙動)。
  • Known gaps: vm/pyvm 実行はまだ Stage0 への橋渡し未着手。llvm も emit object 止まりlink/exec は後続)。

1-5. Phase 25.1A4 — Using SSOT 薄設計BuildBox include 除去

  • SSOT: lang/src/using/resolve_ssot_box.hako に README 相当のコメントと I/Fresolve_modules/resolve_prefixを追加。現状は no-op だが「using をここで扱う」窓口を固定。
  • Stage1UsingResolver: resolve_for_program_json を追加し、SSOT を呼ぶ導線だけ確保(現状は透過返し)。
  • BuildBox: 先頭の include を削除し、using lang.compiler.entry.bundle_resolver as BundleResolver に置換StageB パーサが include を解せない問題の足場づくり)。
  • 実行確認: NYASH_ALLOW_NYASH=1 HAKO_ALLOW_NYASH=1 NYASH_USE_STAGE1_CLI=1 STAGE1_EMIT_PROGRAM_JSON=1 ... cargo run --bin hakorune -- basic_test.hako が RC=0 で完走(ただし stdout は RC: 0 のみ、program-json 出力は未配線)。cargo run ... emit program-json は Rust CLI 側の表面が未対応のためエラー(想定挙動)。

2. まだ残っている問題・課題2025-11-18 時点)

2-1. StageB 本体の型エラー(String > Integer(13)

  • 症状:
    • StageB の Main.main 実行時に、 Type error: unsupported compare Gt on String(...) and Integer(13) が発生。
    • LoopForm v2 / PHI / continue 修正とは 独立の StageB 固有のロジック問題
  • 想定される原因:
    • StageB 側の body 構築 / JSON 生成で、本来数値比較にすべき箇所で「生の文字列」と整数を比較している。
    • もしくは、Parser/Scanner が len やインデックスを文字列のまま扱っている部分がある。
  • 対応方針(次フェーズ向けメモ):
    • StageBBodyExtractorBox.build_body_src が吐く body_src を最小ケースで抽出し、 その中から問題の比較式(>)がどのように生成されているかを特定する。
    • StageB の box レベルで:
      • 「どのフェーズで型を決めるか」(例: ParserBox / StageB / VM 手前)を決めてから修正する。
    • このタスクは 25.1c 続き or 新フェーズ25.1n 相当として、StageB 箱の設計側で扱う。

2-2. StageB 再入ガード env.set/2 の扱い

  • 現状:
    • 一部 StageB コードが env.set/2 を使った再入ガードに依存しており、 Rust VM 側には env.set/2 extern が定義されていないため、 ❌ VM error: Invalid instruction: extern function: Unknown: env.set/2 が発生するケースがある。
  • 方針メモ:
    • 選択肢 A: StageB 再入ガードを Box 内 stateフィールドに寄せて、env.set/2 依存をなくす。
    • 選択肢 B: StageB ハーネス専用に、最小限の env.set/2 extern を Rust 側に実装する(本番経路では使わない)。
    • 25.1m では構造修正Loop/PHI/receiverを優先し、この extern の話は据え置き。

2-3. .hako 側 LoopSSA v2Rust LoopForm v2 との乖離)

  • 現状:
    • lang/src/compiler/builder/ssa/loopssa.hakostabilize_merges() はまだ実質的に stub に近い。
    • StageB Test2compiler_stageb.hako 経由では、Rust MIR 側で LoopForm v2 / PHI v2 が安定した後も、 .hako 側 LoopSSA 経由の JSON から生成した MIR で PHI/SSA 問題が残る可能性がある。
  • 目標:
    • Rust LoopForm v2 を「制御構造と PHI の SSOT」とみなし、 .hako 側 LoopSSA が同じ Carrier/Pinned / preheader/header/exit の規約を JSON レベルで再現する。
  • やること(フェーズ 25.1k 後半〜 25.1f/g 連携):
    • 特定の関数(例: BreakFinderBox._find_loops/2を対象に、Rust 側 / .hako 側のそれぞれで生成されるループ構造を比較。
    • LoopSSA v2 の中に:
      • Carrier 変数の検出、
      • pinned 変数の扱い、
      • exit PHI の構築 を Rust LoopForm v2 に合わせて実装。
    • 2025-11-19 追記:
      • BreakFinderBox._find_loops/2 については、まず .hako 側を「region box」的に整理した。
        • header_pos / header_id / exit_pos / exit_id まわりの異常系を continue ではなく next_i ローカルへの代入で表現し、1 イテレーションの末尾で i = next_i に合流させる形に変更。
        • これにより、LoopForm v2 / LoopSSA 側から見ると「単一 region 内での分岐+最後に合流」という構造になり、 carrier/pinned 検出や今後の SSA 解析が行いやすくなった(挙動は従来と同じ)。

2-5. static box / me セマンティクス(観測タスクへ移行)

  • 現状:
    • static box StringHelpers のようなユーティリティ箱で、me.starts_with(src, i, kw) のように 同一箱内のヘルパー(starts_with)を me. 経由で呼んでいたため、Stage3 降下時に引数ずれが発生していた。
    • 具体的には、StringHelpers.starts_with_kw/3StringHelpers.starts_with/3 の降下で 実際の呼び出しが starts_with("StringHelpers", src, i, kw) のような 4 引数形になり、 starts_with(src, i, pat) 側では src="StringHelpers" / i=<ソース全文> となって、 if i + m > nString > Integer(13) 比較に化けていた。
  • 対応(完了済み・局所修正):
    • lang/src/shared/common/string_helpers.hakostarts_with_kw を、 if me.starts_with(src, i, kw) == 0 から if starts_with(src, i, kw) == 0 に書き換え、 static box ユーティリティに対する me 依存を除去した。
    • これにより、starts_with 内でのガード比較 i + m > n はすべて整数同士となり、 StageB fib ケースで発生していた String("...") > Integer(13) の TypeError は解消済み。
  • 今後Phase 25.1p 以降):
    • static box 全般における me セマンティクス(本当に「シングルトンインスタンス」として扱う箱と、 純粋な名前空間箱をどう区別するかは、25.1p の DebugLog フェーズで観測しながら設計を詰める。
    • 実際に Rust 層(build_me_expression / lower_static_method_as_function / FunctionDefBuilder::is_instance_method)を 統一規約に寄せる作業は、25.1p 以降のサブタスクとして扱う(現時点では局所修正でバグのみ解消)。

2-4. Builder / Selfhost まわりの残タスク(超ざっくり)

  • Builder 内部ルート20.43 系):
    • MirBuilderBox 経由の internal ルートで、MIR を stdout 経由ではなく一時ファイル / FileBox に書き出し、 ハーネスがそこから読む形に揃える案が残タスク。
  • Selfhost CLI / Stage1 CLI:
    • StageB / Stage1 CLI を「Rust VM / LLVM / PyVM / selfhost」の 4 経路で安定確認するラインは進行中。
    • 25.1m では Rust VM + StageB balanced scan を優先し、CLI 全体は次のフェーズで詰める。

3. 次にやること(候補タスク)

ここから先は「どのフェーズを進めるか」をそのときの優先度で選ぶ感じだよ。
Rust 側は LoopForm v2 / StageB fib / Stage1 UsingResolver 構造テストまで一通り整ったので、当面は Stage1 CLI / selfhost ラインの小さな箱から進める。

A. Stage1 CLI / Stage0 ブリッジPhase 25.1 — いまここ)

  • A1: Stage1 CLI stub を Stage0 Rust ランナーから呼び出すブリッジDONE
    • 実装: src/runner/stage1_bridge.rs src/runner/mod.rsmaybe_run_stage1_cli_stub を追加。
      • NYASH_USE_STAGE1_CLI=1(既定 OFFかつ NYASH_STAGE1_CLI_CHILD!=1 のときにだけ有効。
      • entry .hakoSTAGE1_CLI_ENTRY / HAKORUNE_STAGE1_ENTRY で上書き可能(既定: lang/src/runner/stage1_cli.hako)。
      • 入力ファイル / モード:
        • STAGE1_EMIT_PROGRAM_JSON=1: hakorune emit program-json <source.hako> を子プロセスで実行。
        • STAGE1_EMIT_MIR_JSON=1: STAGE1_PROGRAM_JSON があれば --from-program-json、なければ <source.hako> から emit mir-json
        • 上記どちらも無い場合: hakorune run --backend <backend> <source.hako>backend は STAGE1_BACKEND か CLI の backend 設定)。
      • NYASH_SCRIPT_ARGS_JSON を拾って -- 以降の script 引数も Stage1 側に転送。
      • 再入防止として子プロセスには NYASH_STAGE1_CLI_CHILD=1 を付与(子側からは Rust ブリッジを素通り)。
  • A2: Stage1 CLI skeleton の責務を doc に固定DONE
    • lang/src/runner/stage1_cli.hakoStage1Cli.emit_program_json/emit_mir_json/run_program_json/stage1_main のシグネチャとトグルトポロジーを固定。
    • docs/private/roadmap2/phases/phase-25.1/stage1-usingresolver-loopform.md に Rust 側ブリッジの振る舞いとトグル名(NYASH_USE_STAGE1_CLI / STAGE1_EMIT_* / STAGE1_BACKEND / NYASH_STAGE1_CLI_CHILD)を追記。
  • A3: 次ステップ(未着手)
    • Stage1 CLI skeleton に StageB/BuildBox/MirBuilder 呼び出しを順に実装し、「Program(JSON)/MIR(JSON) を selfhost 経由で emit できる」状態まで持っていく。
    • tools/selfhost/run_stage1_cli.sh から呼び出す selfhost パスと、Rust CLl からのブリッジパスの両方で JSON I/O 契約が同じになるように揃える。

B. Stage1 UsingResolver / LoopForm v2 ラインPhase 25.1e 系フォロー)

  • B1: entry UsingResolver の Region+next_i 化とコメント整備(おおむね DONE
    • lang/src/compiler/entry/using_resolver_box.hako の 3 ループentries / JSON スキャン / modules_listは Region+next_i 形に揃え済み。
    • 役割コメント: resolve_for_sourceStageB body_src を受けて prefix を返す)、_collect_using_entriesJSON スキャンして entries を集める)、_build_module_mapmodules_list を map 化)を明記済み。
    • HAKO_STAGEB_APPLY_USINGS=0 の時は prefix を空 string にしつつ、depth ガードだけは走らせる仕様もコメントで固定。
  • B2: UsingResolver 構造テスト(ループ形/PHIの拡充DONE
    • src/tests/mir_stage1_using_resolver_verify.rs に Region+next_i ループと early-exit JSON スキャンパターンの軽量テストを追加。
    • これらは cargo test 経路で常時緑を維持し、v2 quick スモークへの昇格は「実行時間とイズを見ながら後続フェーズで検討」という扱いにするdocs にメモ済み)。
  • B3: pipeline_v2 UsingResolver との責務境界DONE
    • lang/src/compiler/pipeline_v2/using_resolver_box.hako 冒頭に、「entry 側=ファイル I/O + using 収集」「pipeline_v2 側=modules_json 上の alias/path 解決」と役割メモを追加。
    • RegexFlow ベースの単一路ループは Region 化不要stateful helperとし、LoopForm v2 の観点からも「観測対象外」とする。

C. FuncScanner / Exit PHI カナリアPhase 26-F / 26-G への橋渡し)

  • C1: FuncScanner trim/skip_ws/parse_params の最小再現ケース固定DONE
    • lang/src/compiler/tests/funcscanner_trim_min.hako_trim / trim / skip_whitespace を 1 回ずつ呼ぶ最小 Main を定義。
    • src/tests/mir_funcscanner_trim_min.rs で:
      • Stage3 / using 有効化したパーサ設定で func_scanner.hako + 上記テストを一体コンパイル。
      • MirVerifier でモジュール全体の SSA/PHI を検証(HAKO_MIR_BUILDER_METHODIZE=0 でも常に緑になることを確認)。
      • VM 実行は NYASH_TRIM_MIN_VM=1 のときだけ有効化(いまは MIR 側の根治が主目的)。
  • C2: FuncScanner 側ロジックの構造整理DONE
    • lang/src/compiler/entry/func_scanner.hako:
      • parse_params を Region+next_i 形の 1 本ループに整理し、先頭スキップとカンマ探索をそれぞれ helper に寄せた。
      • trim は先頭側を skip_whitespace に全面委譲し、末尾側のみ後ろ向きループで処理するように簡素化。
      • skip_whitespaceloop(i < n) + if/continue だけにした最小形にし、過去の dev 向けログや loop(1==1) ワークアラウンドを撤去。
    • これにより FuncScanner フロントは LoopForm v2 / LoopSSA v2 から見て「素直なループ+明確な next_i 形」になり、以後の PHI/ExitLiveness 側の根治作業が .hako に依存しづらい形になった。
  • C3: Phase 26-F / 26-G のカナリアとして位置付け(進行中)
    • 26-F 時点では NYASH_EXIT_LIVE_ENABLE 既定 OFF で、従来挙動のまま mir_funcscanner_trim_min が MIR verify 緑になることを確認済み。
    • 26-G では:
      • NYASH_EXIT_LIVE_ENABLE=1 + MirScanExitLiveness 経由でも mir_funcscanner_trim_min(特に FuncScannerBox.trim/1 / skip_whitespace/2 / parse_params/1が常に緑になることを受け入れ条件にする。
      • そのうえで mir_funcscanner_skip_ws_direct_vm / StageB / Stage1 UsingResolver 系のカナリアも順に緑に揃える。

D. StageB / LoopSSA / Selfhost まわり(中期タスク)

  • D1: StageB 再入ガード env.set/2 の整理(据え置き)
    • dev 専用 extern を Rust 側に追加するか、StageB 箱側で state に寄せるかを決める必要があるが、現在はループ/PHI ラインを優先し保留。

4. Phase 26-H — JoinIR 設計 & ミニ実験(新規フェーズ)

目的

  • 制御構造if / loop / break / continue / return関数呼び出し+継続 に正規化する中間層JoinIRを設計し、LoopForm v2 / PHI / ExitLiveness の負担を将来軽くする足場を作る。
  • 25.1 / 26-F / 26-G の本線を止めずに、「設計+ごく小さな実験」だけを先に進める。
  • スモーク/本線は既存の MIR/LoopForm 経路のまま維持しつつ、徐々に「関数型LoopFnIR/JoinIR」側に重心を移す。

進捗26-H 完了分)

  • JoinIR 設計ドキュメント反映済み(docs/development/architecture/join-ir.md
  • 26-H README/TASKS でスコープ・最終箱セット・次フェーズ境界を明記
  • src/mir/join_ir.rs で JoinIR 型定義+ JoinIrMin 用のミニ自動変換を実装
  • apps/tests/joinir_min_loop.hako + src/tests/mir_joinir_min.rs(トグル付きカナリア)を追加
  • トグル: NYASH_JOINIR_EXPERIMENT=1 で JoinIR 実験を有効化(デフォルトは既存 MIR/LoopForm のみ)

次フェーズPhase 27 — JoinIR 実用化)

  • フォルダ: docs/private/roadmap2/phases/phase-27-joinir/
  • 27.1: JoinIR 変換を FuncScanner/StageB の代表ループに拡張(トグル付き)
  • 27.2: JoinIR → VM/LLVM ブリッジのプロトタイプを作り、A/B 実行を試す(トグル付き)
  • 27.3: レガシー PHI/Loop 箱を段階削減Header/Exit/LoopPhi 系の吸収・削除計画を実行)

やること26-H スコープ)

  • H1: JoinIR 設計ドキュメントの追加(完了

    • docs/development/architecture/join-ir.md に命令セットと変換規則、対応表を記述済み。
    • docs/private/roadmap2/phases/phase-26-H/README.md に、26-H のスコープ/やらないこと/他フェーズとの関係を記載済み。
  • H2: JoinIR 型定義とミニ変換の骨格(完了

    • src/mir/join_ir.rsJoinFunction/JoinInst/JoinContId/JoinModule 等の型を定義済み。
    • lower_min_loop_to_joinirJoinIrMin.main/0 用の試験的な自動変換を実装Phase 27.x で一般化予定)。
    • src/tests/mir_joinir_min.rsapps/tests/joinir_min_loop.hako でカナリアテストを追加(NYASH_JOINIR_EXPERIMENT=1 時のみ有効)。
  • H3: トグル付きミニ実験(完了

    • NYASH_JOINIR_EXPERIMENT=1 で JoinIR 実験テストを有効化。
    • トグル OFF 時は既存の MIR/LoopForm 経路のみが動作することを確認(ゼロリグレッション)。

やらないこと26-H では保留)

  • 既存の LoopForm v2 / PhiBuilderBox / ExitPhiBuilder を JoinIR ベースに全面移行すること。
  • StageB / Stage1 / CLI / selfhost ラインの本線を JoinIR で差し替えること。
  • 既存の SSA/PHI 実装を削除すること(全部別フェーズで検討)。

優先度と位置付け

  • 本線(いま重視する順):
    1. Phase 25.1 — Stage1 UsingResolver / Stage1 CLI program-json/mir-json を安定化。
    2. Phase 26-F / 26-G — Exit PHI / ExitLiveness の根治LoopForm v2 / PHI SSOT / MirScanExitLiveness
  • Phase 26-H は:
    • 「本線の合間に進める設計フェーズ」として扱う。

    • JoinIR が小さいケースでうまく動くことを確認できたら、27.x 以降で本格的な導入を検討する。

    • このタスクに着手するときは「prod/CI 経路から完全に切り離した dev ガード」として設計する。

  • C2: .hako LoopSSA v2 実装Rust LoopForm v2 への追従)
    • Rust LoopForm v2 の Carrier/Pinned/BodyLocalInOut モデルを .hako の LoopSSA に輸入し、StageB Test2 / selfhost CLI でも MirVerifier 緑を目指す中〜長期タスク。
    • 具体的な対象: lang/src/compiler/builder/ssa/loopssa.hako と StageB/BreakFinder 周辺の region 化済みループ。
  • C3: Selfhost / CLI 周辺のテスト整理
    • 代表的な selfhost / StageB / Stage1 CLI ケースを tests/tools 側でタグ付けquick/integration/selfhost、Phase 25.1 の「どこまでが Rust 側」「どこからが Stage1 側」を見える化する。

4. 履歴の見方メモ

  • 以前の CURRENT_TASK.md は ~1900 行の長いログだったけど、読みやすさ重視でこのファイルはスナップショット形式にしたよ。
  • 過去の詳細ログが必要になったら:
    • git log -p CURRENT_TASK.md
    • あるいは特定のコミット時点の CURRENT_TASK.mdgit show <commit>:CURRENT_TASK.md
      でいつでも復元できるよ。

Phase 25.4 — Naming & Stage1 CLI Cleanupdesign only

  • ねらい:
    • static box / global 呼び出しの命名規約を NamingBox に集約し、VM 側のレガシーフォールバック経路を撤去する。
    • Stage1 CLI の env/トグル解釈を 1 箇所の設定箱にまとめ、stage1_main の責務を薄く保つ。
    • __mir__.log ベースの MIR ログ観測ポイントをドキュメントで一覧化し、将来の正式 API 化に備える。
  • 現状:
    • NamingBoxsrc/mir/naming.rsは導入済みで、Builder 側の static メソッド名は encode_static_method 経由、VM 側の global 呼び出しは normalize_static_global_name 経由になっている。
    • VM 側の「canonical 名で見つからなければ元名でもう一度探す」フォールバックは削除済みで、mir_static_box_naming テスト群が Main._nop/0 経路を固定している。
    • Stage1 CLI は env-only 仕様argv 依存なし)で Stage0 ブリッジと接続済みだが、env 群の解釈はまだ stage1_main 内に散在している。
  • このフェーズでやること(設計レベル):
    • NamingBox を「static 名に触るすべてのコードの SSOT」として整理直接 format!("Box.main") する箇所を洗い出し)。
    • Stage1CliConfigBoxを設計し、env→Config 変換の責務とフィールドを docs に書き出す(実装は後続でも可)。
    • __mir__.log のタグと用途を 1 ページの docs にまとめ、dev 用ログと残したい観測ログを分けておく。

以上が 2025-11-18 時点の Phase 21.8 / 25 / 25.1 / 25.2 / 25.4 ラインの「いまどこ」「なに済み」「なに残り」だよ。
次にどの箱から攻めるか決めたら、ここに箇条書きで足していこうね。

3. これからやるタスクのラフ一覧25.1 / Stage1 系)

ここから先は「まず設計と箱分割を書いてから実装」という方針で進めるタスク群だよ。

A. Rust 層解析LoopForm v2 / JSON v0 / Stage1 観測)

  • A-1: LoopForm v2 / LoopSnapshotMerge の入口確認
    • src/mir/loop_builder.rs / src/mir/phi_core/loopform_builder.rs / src/mir/phi_core/loop_snapshot_merge.rs を「Stage1 から見た導線」として読み直し、どのレイヤで Carrier / Pinned / BodyLocalInOut が決まるかを short メモ化する。
  • A-2: JSON v0 → MIR ブリッジの導線整理
    • src/runner/json_v0_bridge/lowering/(特に loop_.rsを通して、Program(JSON v0).body / defs.body(Block) が LoopForm v2 までどう運ばれるかを図として docs に落とす。
  • A-3: Stage1 UsingResolver の MIR 観測
    • 既存テスト src/tests/mir_stage1_using_resolver_verify.rs の MIR dump を元に、「どのループが Region+next_i 化候補か」「既に問題なく LoopForm に乗っている場所はどこか」を箇条書きで整理する。

B. Stage1 UsingResolver 箱化・ループ整理(.hako 側)

  • B-1: Stage1UsingResolverBox の責務分割設計
    • lang/src/compiler/entry/using_resolver_box.hako を、collect_entries / modules_map / file_read などの小さいロジック箱に概念的に分割し、「どの箱が何を責務とするか」を docs に書く(実際のファイル分割は後段)。
  • B-2: すべてのループを Region+next_i 形に揃える計画
    • entry の UsingResolver 内に残っている「pos++/continue 多発型」ループを洗い出し、Region+next_i 形にどう書き換えるかを phase-25.1 docs に追記する。
    • 目的: LoopForm v2 / PHI から見たときに「1 region / 1 backedge / 明確な次位置決定」という形に統一する。
    • 状況メモ: entry 側 3 ループentries/JSON scan/modules_listは Region+next_i 化済み。残りなし。
  • B-3: pipeline_v2 UsingResolver との役割分担
    • lang/src/compiler/pipeline_v2/using_resolver_box.hako と entry/Stage1UsingResolverBox のどちらが「テキスト / JSON / modules_map」のどこまでを担当するかを整理し、責務境界をドキュメントに固定する。
    • 状況メモ: pipeline_v2 側は modules_json の alias 解決のみRegexFlow.find_from の単一路ループ。Region 化不要として据え置き、境界だけ明記。
  • B-4: 構造テストの追加計画
    • Region+next_i パターンの軽量 SSA テスト(すでに 1 本追加済み)を基準に、もう 1〜2 本、UsingResolver ソースに近いパターンJSON スキャンearly-exitを追加する方針を決める。

C. Stage1 CLI / program-json / mir-json SelfHost 準備

  • C-1: Stage1 CLI インターフェースの設計メモ
    • .hako → Program(JSON) / Program(JSON) → MIR(JSON) / MIR(JSON) → 実行 を Stage1 側からどう呼び出すか(関数名・引数レベル)を docs に先に書く。
  • C-2: StageB → Stage1 データフロー図
    • compiler_stageb.hako → Program(JSON v0) → Stage1 UsingResolver → MirBuilder までのパイプラインを Phase25.1 ドキュメントに 1 枚の図としてまとめる。
  • C-3: Rust CLI 側ブリッジの最小ガード案
    • Stage0/Rust CLI は「Program(JSON/MIR(JSON) を受け取り VM/LLVM に流すだけ」に縮退させる方針と、既定 OFF トグルselfhost 入口)をどう切るかを設計メモとして追加。

D. 将来フェーズ向けメモvariable_map 決定化ライン)

  • D-1: MirBuilder::variable_map / BoxCompilationContext::variable_map BTreeMap 化案
    • どの構造を HashMap→BTreeMap 化するか、どのテスト(mir_funcscanner_skip_ws_vm_debug_flaky など)で決定性を確認するかを Phase25.x の設計メモとして書いておく。
  • D-2: dev 専用 / flaky テストの扱い方針
    • どのテストが dev ignore手動実行用で、いつ/何を満たしたら常時有効に戻すかを、このファイルと関連 README に明確に残す。

このセクションは「すぐ実装する TODO ではなく、25.1〜25.x ラインで踏むべき設計タスク一覧」として使う予定だよ。
(静的 me-call 修正の参考メモはここに残しつつ、別セクションは整理済み)

E. Legacy Loop/PHI 経路の囲い込みと削除準備

  • E-1: Legacy loop_phi.rs の役割と削除条件の明文化

    • ファイル: src/mir/phi_core/loop_phi.rs
    • 状態: LoopForm v2 + LoopSnapshotMergeBox への移行後は「legacy scaffold」としてのみ残存。
    • やること:
      • 現在の利用箇所を 2 種類に分類する:
        • 本線経路LoopForm v2 / Stage1 / StageB から参照される部分)
        • 互換レイヤ解析専用JSON v0 bridge, 旧 smokes, dev-only ヘルパ)
      • 本線はすべて loopform_builder.rs + header_phi_builder.rs + loop_snapshot_merge.rs で賄えることを確認し、loop_phi.rs を「legacy 専用(新規利用禁止)」として CURRENT_TASK と docs に固定しておく。
      • Phase 31.x の cleanup で実ファイル削除してよい条件(参照 0対応する smokes/テストの移行完了)を docs/private/roadmap/phases/phase-31.2/legacy-loop-deletion-plan.md 側と揃えておく。
  • E-2: PHI/LoopForm 周辺で HashMap を使ってよい/いけない場所を線引き

    • ファイル: src/mir/builder.rs, src/mir/phi_core/*, src/mir/loop_builder.rs
    • やること:
      • 「PHI 生成とスナップショット決定」に関わる構造では BTreeMap / BTreeSet / Vec+sort のみに限定し、HashMap は使わない、というルールを Phase 25.1 docs に明記する。
      • それ以外のメタ情報plugin sigs, weak_fields など)は HashMap 維持可とし、「決定性」に影響しないことをコメントで示しておく。
      • 代表として loop_phi.rs 内の sanitize_phi_inputs のように「一度 HashMap で集約してから sort する」パターンは、LoopForm v2 正系統では PhiInputCollector + BTree 系で代替されていることを確認し、legacy 側のみに閉じ込める。
  • E-3: Legacy 経路の一覧と新規利用禁止ポリシーを docs に反映

    • ファイル:
      • docs/private/roadmap2/phases/phase-25.1/README.md(本線側のルール)
      • docs/private/roadmap/phases/phase-31.2/legacy-loop-deletion-plan.md(削除計画側と整合させる)
    • やること:
      • Legacy として扱うモジュール(例: phi_core::loop_phi, 一部旧 JSON v0 bridge helperを一覧にして、「新しいコードからここを呼ばない」「Phase 31.x で削除予定」と明記する。
      • 逆に、今後 PHI/Loop/If で使うべき SSOT 箱LoopForm v2 + HeaderPhiBuilder + BodyLocalPhiBuilder + if_phi + ControlFormを 1 セクションで列挙し、「ここだけを見ると設計が分かる」導線を作る。

F. IfForm / Body-Local PHI 統合Phase 26-F 進捗メモ)

  • F-1: IfBodyLocalMergeBox の導入(完了)
    • ファイル: src/mir/phi_core/if_body_local_merge.rs
    • 責務: if-merge 専用の body-local PHI 候補決定。
      • 両腕に存在する変数のみを候補とし、pre_if から値が変化した変数だけを返す。
      • empty else の場合は空リストを返し、従来の PhiBuilderBox ロジックに委ねる。
  • F-2: LoopBuilder 内 if-merge への統合(進行中)
    • ファイル: src/mir/loop_builder.rs, src/mir/phi_core/phi_builder_box.rs
    • 状態: Phase 26-F-2 までで、loop 内 if の PHI 生成に IfBodyLocalMergeBox を噛ませるところまで実装。
      • 代表テスト 1 本が新たに PASS になったが、Loop PHI 側に残る domination errorValue %48 / non-dominating useがまだ存在。
    • メモ: この残件は LoopForm Exit PHI 側ExitPhiBuilder/LoopFormBuilderの古い Case に起因する既知バグとして扱い、次フェーズで Loop PHI 側の SSOT 化PhiBuilderBox への統合 or ExitPhiBuilder 根治)の入口とする。

3. Phase 25.1q — LoopForm Front UnificationDONE / follow-up 別タスクへ)

  • 目的: Rust AST ルート (LoopBuilder) と JSON v0 ルート (json_v0_bridge::lower_loop_stmt) のループ lowering を “LoopFormBuilder + LoopSnapshotMergeBox” に一本化し、どの経路からでも同じ SSOT を見るだけで良い構造に揃える。
  • 完了状態:
    • AST ルート:
      • LoopBuilder::build_loop_with_loopform で canonical continue_merge_bb を常時生成し、continue_target を header ではなく continue_merge_bb に統一済み。
      • LoopFormBuilder::seal_phis / LoopSnapshotMergeBox の continue/exit 入力は「preheader + continue_merge + latch」「header + break snapshots」で完全管理。
    • JSON v0 ルート:
      • loop_.rsLoopFormJsonOps を実装し、preheader/header/body/latch/continue_merge/exit の block ID を AST ルートと同じ形で生成。
      • break/continue/exit の snapshot を LoopSnapshotMergeBox でマージし、canonical continue_merge → header backedge を JSON 側でも採用。
      • tests/json_program_loop.rs で JSON v0 だけを入力にした軽量ループ(通常 / continue / body-local exitMirVerifier で確認するスモークを追加。
    • Docs/README:
      • docs/private/roadmap2/phases/phase-25.1q/README.md に「AST/JSON ともに LoopForm v2 + LoopSnapshotMergeBox が SSOT」と明記。
      • src/runner/json_v0_bridge/README.md で “bridge は薄いアダプタであり、新しい PHI 仕様は loopform 側でのみ扱う” とガードを追記。
      • src/mir/phi_core/loop_phi.rs には “legacy分析用のみ” コメントを追加。将来の cleanup (Phase 31.x) で削除対象とする。
  • 残タスクは別フェーズへ:
    • Stage1 UsingResolver 周りの SSA バグ(tests::mir_stage1_using_resolver_verify::mir_stage1_using_resolver_full_collect_entries_verifies の Undefined Valueは 25.1q の範囲外。LoopForm の SSOT 化は終わっているため、今後は Stage1 側の PHI/Env スナップショット設計タスクとして切り出す。
    • JSON v0 → Nyash AST への統合案や loop_phi.rs の実ファイル削除は、Phase 31.x cleanup 計画側で扱う。