Unify condition lowering logic across Pattern 2/4 with trait-based API. New infrastructure: - condition_lowering_box.rs: ConditionLoweringBox trait + ConditionContext (293 lines) - ExprLowerer implements ConditionLoweringBox trait (+51 lines) Pattern migrations: - Pattern 2 (loop_with_break_minimal.rs): Use trait API - Pattern 4 (loop_with_continue_minimal.rs): Use trait API Benefits: - Unified condition lowering interface - Extensible for future lowering strategies - Clean API boundary between patterns and lowering logic - Zero code duplication Test results: 911/911 PASS (+2 new tests) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
9.7 KiB
Phase 154: MIR CFG 統合 & ブロックレベル unreachable 検出
0. ゴール
hako_check に MIR CFG 情報を取り込み、「到達不能な basic block」を検出する HC020 ルールを追加する。
目的:
- Phase 153 で復活した dead code 検出(メソッド・Box 単位)を、ブロック単位まで細粒度化
- JoinIR/MIR の CFG 情報を hako_check の Analysis IR に統合
- 「unreachable basic block」を検出し、コード品質向上に寄与
1. Scope / Non-scope
✅ やること
-
MIR/CFG 情報のインベントリ
- 現在の MIR JSON v0 に含まれる CFG 情報(blocks, terminators)を確認
- hako_check の Analysis IR に追加すべきフィールドを特定
-
DeadBlockAnalyzerBox の設計(箱化モジュール化)
- Phase 153 の DeadCodeAnalyzerBox パターンを踏襲
- 入力: Analysis IR(CFG 情報付き)
- 出力: 未到達ブロックのリスト
-
hako_check パイプラインへの統合設計
- Analysis IR 生成時に CFG 情報を含める方法を決定
- HC020 ルールの位置付け(HC019 の後に実行)
-
テストケース設計(ブロックレベル)
- 到達不能な if/else 分岐
- 早期 return 後のコード
- 常に false のループ条件
-
実装 & テスト
- DeadBlockAnalyzerBox 実装
- HC020 ルール実装
- スモークテスト作成
-
ドキュメント & CURRENT_TASK 更新
❌ やらないこと
- JoinIR/MIR の意味論を変えない(解析は「読むだけ」)
- 新しい Stage-3 構文を追加しない
- 環境変数を増やさない(CLI フラグ
--dead-blocksのみ)
2. Task 1: MIR/CFG 情報のインベントリ
対象ファイル
src/mir/join_ir/json.rs- JoinIR JSON シリアライズsrc/mir/join_ir_runner.rs- JoinIR 実行src/mir/- MIR 構造定義tools/hako_check/analysis_ir.hako- 現在の Analysis IR 定義
やること
-
MIR JSON v0 の CFG 情報を確認
- blocks 配列の構造
- terminator の種類(Jump, Branch, Return)
- predecessors / successors の有無
-
Analysis IR に追加すべきフィールドを特定
blocks: Array<BlockInfo>?cfg_edges: Array<Edge>?entry_block: BlockId?
-
JoinIR Strict モードでの動作確認
NYASH_JOINIR_STRICT=1で MIR が正しく生成されているか- Phase 150 の代表ケースで CFG 情報が取れるか
成果物
- CFG 情報インベントリ結果の記録
3. Task 2: DeadBlockAnalyzerBox の設計(箱化モジュール化)
目的
Phase 153 の DeadCodeAnalyzerBox パターンを踏襲し、ブロックレベル解析を箱化
方針
- エントリブロックからの到達可能性を DFS/BFS で計算
- 到達しなかったブロックを列挙
- 各ブロックがどの関数に属するかも記録
箱単位の設計
DeadBlockAnalyzerBox として:
- 入力: Analysis IR(CFG 情報付き)
- 出力: 「未到達ブロック」のリスト
API シグネチャ案
static box DeadBlockAnalyzerBox {
method apply_ir(ir, path, out) {
// CFG 情報を取得
local blocks = ir.get("blocks")
local edges = ir.get("cfg_edges")
local entry = ir.get("entry_block")
// 到達可能性解析
local reachable = me._compute_reachability(entry, edges)
// 未到達ブロックを検出
me._report_unreachable_blocks(blocks, reachable, path, out)
}
method _compute_reachability(entry, edges) {
// DFS/BFS で到達可能なブロックを収集
// return: Set<BlockId>
}
method _report_unreachable_blocks(blocks, reachable, path, out) {
// 到達不能なブロックを HC020 として報告
}
}
出力フォーマット
[HC020] Unreachable basic block: fn=Main.main bb=10 (after early return)
[HC020] Unreachable basic block: fn=Foo.bar bb=15 (if false branch never taken)
成果物
- DeadBlockAnalyzerBox の設計(API シグネチャ)
- Analysis IR 拡張フィールド決定
4. Task 3: hako_check パイプラインへの統合設計
目的
HC020 ルールを既存の hako_check パイプラインに統合
やること
-
Analysis IR 生成の拡張
tools/hako_check/analysis_ir.hakoを拡張- CFG 情報(blocks, edges, entry_block)を含める
-
CLI フラグ追加
--dead-blocksフラグで HC020 を有効化- または
--dead-codeに統合(ブロックレベルも含む)
-
ルール実行順序
- HC019(dead code)の後に HC020(dead blocks)を実行
- または
--rules dead_blocksで個別指定可能に
設計方針
Option A: --dead-code に統合
# HC019 + HC020 を両方実行
./tools/hako_check.sh --dead-code target.hako
Option B: 別フラグ
# HC019 のみ
./tools/hako_check.sh --dead-code target.hako
# HC020 のみ
./tools/hako_check.sh --dead-blocks target.hako
# 両方
./tools/hako_check.sh --dead-code --dead-blocks target.hako
推奨: Option A(ユーザーは「dead code」を広義に捉えるため)
成果物
- パイプライン統合設計
- CLI フラグ仕様確定
5. Task 4: テストケース設計(ブロックレベル)
テストケース一覧
Case 1: 早期 return 後のコード
static box TestEarlyReturn {
test(x) {
if x > 0 {
return 1
}
// ここに到達不能コード
local unreachable = 42 // HC020 検出対象
return unreachable
}
}
Case 2: 常に false の条件
static box TestAlwaysFalse {
test() {
if false {
// このブロック全体が到達不能
return 999 // HC020 検出対象
}
return 0
}
}
Case 3: 無限ループ後のコード
static box TestInfiniteLoop {
test() {
loop(true) {
// 無限ループ
}
// ここに到達不能
return 0 // HC020 検出対象
}
}
Case 4: break 後のコード(ループ内)
static box TestAfterBreak {
test() {
loop(true) {
break
// break 後のコード
local x = 1 // HC020 検出対象
}
return 0
}
}
成果物
- テスト .hako ファイル 4 本
- 期待される HC020 出力の定義
6. Task 5: 実装 & テスト
実装ファイル
-
tools/hako_check/rules/rule_dead_blocks.hako- 新規作成- DeadBlockAnalyzerBox 実装
- HC020 ルール実装
-
tools/hako_check/analysis_ir.hako- 拡張- CFG 情報フィールド追加
-
tools/hako_check/cli.hako- 修正--dead-blocksまたは--dead-code拡張- HC020 実行統合
テストファイル
apps/tests/hako_check/test_dead_blocks_early_return.hakoapps/tests/hako_check/test_dead_blocks_always_false.hakoapps/tests/hako_check/test_dead_blocks_infinite_loop.hakoapps/tests/hako_check/test_dead_blocks_after_break.hako
スモークスクリプト
tools/hako_check_deadblocks_smoke.sh- HC020 スモークテスト
成果物
- DeadBlockAnalyzerBox 実装
- HC020 ルール実装
- テストケース 4 本
- スモークスクリプト
7. Task 6: ドキュメント & CURRENT_TASK 更新
ドキュメント更新
-
phase154_mir_cfg_deadblocks.md に:
- 実装結果を記録
- CFG 統合の最終設計
-
hako_check_design.md を更新:
- HC020 ルールの説明
- CFG 解析機能の説明
-
CURRENT_TASK.md:
- Phase 154 セクションを追加
-
CLAUDE.md:
- hako_check ワークフローに
--dead-blocks追記(必要なら)
- hako_check ワークフローに
成果物
- 各種ドキュメント更新
- git commit
✅ 完成チェックリスト(Phase 154)
- Task 1: MIR/CFG 情報インベントリ完了
- CFG 構造確認
- Analysis IR 拡張フィールド決定
- Task 2: DeadBlockAnalyzerBox 設計
- API シグネチャ決定
- 到達可能性アルゴリズム決定
- Task 3: パイプライン統合設計
- CLI フラグ仕様確定
- ルール実行順序確定
- Task 4: テストケース設計
- テスト .hako 4 本設計
- Task 5: 実装 & テスト
- DeadBlockAnalyzerBox 実装
- HC020 ルール実装
- テストケース実装
- スモークスクリプト作成
- Task 6: ドキュメント更新
- phase154_mir_cfg_deadblocks.md 確定版
- hako_check_design.md 更新
- CURRENT_TASK.md 更新
- git commit
技術的考慮事項
JoinIR Strict モードとの整合性
Phase 150 で確認済みの代表ケースで CFG 情報が取れることを確認:
peek_expr_block.hako- match 式、ブロック式loop_min_while.hako- ループ変数、Entry/Exit PHIjoinir_min_loop.hako- break 制御joinir_if_select_simple.hako- 早期 return
Analysis IR の CFG 拡張案
{
"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"}
]
}
]
}
}
次のステップ
Phase 154 完了後:
- Phase 155+: より高度な解析(定数畳み込み、型推論など)
- Phase 160+: .hako JoinIR/MIR 移植章
作成日: 2025-12-04 Phase: 154(MIR CFG 統合 & ブロックレベル unreachable 検出) Status: Historical