Files
hakorune/docs/development/roadmap/phases/phase-25.3-funcscanner/README.md
nyash-codex 461bdec45a feat(phi): Step 5-5-H完了 - Phantom block検証+PHI決定性向上
 Step 5-5-H: exit_preds検証でphantom block除外
  - loop_snapshot_merge.rs line 268: CFG実在チェック追加

 PHI生成決定性向上(4ファイル)
  - HashMap/HashSet → BTreeMap/BTreeSet変換
  - if_phi.rs, loop_phi.rs, loop_snapshot_merge.rs, loopform_builder.rs

 根本原因分析完了(Task先生調査)
  - ValueId変動の真因: HashMap非決定的イテレーション
  - 詳細: docs/development/current/main/valueid-*.md

📊 テスト結果: 267/268 PASS(退行なし)
  - mir_funcscanner_skip_ws: 非決定性残存(variable_map由来)
  - 後続タスクで対応予定

🎉 PHI Bug Option C実装ほぼ完了!

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 17:10:03 +09:00

169 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 25.3 — FuncScanner / StageB 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` が含まれること(箱レベルの振る舞いが安定)。
- StageB 側からも同じ結果が得られる:
- `tools/smokes/v2/profiles/quick/core/phase251/stageb_fib_program_defs_canary_vm.sh` を実行すると、
- `defs``TestBox.fib` が存在し、
- その `body``Loop` ノードが含まれていること。
- Loop/PHI の意味論は **LoopFormBuilder + LoopSnapshotMergeBox** に完全委譲したまま、
- FuncScanner / StageB は「テキストスキャンJSON 組み立て」の箱として綺麗に分離された状態にする。
## すでに前提としている状態
- LoopForm v2 / PHI / snapshot:
- ループ構造・PHI・break/continue スナップショットの意味論は、
- `src/mir/loop_builder.rs`
- `src/mir/phi_core/loopform_builder.rs`
- `src/mir/phi_core/loop_snapshot_merge.rs`
に集約されており、AST ルート / JSON ルートともに同じ実装を使っている。
- canonical `continue_merge` ブロック(ループごとに 1 つが導入済みで、backedge は
- `latch``header`
- `continue_merge``header`
の 2 本に限定されている。
- 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/continuebodylocal exit に対して MIR 検証が通っている。
この Phase 25.3 では、「LoopForm / JSON front は触らずに、FuncScanner / StageB ラインをその上に綺麗に載せる」ことが目的になる。
## タスク一覧
### 1. FuncScanner fib 最小ハーネスSSA バグの確認完了)
- 対象:
- `lang/src/compiler/tests/funcscanner_fib_min.hako`
- `FuncScannerBox.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 バグの根治」は完了とみなし、
以降は StageB 側の defs 欠落(`defs=[]`)を主ターゲットとする。
- 追加の SSA ガードme-call 周り):
- Rust 側では `MirBuilder::handle_me_method_call``MeCallPolicyBox` によって箱化し、
- `Box.method/Arity` lowered 関数が存在する場合は、従来どおり `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 的に安全になっている。
### 2.5. MIR ロガー (__mir__) による観測Dev 専用)
- 位置づけ:
- Phase 25.3 では、FuncScanner / StageB のような `.hako` 側ロジックを LoopForm v2 上でデバッグしやすくするため、
専用の MIR ログ構文 `__mir__` を導入する(実行意味論には影響しない dev 専用 Hook
- 構文:
- `__mir__.log("label", v1, v2, ...)`
- lowering 時に `MirInstruction::DebugLog { message: "label", values: [v1, v2, ...] }` へ変換される。
- `__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 命令追加するだけの観測レイヤ。
- 実装ポイント:
- `src/mir/builder/calls/build.rs` 内の `build_method_call_impl` で、
- receiver が `__mir__``__mir__.log/mark` を検出し、
- `try_build_mir_debug_call``DebugLog` 命令に直接 lowering している。
FuncScanner / StageB のデバッグ時には、`scan_all_boxes` のループ頭や `box` 検出直後に
`__mir__.log("funcscan/head", i, in_str, in_block)` などを埋め込み、VM 実行ログと合わせて
「どの経路で環境スナップショットやステートが崩れているか」を観測する想定だよ。
### 3. StageB FuncScanner との整合性確保(主ターゲット)
- 対象:
- `lang/src/compiler/entry/compiler_stageb.hako`
- `StageBFuncScannerBox.scan_all_boxes`
- `StageBFuncScannerBox._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 ではなく、StageB が fib ソースから defs を組み立てきれていないこと」なので、
ループ構造や LoopForm には手を入れず、StageB 側のテキスト処理と defs 生成パスを中心に見る。
### 4. fib defs canary & ドキュメント更新
- 対象:
- `tools/smokes/v2/profiles/quick/core/phase251/stageb_fib_program_defs_canary_vm.sh`
- `docs/development/roadmap/phases/phase-25.1q/README.md`
- `CURRENT_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 / StageB defs もこの土台の上に載せた」
というつながりを 1〜2 行で追記する。
- `CURRENT_TASK.md` には:
- Phase 25.3 のタスク完了状況FuncScanner fib / StageB fib canary 緑)と、
- その後に繋がる Stage1 UsingResolver / Stage1 CLI selfhost ラインへのブリッジ
を短く整理しておく。
### 5. mir_funcscanner_skip_ws 系テストの扱いflaky → dev 専用)
- LoopForm v2 + LoopSnapshotMergeBox + PHI まわりの BTreeSet/BTreeMap 化により、
ループ/PHI 関連の 267 テストはすべて安定して緑になっている。
- 一方で、`FuncScannerBox.skip_whitespace/2` を経由する最小 VM ハーネスだけが、
ValueId / BasicBlockId の非決定的な揺れを見せるケースが 1 本だけ残っている。
- Rust 側では `__pin$` の variable_map への混入を禁止しStep 5-5-F/G
PHI 生成側の順序もすべて BTree* で決定化済み。
- 残る非決定性は `MirBuilder::variable_map: HashMap<String, ValueId>`
BoxCompilationContext 内の `variable_map` による iteration 順序依存の可能性が高い。
- Phase 25.3 のスコープでは MirBuilder 全体を BTreeMap 化する広域変更は行わず、
当該テストは `mir_funcscanner_skip_ws_vm_debug_flaky` として `#[ignore]` 付き dev ハーネスに格下げした。
- 通常の `cargo test` では実行されず、必要なときだけ手動で有効化して
VM + `__mir__` ログを観測する用途に限定する。
- 将来フェーズBoxCompilationContext / variable_map 構造の見直し)で、
完全決定性まで含めた根治を行う。
---
この Phase 25.3 は、
- LoopForm v2 / JSON front を「箱として完成済み」とみなし、
- その上で FuncScanner / StageB defs ラインを **構造的に**安定させる
ための仕上げフェーズだよ。
ループや PHI の意味論は触らず、テキストスキャンとスコープ設計を整えることで、selfhosting ライン全体の足場を固めるのが狙い。+