# Phase 155: MIR CFG データブリッジ実装 ## 0. ゴール **Phase 154 で設計した DeadBlockAnalyzerBox を、実際に MIR CFG データで動かすための「データブリッジ」を実装する。** 目的: - Rust MIR → Analysis IR へ CFG データを抽出・変換 - `extract_mir_cfg()` builtin 関数を実装 - HC020(unreachable basic block 検出)を完全に動作させる --- ## 実装状況 (2025-12-04) ### ✅ 完了項目 1. **MIR JSON への CFG 追加** (Phase 155-1) - `src/runner/mir_json_emit.rs` を修正 - `extract_cfg_info()` を MIR JSON 出力時に呼び出し - CFG データを JSON の `cfg` フィールドとして出力 - v0/v1 両フォーマット対応 2. **Analysis IR への CFG フィールド追加** (Phase 155-2 MVP) - `tools/hako_check/analysis_consumer.hako` を修正 - 空の CFG 構造体を Analysis IR に追加(暫定実装) - DeadBlockAnalyzerBox が `ir.get("cfg")` で CFG にアクセス可能 ### 🔄 未完了項目(今後の実装) 3. **実際の CFG データ連携** - MIR JSON から CFG を読み込む処理が未実装 - 現在は空の CFG 構造体のみ(ブロック情報なし) - HC020 はスキップされる(CFG functions が空のため) 4. **builtin 関数の実装** - `extract_mir_cfg()` builtin 関数は未実装 - Phase 155 指示書では builtin 関数経由を想定 - 現状では Rust 側で CFG を MIR JSON に含めるのみ --- ## 1. 背景:Phase 154 の現状 ### 何が完了したか - ✅ DeadBlockAnalyzerBox (HC020 ルール) - ✅ CLI フラグ `--dead-blocks` - ✅ テストケース 4 本 - ✅ スモークスクリプト ### 何が残っているか(このフェーズ) - 🔄 **CFG データブリッジ** - MIR JSON から CFG 情報を抽出 - Analysis IR の `cfg` フィールドに追加 - `.hako` コード内で呼び出し可能にする --- ## 2. Scope / Non-scope ### ✅ やること 1. **Rust 側:CFG 抽出機能** - `src/mir/cfg_extractor.rs` からの CFG 抽出(既に Phase 154 で作成済み) - `extract_mir_cfg()` builtin 関数を作成 - JSON シリアライズ対応 2. **.hako 側:Analysis IR 拡張** - `tools/hako_check/analysis_ir.hako` を拡張 - `cfg` フィールドを Analysis IR に追加 - `analysis_consumer.hako` から `extract_mir_cfg()` を呼び出し 3. **CLI 統合** - hako_check の `--dead-blocks` フラグで HC020 実行時に CFG が利用される - スモークテストで HC020 出力を確認 4. **テスト & 検証** - Phase 154 の 4 テストケースすべてで HC020 出力確認 - スモークスクリプト成功確認 ### ❌ やらないこと - Phase 154 の HC020 ロジック修正(既に完成) - 新しい解析ルール追加(Phase 156+ へ) - CFG 可視化(DOT 出力など) --- ## 3. 技術概要 ### 3.1 データフロー ``` MIR JSON (Phase 154 作成済み) ↓ extract_mir_cfg() builtin (Rust) ← このフェーズで実装 ↓ cfg: { functions: [...] } (JSON) ↓ analysis_consumer.hako (呼び出し側) ↓ Analysis IR (cfg フィールド付き) ↓ DeadBlockAnalyzerBox (HC020) ↓ HC020 出力 ``` ### 3.2 Analysis IR 拡張案 ```json { "methods": [...], "calls": [...], "boxes": [...], "entrypoints": [...], "cfg": { "functions": [ { "name": "Main.main", "entry_block": 0, "blocks": [ { "id": 0, "successors": [1, 2], "terminator": "Branch" }, { "id": 1, "successors": [3], "terminator": "Jump" }, { "id": 2, "successors": [3], "terminator": "Jump" }, { "id": 3, "successors": [], "terminator": "Return" } ] } ] } } ``` --- ## 4. Task 1: extract_mir_cfg() builtin 関数実装 ### 対象ファイル - `src/mir/cfg_extractor.rs` - 既存(Phase 154 作成済み) - `src/runtime/builtin_functions.rs` または `src/runtime/builtin_registry.rs` - builtin 登録 - `src/mir/mod.rs` - モジュール露出 ### やること 1. **extract_mir_cfg() 関数を実装** - 入力:MIR Function オブジェクト - 出力:CFG JSON オブジェクト - 実装例: ```rust pub fn extract_mir_cfg(function: &MirFunction) -> serde_json::Value { let blocks: Vec<_> = function.blocks.values().map(|block| { serde_json::json!({ "id": block.id.0, "successors": get_successors(block), "terminator": format!("{:?}", block.terminator) }) }).collect(); serde_json::json!({ "name": "...", // 関数名は別途指定 "entry_block": 0, "blocks": blocks }) } ``` 2. **Builtin Registry に登録** - 関数シグネチャ:`extract_mir_cfg(mir_json: Object) -> Object` - JoinIR ビルダーから呼び出し可能に 3. **テスト** - 単体テスト作成:`test_extract_mir_cfg_simple()` - 複数ブロック、分岐、ループ対応確認 ### 成果物 - `extract_mir_cfg()` builtin 実装 - Builtin 登録完了 - ユニットテスト --- ## 5. Task 2: analysis_consumer.hako 修正 ### 対象ファイル - `tools/hako_check/analysis_consumer.hako` ### やること 1. **MIR JSON を受け取り、CFG を抽出** ```hako method apply_ir(ir, options) { // ... 既存処理 ... // CFG 抽出(新規) local cfg_data = me.extract_cfg_from_ir(ir) // Analysis IR に cfg を追加 ir.set("cfg", cfg_data) } method extract_cfg_from_ir(ir) { // builtin extract_mir_cfg() 呼び出し // または直接 JSON 操作 local functions = ir.get("functions") local cfg_functions = ... return cfg_functions } ``` 2. **HC020 実行時に CFG が利用される確認** - DeadBlockAnalyzerBox が `ir.cfg` を参照 ### 成果物 - `analysis_consumer.hako` 修正 - CFG 抽出ロジック統合 --- ## 6. Task 3: 統合テスト & 検証 ### テスト項目 1. **Phase 154 の 4 テストケース全て実行** ```bash ./tools/hako_check_deadblocks_smoke.sh --with-cfg ``` 2. **期待される HC020 出力** ``` [HC020] Unreachable basic block: fn=TestEarlyReturn.test bb=2 [HC020] Unreachable basic block: fn=TestAlwaysFalse.test bb=1 [HC020] Unreachable basic block: fn=TestInfiniteLoop.test bb=2 [HC020] Unreachable basic block: fn=TestAfterBreak.test bb=2 ``` 3. **スモークスクリプト更新** - CFG ブリッジ有効時の出力確認 - HC019 + HC020 の両方が実行される確認 ### 成果物 - 統合テスト結果 - スモークスクリプト成功 --- ## 7. Task 4: ドキュメント & CURRENT_TASK 更新 ### ドキュメント 1. **phase155_mir_cfg_bridge.md** に: - 実装結果を記録 - データフロー図 - テスト結果 2. **CURRENT_TASK.md**: - Phase 154 完了記録 - Phase 155 完了記録 - Phase 156 への推奨 ### git commit ``` feat(hako_check): Phase 155 MIR CFG data bridge implementation 🌉 CFG データブリッジ完成! 🔗 実装内容: - extract_mir_cfg() builtin 関数(Rust) - analysis_consumer.hako 修正(.hako) - HC020 完全動作確認 ✅ テスト結果: 4/4 PASS - TestEarlyReturn - TestAlwaysFalse - TestInfiniteLoop - TestAfterBreak 🎯 Phase 154 + 155 で hako_check HC020 ルール完全実装! ``` --- ## ✅ 完成チェックリスト(Phase 155) - [ ] Task 1: extract_mir_cfg() builtin 実装 - [ ] 関数実装 - [ ] Builtin 登録 - [ ] ユニットテスト - [ ] Task 2: analysis_consumer.hako 修正 - [ ] CFG 抽出ロジック統合 - [ ] DeadBlockAnalyzerBox との連携確認 - [ ] Task 3: 統合テスト & 検証 - [ ] 4 テストケース全て HC020 出力確認 - [ ] スモークスクリプト成功 - [ ] Task 4: ドキュメント & CURRENT_TASK 更新 - [ ] 実装ドキュメント完成 - [ ] git commit --- ## 技術的考慮事項 ### CFG 抽出の鍵 - **Entry Block**: 関数の最初のブロック(多くの場合 block_id = 0) - **Successors**: terminator から判定 - `Jump { target }` → 1 successor - `Branch { then_bb, else_bb }` → 2 successors - `Return` → 0 successors - **Reachability**: DFS で entry から到達可能なブロックを収集 ### .hako での JSON 操作 ```hako // JSON オブジェクト生成 local cfg_obj = {} cfg_obj.set("name", "Main.main") cfg_obj.set("entry_block", 0) // JSON 配列操作 local blocks = [] blocks.push(block_info) cfg_obj.set("blocks", blocks) ``` --- ## 次のステップ Phase 155 完了後: - **Phase 156**: HC021(定数畳み込み検出) - **Phase 157**: HC022(型不一致検出) --- ## 参考リソース - **Phase 154**: `docs/development/current/main/phase154_mir_cfg_deadblocks.md` - **MIR CFG 抽出**: `src/mir/cfg_extractor.rs` (Phase 154 で作成済み) - **Analysis IR 定義**: `tools/hako_check/analysis_ir.hako` - **DeadBlockAnalyzerBox**: `tools/hako_check/rules/rule_dead_blocks.hako` --- **作成日**: 2025-12-04 **Phase**: 155(MIR CFG データブリッジ実装) **予定工数**: 2-3 時間 **難易度**: 低(主に plumbing) --- ## Phase 155 MVP 実装詳細 ### 実装アプローチ **Phase 155-1: MIR JSON に CFG を含める** ✅ 完了 - 場所: `src/runner/mir_json_emit.rs` - 変更: `emit_mir_json_for_harness()` と `emit_mir_json_for_harness_bin()` - 処理: ```rust // Phase 155: Extract CFG information for hako_check let cfg_info = nyash_rust::mir::extract_cfg_info(module); let root = if use_v1_schema { let mut root = create_json_v1_root(json!(funs)); if let Some(obj) = root.as_object_mut() { obj.insert("cfg".to_string(), cfg_info); } root } else { json!({"functions": funs, "cfg": cfg_info}) }; ``` **Phase 155-2: Analysis IR に CFG フィールド追加** ✅ MVP 完了 - 場所: `tools/hako_check/analysis_consumer.hako` - 変更: `build_from_source_flags()` の最後に CFG フィールドを追加 - 処理: ```hako // Phase 155: Add mock CFG data for MVP (will be replaced with actual MIR CFG extraction) // For now, create empty CFG structure so DeadBlockAnalyzerBox doesn't crash local cfg = new MapBox() local cfg_functions = new ArrayBox() cfg.set("functions", cfg_functions) ir.set("cfg", cfg) ``` ### MVP の制限事項 1. **CFG データは空** - MIR JSON に CFG は含まれるが、hako_check は読み込まない - Analysis IR の `cfg.functions` は空配列 - DeadBlockAnalyzerBox は実行されるが、検出結果は常に 0 件 2. **MIR 生成パスが未統合** - hako_check は現在ソース解析のみ(AST ベース) - MIR 生成・読み込みパスがない - MIR JSON ファイルを中間ファイルとして使う設計が必要 3. **builtin 関数なし** - `extract_mir_cfg()` builtin 関数は未実装 - .hako から Rust 関数を直接呼び出す仕組みが未整備 ### 次のステップ(Phase 156 or 155.5) **Option A: hako_check に MIR パイプライン統合** 1. hako_check.sh で MIR JSON を生成 2. cli.hako で MIR JSON を読み込み 3. CFG を Analysis IR に反映 4. HC020 が実際にブロックを検出 **Option B: builtin 関数経由** 1. Rust 側で builtin 関数システムを実装 2. `extract_mir_cfg(mir_json)` を .hako から呼び出し可能に 3. analysis_consumer.hako で MIR JSON を処理 **推奨**: Option A(よりシンプル、既存の hakorune_emit_mir.sh を活用) --- ## テスト結果 ### 基本動作確認 ```bash # MIR JSON に CFG が含まれることを確認 $ ./tools/hakorune_emit_mir.sh test.hako /tmp/test.json $ jq '.cfg.functions[0].blocks' /tmp/test.json # → CFG ブロック情報が出力される ✅ ``` ### hako_check 実行 ```bash $ ./tools/hako_check.sh apps/tests/hako_check/test_dead_blocks_early_return.hako # → エラーなく実行完了 ✅ # → HC020 出力なし(CFG が空のため)✅ 期待通り ``` --- ## まとめ Phase 155 MVP として以下を達成: - ✅ MIR JSON に CFG データを追加(Rust 側) - ✅ Analysis IR に CFG フィールドを追加(.hako 側) - ✅ DeadBlockAnalyzerBox が CFG にアクセス可能な構造 今後の課題: - 🔄 MIR JSON → Analysis IR のデータ連携 - 🔄 hako_check の MIR パイプライン統合 または builtin 関数実装 Phase 154 + 155 により、HC020 の基盤は完成。実際の検出機能は Phase 156 で実装推奨。 --- **実装日**: 2025-12-04 **実装者**: Claude (AI Assistant) **コミット**: feat(hako_check): Phase 155 MIR CFG data bridge (MVP)