**FuncScanner .hako 側改善**: - scan_all_boxes を Region + next_i 形式に統一(continue 多発による SSA/PHI 複雑さ削減) - インデント修正(タブ→スペース統一) - デバッグ print 削除 **SSA テスト追加**: - lang/src/compiler/tests/funcscanner_scan_methods_min.hako - src/tests/mir_funcscanner_ssa.rs (scan_methods & fib_min SSA デバッグテスト) **Phase 25.3 ドキュメント**: - docs/development/roadmap/phases/phase-25.3-funcscanner/ 追加 **関連**: Phase 25.3 FuncScanner 箱化準備作業 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Phase 25.3 — FuncScanner / Stage‑B defs 安定化
スコープ / ゴール
-
対象レイヤ
.hako側:lang/src/compiler/entry/func_scanner.hako(FuncScannerBox)lang/src/compiler/entry/compiler_stageb.hako(StageBFuncScannerBox,StageBDriverBox)- 必要に応じて
lang/src/compiler/tests/funcscanner_fib_min.hakoなどのテスト用ハーネス
- Rust 側:
- 既存の LoopForm v2 / LoopSnapshotMergeBox / JSON front は「完成済みの土台」として利用するだけで、原則ここでは触らない。
-
ゴール
- Rust VM 検証付きで FuncScanner を安定させる:
NYASH_VM_VERIFY_MIR=1でlang/src/compiler/tests/funcscanner_fib_min.hakoを実行したときに、FuncScannerBox.scan_all_boxes/1で Undefined value が発生しないこと。- fib 風ソースに対して
defsにTestBox.fib/Main.mainが含まれること(箱レベルの振る舞いが安定)。
- Stage‑B 側からも同じ結果が得られる:
tools/smokes/v2/profiles/quick/core/phase251/stageb_fib_program_defs_canary_vm.shを実行すると、defsにTestBox.fibが存在し、- その
bodyにLoopノードが含まれていること。
- Loop/PHI の意味論は LoopFormBuilder + LoopSnapshotMergeBox に完全委譲したまま、
- FuncScanner / Stage‑B は「テキストスキャン+JSON 組み立て」の箱として綺麗に分離された状態にする。
- Rust VM 検証付きで FuncScanner を安定させる:
すでに前提としている状態
-
LoopForm v2 / PHI / snapshot:
- ループ構造・PHI・break/continue スナップショットの意味論は、
src/mir/loop_builder.rssrc/mir/phi_core/loopform_builder.rssrc/mir/phi_core/loop_snapshot_merge.rsに集約されており、AST ルート / JSON ルートともに同じ実装を使っている。
- canonical
continue_mergeブロック(ループごとに 1 つ)が導入済みで、backedge はlatch→headercontinue_merge→headerの 2 本に限定されている。
- ループ構造・PHI・break/continue スナップショットの意味論は、
-
JSON v0 front:
src/runner/json_v0_bridge/lowering/loop_.rsは LoopForm v2 の 薄いアダプタになっている。- ブロック ID の確保
vars/ snapshot の受け渡しLoopFormOps実装 (LoopFormJsonOps) だけを担い、PHI 生成は LoopForm v2 に一元化された。
-
25.1e / 25.1q / 25.2:
- 変数スコープ(Carrier / Pinned / Invariant / BodyLocalInOut)と Env_in/Env_out モデルは文書と実装が一致している。
- JSON ループ用のスモーク(
tests/json_program_loop.rs)はすでに緑で、ループ+break/continue+body‑local exit に対して MIR 検証が通っている。
この Phase 25.3 では、「LoopForm / JSON front は触らずに、FuncScanner / Stage‑B ラインをその上に綺麗に載せる」ことが目的になる。
タスク一覧
1. FuncScanner fib 最小ハーネス(SSA バグの確認完了)
-
対象:
lang/src/compiler/tests/funcscanner_fib_min.hakoFuncScannerBox.scan_all_boxes/1(Rust lowering 時の MIR)
-
現状:
NYASH_VM_VERIFY_MIR=1付きでfuncscanner_fib_min.hakoを実行しても、
Undefined value /ssa-undef-debugは発生していない(LoopForm v2 / LoopSnapshotMergeBox 修正で解消済み)。cargo test mir_funcscanner_fib_min_ssa_debugも緑で、FuncScanner 単体の SSA 破綻は再現しない。- このフェーズで導入した
__mir__ロガーは、今後の再現時に経路観測用フックとして利用できる状態になっている。
-
位置づけ:
- 「FuncScanner + LoopForm v2 での Undefined Value バグの根治」は完了とみなし、
以降は Stage‑B 側の defs 欠落(defs=[])を主ターゲットとする。
- 「FuncScanner + LoopForm v2 での Undefined Value バグの根治」は完了とみなし、
-
追加の SSA ガード(me-call 周り):
- Rust 側では
MirBuilder::handle_me_method_callをMeCallPolicyBoxによって箱化し、Box.method/Aritylowered 関数が存在する場合は、従来どおりmeを先頭引数とする Global call(インスタンス文脈の me-call)。- 存在しない場合は、
handle_static_method_call(cls, method, arguments)にフォールバックし、
static helper(FuncScannerBox._parse_params/_strip_commentsなど)への呼び出しとして扱うようにした。
- これにより、static box 文脈で「実体のない me を receiver とする Method call」が生成される経路が閉じられ、
FuncScannerBox._scan_methods/4 +_parse_params+_strip_commentsのラインは SSA 的に安全になっている。
- Rust 側では
2.5. MIR ロガー (mir) による観測(Dev 専用)
- 位置づけ:
- Phase 25.3 では、FuncScanner / Stage‑B のような
.hako側ロジックを LoopForm v2 上でデバッグしやすくするため、 専用の MIR ログ構文__mir__を導入する(実行意味論には影響しない dev 専用 Hook)。
- Phase 25.3 では、FuncScanner / Stage‑B のような
- 構文:
__mir__.log("label", v1, v2, ...)- lowering 時に
MirInstruction::DebugLog { message: "label", values: [v1, v2, ...] }へ変換される。
- lowering 時に
__mir__.mark("label")- 値無し版の
DebugLogとしてdebug_log "label"だけを差し込む。
- 値無し版の
- 振る舞い:
- VM 実行時は
NYASH_MIR_DEBUG_LOG=1のときだけ[MIR-LOG] label: %id=value ...の形式でログ出力され、それ以外のときは完全に無視される(Effect::Debug のみ)。
- LoopForm / PHI / snapshot には関与せず、単に MIR に 1 命令追加するだけの観測レイヤ。
- VM 実行時は
- 実装ポイント:
src/mir/builder/calls/build.rs内のbuild_method_call_implで、- receiver が
__mir__の__mir__.log/markを検出し、 try_build_mir_debug_callでDebugLog命令に直接 lowering している。
- receiver が
FuncScanner / Stage‑B のデバッグ時には、scan_all_boxes のループ頭や box 検出直後に
__mir__.log("funcscan/head", i, in_str, in_block) などを埋め込み、VM 実行ログと合わせて
「どの経路で環境スナップショットやステートが崩れているか」を観測する想定だよ。
3. Stage‑B FuncScanner との整合性確保(主ターゲット)
-
対象:
lang/src/compiler/entry/compiler_stageb.hakoStageBFuncScannerBox.scan_all_boxesStageBFuncScannerBox._find_matching_brace他StageBDriverBox.main内の defs 組み立てロジック
-
やること:
StageBFuncScannerBoxのロジックを、可能な範囲でFuncScannerBoxと共有・委譲する方向に寄せる。_find_matching_braceなどはすでに FuncScannerBox に委譲済みなので、 残りのスキャンロジックも「同じアルゴリズム / 同じ境界条件」で動くように整理する。
HAKO_STAGEB_FUNCSCAN_TEST=1でStageBFuncScannerBox.test_fib_scan()を走らせ、brace1/brace2の close_idx が正しく取れること。defs_len > 0となり、TestBox.fib/Main.mainがログに出ること。
- そのうえで
StageBDriverBox.mainがStageBFuncScannerBox.scan_all_boxes(src)の結果を- Program(JSON v0).defs に正しく注入できているかを確認する。
- ここでの主なバグは「SSA ではなく、Stage‑B が fib ソースから defs を組み立てきれていないこと」なので、
ループ構造や LoopForm には手を入れず、Stage‑B 側のテキスト処理と defs 生成パスを中心に見る。
4. fib defs canary & ドキュメント更新
-
対象:
tools/smokes/v2/profiles/quick/core/phase251/stageb_fib_program_defs_canary_vm.shdocs/development/roadmap/phases/phase-25.1q/README.mdCURRENT_TASK.md
-
やること:
- canary スクリプトで:
Program.kind == "Program"defsにTestBox.fibが存在すること。TestBox.fib.bodyにLoopノードが含まれること。 を満たした状態でrc=0になるまで確認する。
- Phase 25.1q / 25.2 の README には、
- 「loop/PHI/スナップショットの SSOT は LoopForm v2 + LoopSnapshotMergeBox」
- 「Phase 25.3 で FuncScanner / Stage‑B defs もこの土台の上に載せた」 というつながりを 1〜2 行で追記する。
CURRENT_TASK.mdには:- Phase 25.3 のタスク完了状況(FuncScanner fib / Stage‑B fib canary 緑)と、
- その後に繋がる Stage‑1 UsingResolver / Stage‑1 CLI self‑host ラインへのブリッジ を短く整理しておく。
- canary スクリプトで:
この Phase 25.3 は、
- LoopForm v2 / JSON front を「箱として完成済み」とみなし、
- その上で FuncScanner / Stage‑B defs ラインを 構造的に安定させる
ための仕上げフェーズだよ。
ループや PHI の意味論は触らず、テキストスキャンとスコープ設計を整えることで、self‑hosting ライン全体の足場を固めるのが狙い。+