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>
Phase 25.1q — LoopForm Front Unification (AST / JSON v0)
Status: planning-only(Phase 25.1 ラインの安定化が終わったあとに着手)
ゴール
- ループ lowering / PHI 構築の SSOT を
phi_core + LoopFormBuilderに完全に寄せる。- Rust AST → MIR(
MirBuilder/LoopBuilder)と JSON v0 → MIR(json_v0_bridge::lower_loop_stmt)のフロントを整理し、 「どこを直せば loop/PHI の意味論が変わるか」を 1 箇所に明示する。
- Rust AST → MIR(
- 実装者・LLM の混乱ポイントを減らす:
- Stage‑B / 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::Loopsrc/mir/builder_modularized/control_flow.rs::build_loop_statementsrc/mir/builder/control_flow.rs::cf_loopsrc/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_varsStmtV0::Loop { .. } => loop_::lower_loop_stmt(...)src/runner/json_v0_bridge/lowering/loop_.rs::lower_loop_stmt
- ここも LoopForm v2 / phi_core を呼ぶ構造にはなっているが、
- ファイルが AST ルートとは別に分かれている
- 追加ログや一時的なデバッグコードが入りやすく、「どの経路でループが下りているか」分かりづらい状態になりがち。
-
結果として:
- Stage‑B / FuncScannerBox のような「Rust AST 経路」を見たいときに、誤って
loop_.rs側だけを触る、といった混乱が起きやすい。 - 一方で JSON v0 経路は provider (
env.mirbuilder.emit/--program-json-to-mir) で重要なので、急に削除はできない。
- Stage‑B / FuncScannerBox のような「Rust AST 経路」を見たいときに、誤って
スコープ(25.1q でやること)
-
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に一本化すると明言する。 LoopBuilder(Rust AST フロント)とjson_v0_bridge::lower_loop_stmt(JSON フロント)は「薄いアダプタ」に留める方針を書いておく。
- ループ意味論(preheader/header/body/latch/exit、continue/break スナップショット、PHI)の SSOT を
-
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側には分岐や条件を増やさない。
- 余計なデバッグログや独自判定を段階的に削り、やることを
- 目標:
-
ログ・デバッグ経路の整理
HAKO_LOOP_PHI_TRACE/NYASH_LOOPFORM_DEBUGなどのトグルについて:- どのフロント(Rust AST / JSON)からでも同じタグで観測できるようにし、ログの出し場所を整理する。
loop_.rsに残っている「一時的な ALWAYS LOG」などはすでに削除済みだが、今後も dev トレースは必ず env ガード越しに行う。
-
JSON v0 → AST → MirBuilder 統合の検討(設計レベルのみ)
- 将来案として:
ProgramV0を一度 Nyash AST 相当の構造体に変換し、MirBuilderのbuild_loop_statementを再利用する形に寄せる。- これが実現すると、
loop_.rs自体を削除しても LoopForm/PHI の意味論は完全に一箇所(LoopBuilder + phi_core)に集約される。
- 25.1q ではここまでは踏み込まず、「やるならどのフェーズで、どの単位の差分にするか」を設計メモとして残す。
- 将来案として:
スコープ外(25.1q ではやらないこと)
- ループ意味論そのものの変更:
loop(cond){...}の評価順序や break/continue の意味論を変えない。- Stage‑B / Stage‑1 / 自己ホストルートで既に green な LoopForm/SSA テストの挙動は不変とする。
- 新しいループ構文・最適化の追加:
while/for/ range loop など、新構文の導入は別フェーズ(言語拡張側)に任せる。
- JSON v0 スキーマの変更:
StmtV0::Loopなどの JSON 形は既存のまま(schema v0/v1 は維持)。
他フェーズとの関係
-
25.1m(Static Method / LoopForm v2 continue + PHI Fix):
- ここで LoopForm v2 / continue + header PHI は Rust AST 経路でほぼ安定している。
- 25.1q では、その成果を JSON v0 経路にも構造的に反映し、「LoopForm v2 がどこから使われているか」を明示する役割を担う。
-
25.1p(MIR DebugLog 命令):
- DebugLog を使って LoopForm/PHI の ValueId を観測しやすくすることで、25.1q での統一作業時に「AST ルートと JSON ルートの差」を追いやすくする。
- 25.1q は DebugLog 基盤が整っていることを前提に、小さな JSON v0 → MIR のテストケースで CFG/PHI を比較するフェーズとする。
-
25.2(Numeric Microbench / EXE Tuning):
- JSON v0 → MIR → EXE 経路は numeric_core / AotPrep と強く結びついているため、25.1q で LoopForm front を整理しておくと、25.2 でのパフォーマンス解析やバグ調査がやりやすくなる。***