Files
hakorune/docs/development/roadmap/phases/phase-25.1q/README.md
nyash-codex 525e59bc8d feat(loop-phi): Add body-local variable PHI generation for Rust AST loops
Phase 25.1c/k: Fix ValueId undefined errors in loops with body-local variables

**Problem:**
- FuncScannerBox.scan_all_boxes/1 and BreakFinderBox._find_loops/2 had ValueId
  undefined errors for variables declared inside loop bodies
- LoopFormBuilder only generated PHIs for preheader variables, missing body-locals
- Example: `local ch = s.substring(i, i+1)` inside loop → undefined on next iteration

**Solution:**
1. **Rust AST path** (src/mir/loop_builder.rs):
   - Detect body-local variables by comparing body_end_vars vs current_vars
   - Generate empty PHI nodes at loop header for body-local variables
   - Seal PHIs with latch + continue snapshot inputs after seal_phis()
   - Added HAKO_LOOP_PHI_TRACE=1 logging for debugging

2. **JSON v0 path** (already fixed in previous session):
   - src/runner/json_v0_bridge/lowering/loop_.rs handles body-locals
   - Uses same strategy but for JSON v0 bridge lowering

**Results:**
-  FuncScannerBox.scan_all_boxes: 41 body-local PHIs generated
-  Main.main (demo harness): 23 body-local PHIs generated
- ⚠️ Still some ValueId undefined errors remaining (exit PHI issue)

**Files changed:**
- src/mir/loop_builder.rs: body-local PHI generation logic
- lang/src/compiler/entry/func_scanner.hako: debug logging
- /tmp/stageb_funcscan_demo.hako: test harness

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 23:12:01 +09:00

6.3 KiB
Raw Blame History

Phase 25.1q — LoopForm Front Unification (AST / JSON v0)

Status: planning-onlyPhase 25.1 ラインの安定化が終わったあとに着手)

ゴール

  • ループ lowering / PHI 構築の SSOT を phi_core + LoopFormBuilder に完全に寄せる
    • Rust AST → MIRMirBuilder / LoopBuilder)と JSON v0 → MIRjson_v0_bridge::lower_loop_stmt)のフロントを整理し、 「どこを直せば loop/PHI の意味論が変わるか」を 1 箇所に明示する。
  • 実装者・LLM の混乱ポイントを減らす:
    • StageB / FuncScanner のようなループバグ調査時に、「Rust AST 側を触るべきか」「JSON v0 側を触るべきか」で迷わない構造にする。
    • 今回のように loop_.rs 側だけにログ・修正を入れてしまう誤りを防ぐ。

現状25.1m / 25.1p 時点の構造)

  • バックエンドSSOT

    • src/mir/phi_core/loop_phi.rs / src/mir/phi_core/loopform_builder.rs
      • LoopForm v2 / LoopSSA v2 の本体。
      • LoopFormBuilder + LoopFormOps として、ヘッダ PHI / exit PHI / continue スナップショットなどを一元的に扱う。
  • Rust AST → MIR 経路

    • ASTNode::Loop
      • src/mir/builder_modularized/control_flow.rs::build_loop_statement
      • src/mir/builder/control_flow.rs::cf_loop
      • src/mir/loop_builder.rs::LoopBuilder::build_loop_with_loopform
    • こちらはすでに LoopForm v2 / ControlForm v2 に統一済みで、「Rust パーサで読んだ .hako」を MIR に落とす主経路。
  • JSON v0 → MIR 経路

    • Program(JSON v0)ProgramV0:
      • src/runner/json_v0_bridge/lowering.rs::lower_stmt_with_vars
      • StmtV0::Loop { .. } => loop_::lower_loop_stmt(...)
      • src/runner/json_v0_bridge/lowering/loop_.rs::lower_loop_stmt
    • ここも LoopForm v2 / phi_core を呼ぶ構造にはなっているが、
      • ファイルが AST ルートとは別に分かれている
      • 追加ログや一時的なデバッグコードが入りやすく、「どの経路でループが下りているか」分かりづらい状態になりがち。
  • 結果として:

    • StageB / FuncScannerBox のような「Rust AST 経路」を見たいときに、誤って loop_.rs 側だけを触る、といった混乱が起きやすい。
    • 一方で JSON v0 経路は provider (env.mirbuilder.emit / --program-json-to-mir) で重要なので、急に削除はできない。

スコープ25.1q でやること)

  1. LoopForm / phi_core を SSOT として明文化(ドキュメント整理)

    • docs/development/roadmap/phases/phase-25.1b/ / phase-25.1m/ / 本 phase-25.1q で:
      • ループ意味論preheader/header/body/latch/exit、continue/break スナップショット、PHIの SSOT を phi_core::loop_phi / LoopFormBuilder に一本化すると明言する。
      • LoopBuilderRust AST フロント)と json_v0_bridge::lower_loop_stmtJSON フロント)は「薄いアダプタ」に留める方針を書いておく。
  2. json_v0_bridge::lower_loop_stmt の責務縮小(薄いフロント化)

    • 目標: loop_.rs は「JSON から LoopForm に渡すための最低限の橋渡し」に限定する。
    • 具体案:
      • 余計なデバッグログや独自判定を段階的に削り、やることを
        • preheader/header/body/latch/exit のブロック ID を用意する
        • ループ開始時点の vars を LoopPhiOps 実装に渡す
        • break / continue のスナップショット記録を呼び出す に絞る。
      • ループ構造・PHI の仕様変更は phi_core 側だけ に集約し、loop_.rs 側には分岐や条件を増やさない。
  3. ログ・デバッグ経路の整理

    • HAKO_LOOP_PHI_TRACE / NYASH_LOOPFORM_DEBUG などのトグルについて:
      • どのフロントRust AST / JSONからでも同じタグで観測できるようにし、ログの出し場所を整理する。
      • loop_.rs に残っている「一時的な ALWAYS LOG」などはすでに削除済みだが、今後も dev トレースは必ず env ガード越しに行う。
  4. JSON v0 → AST → MirBuilder 統合の検討(設計レベルのみ)

    • 将来案として:
      • ProgramV0 を一度 Nyash AST 相当の構造体に変換し、MirBuilderbuild_loop_statement を再利用する形に寄せる。
      • これが実現すると、loop_.rs 自体を削除しても LoopForm/PHI の意味論は完全に一箇所LoopBuilder + phi_coreに集約される。
    • 25.1q ではここまでは踏み込まず、「やるならどのフェーズで、どの単位の差分にするか」を設計メモとして残す。

スコープ外25.1q ではやらないこと)

  • ループ意味論そのものの変更:
    • loop(cond){...} の評価順序や break/continue の意味論を変えない。
    • StageB / Stage1 / 自己ホストルートで既に green な LoopForm/SSA テストの挙動は不変とする。
  • 新しいループ構文・最適化の追加:
    • while / for / range loop など、新構文の導入は別フェーズ(言語拡張側)に任せる。
  • JSON v0 スキーマの変更:
    • StmtV0::Loop などの JSON 形は既存のままschema v0/v1 は維持)。

他フェーズとの関係

  • 25.1mStatic Method / LoopForm v2 continue + PHI Fix:

    • ここで LoopForm v2 / continue + header PHI は Rust AST 経路でほぼ安定している。
    • 25.1q では、その成果を JSON v0 経路にも構造的に反映し、「LoopForm v2 がどこから使われているか」を明示する役割を担う。
  • 25.1pMIR DebugLog 命令):

    • DebugLog を使って LoopForm/PHI の ValueId を観測しやすくすることで、25.1q での統一作業時に「AST ルートと JSON ルートの差」を追いやすくする。
    • 25.1q は DebugLog 基盤が整っていることを前提に、小さな JSON v0 → MIR のテストケースで CFG/PHI を比較するフェーズとする。
  • 25.2Numeric Microbench / EXE Tuning:

    • JSON v0 → MIR → EXE 経路は numeric_core / AotPrep と強く結びついているため、25.1q で LoopForm front を整理しておくと、25.2 でのパフォーマンス解析やバグ調査がやりやすくなる。***