refactor(extractors): Phase 282 P9a - CommonExtractionHelpers SSOT統合(スコープ限定版)
# Phase 282 P9a 完了 (Scope-Limited Integration) ## 実装内容 - **common_helpers.rs 作成**: 4グループの共通ヘルパー統合 (316行) - Group 1: Control Flow Counting (count_control_flow - 汎用カウンター) - Group 2: Control Flow Detection (has_break/continue/return_statement) - Group 3: Condition Validation (extract_loop_variable, is_true_literal) - Group 4: Pattern5専用ヘルパー (validate_continue_at_end, validate_break_in_simple_if) - **Pattern統合完了**: Pattern5 → Pattern4 → Pattern2 → Pattern1 - Pattern5: ~90行削減 (5 tests PASS) - Pattern4: ~66行削減 (5 tests PASS) - Pattern2: ~67行削減 (4 tests PASS) - Pattern1: ~28行削減 (3 tests PASS) - Pattern3: 別フェーズに延期(pattern固有ロジック除外) ## 成果 - **コード削減**: ~251行(Pattern3除く、total ~400行見込み) - **テスト**: 40 unit tests PASS (23 common_helpers + 17 extractors) - **スモークテスト**: 45 PASS, 1 pre-existing FAIL(退行ゼロ) - **ビルド警告**: 130 → 120 (-10) ## USER CORRECTIONS適用済み 1. ✅ スコープ限定(共通ロジックのみ、pattern固有除外) 2. ✅ Placeholder禁止(SSOT違反排除) 3. ✅ 統合順序変更(Pattern3を最後/別フェーズへ) ## 追加ドキュメント - Phase 284 計画追加(Return as ExitKind SSOT) - 10-Now.md, 30-Backlog.md 更新 🎯 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -2,13 +2,15 @@
|
||||
|
||||
## Current Focus (next)
|
||||
|
||||
- Phase 283(bugfix): JoinIR if-condition remap fix: `docs/development/current/main/phases/phase-283/README.md`
|
||||
- 目的: Pattern3(if-sum)で `i % 2 == 1` が undefined `ValueId` を生成する不具合を根治する
|
||||
- SSOT: `src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs`(ConditionEnv の正しい使用位置)
|
||||
- Phase 284(design-first): Return as ExitKind SSOT(patternに散らさない)
|
||||
- 目的: `return` を `ExitKind` + `compose::*` / `emit_frag()` に収束させ、pattern側の個別実装を増やさない
|
||||
- 入口: `docs/development/current/main/phases/phase-284/README.md`
|
||||
- 手順: `docs/development/current/main/phases/phase-284/P0-INSTRUCTIONS.md`
|
||||
|
||||
## Recently Completed (2025-12-23)
|
||||
|
||||
- Phase 282(Router shrinkage + extraction-based migration P0–P5): `docs/development/current/main/phases/phase-282/README.md`
|
||||
- Phase 283(bugfix): JoinIR if-condition remap fix: `docs/development/current/main/phases/phase-283/README.md`
|
||||
- Phase 282(Router shrinkage + extraction-based migration + extractor refactor P0–P9a): `docs/development/current/main/phases/phase-282/README.md`
|
||||
- Phase 280(Frag composition SSOT positioning): `docs/development/current/main/phases/phase-280/README.md`
|
||||
- Phase 281(Pattern6/7 compose adoption, P0–P3): `docs/development/current/main/phases/phase-281/README.md`
|
||||
- Phase 273(Plan line SSOT): `docs/development/current/main/phases/phase-273/README.md`
|
||||
|
||||
@ -8,9 +8,21 @@ Related:
|
||||
|
||||
## 直近(JoinIR/selfhost)
|
||||
|
||||
- **Phase 282(planned, design-first): Router shrinkage**
|
||||
- 入口: `docs/development/current/main/phases/phase-282/README.md`
|
||||
- 目的: pattern番号を “症状ラベル” に縮退し、router の責務を「抽出の配線」へ収束させる
|
||||
- **Phase 284(planned, design-first): Return as ExitKind SSOT(patternに散らさない)**
|
||||
- 目的: `return` を “pattern最適化の個別実装” にせず、`ExitKind` と `compose::*` / `emit_frag()` に収束させる
|
||||
- ねらい: 移行期間中の「二重ルール」「検出の穴」を減らし、将来の pattern 増殖を防ぐ
|
||||
- 入口: `docs/development/current/main/phases/phase-284/README.md`
|
||||
- P0(docs-only): `docs/development/current/main/phases/phase-284/P0-INSTRUCTIONS.md`
|
||||
- SSOT:
|
||||
- Composition: `src/mir/builder/control_flow/edgecfg/api/compose.rs`
|
||||
- Terminator emission: `emit_frag()`(`src/mir/builder/control_flow/edgecfg/api/emit.rs`)
|
||||
- Frag docs: `docs/development/current/main/design/edgecfg-fragments.md`
|
||||
- 進め方:
|
||||
- P0(docs-only)で “return の意味” と “Ok(None)/Err” の境界を固定
|
||||
- P1+ で Rust/LLVM の実装を SSOT に収束(pattern側に例外実装を増やさない)
|
||||
|
||||
- (✅ done)**Phase 282**: Router shrinkage + detection SSOT + extractor refactor
|
||||
- 完了: `docs/development/current/main/phases/phase-282/README.md`
|
||||
|
||||
(✅ done)**Phase 279 P0**: Type propagation pipeline SSOT 統一(lifecycle / JoinIR / LLVM の二重化解消)
|
||||
- 完了: `docs/development/current/main/phases/phase-279/README.md`
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Phase 282: Router Shrinkage (pattern番号の症状ラベル化)
|
||||
|
||||
Status: Planned (design-first)
|
||||
Status: Active SSOT / ✅ P0–P9a complete (2025-12-23)
|
||||
|
||||
Goal:
|
||||
- pattern番号(Pattern1/2/…)を “症状ラベル(テスト名)” に縮退させ、router の責務を「抽出の配線」へ収束させる。
|
||||
@ -57,10 +57,42 @@ CFG構築は以下に収束させる:
|
||||
- ✅ 正しい用途: テスト名(`loop_if_phi.hako` → Pattern3_WithIfPhi)、debug ログ
|
||||
- ❌ 禁止: CFG 分岐(`if pattern == 6 then ...`)、アーキテクチャ SSOT(Frag composition が SSOT)
|
||||
|
||||
**Detection 戦略**(簡潔版、詳細は P2+ で補完):
|
||||
- **ExtractionBased**(Pattern6/7/8/9): extract() 成功 → match(SSOT 単一)
|
||||
- 注: Pattern8/9 は JoinIR table 経由でも、can_lower 内部で extract を使って判定している(pattern_kind 依存ではない)
|
||||
- **StructureBased**(主に Pattern1-5): ctx.pattern_kind などの事前分類を使う(legacy、SSOT が二重になりやすい)
|
||||
**Detection 戦略**(Phase 282 P3-P7 migration 完了):
|
||||
- **ExtractionBased** (全Pattern統一): extract_*() 成功 → match(SSOT 単一)
|
||||
- Pattern1-5: Phase 282 P3-P7 で ExtractionBased 移行完了
|
||||
- Pattern6/7: Phase 273 Plan-based (extract_*_plan)
|
||||
- Pattern8/9: Phase 259/270 で既に ExtractionBased
|
||||
- pattern_kind: **safety valve のみ**(O(1) perf guard、検出ロジックではない)
|
||||
|
||||
### Pattern Detection SSOT Table (Phase 282 P3-P7 Complete)
|
||||
|
||||
**全Pattern統一ルール**:
|
||||
1. **SSOT = extract**: Extraction 関数が検出の唯一の真実(pattern_kind ではない)
|
||||
2. **Safety valve**: pattern_kind は O(1) 早期reject のみ(検出ロジックに使わない)
|
||||
3. **Re-extract**: lower() は必ず再extract して SSOT 強制(can_lower 通過を信じない)
|
||||
|
||||
| Pattern | SSOT Entrypoint | Safety Valve | Re-extract | Phase |
|
||||
|---------|-----------------|--------------|------------|-------|
|
||||
| **Pattern1** | `extractors/pattern1.rs::extract_*` | `pattern_kind==Minimal` | ✅ | P282 P3 |
|
||||
| **Pattern2** | `extractors/pattern2.rs::extract_*` | `pattern_kind==Basic` | ✅ | P282 P4 |
|
||||
| **Pattern3** | `extractors/pattern3.rs::extract_*` | `pattern_kind==WithIfPhi` | ✅ | P282 P5 |
|
||||
| **Pattern4** | `extractors/pattern4.rs::extract_*` | `pattern_kind==Carrier` | ✅ | P282 P6 |
|
||||
| **Pattern5** | `extractors/pattern5.rs::extract_*` | `pattern_kind==InfiniteEarlyExit` | ✅ | P282 P7 |
|
||||
| **Pattern6** | `pattern6_scan_with_init.rs::extract_scan_with_init_plan()` | (none, Plan-based) | ✅ | P273 P1 |
|
||||
| **Pattern7** | `pattern7_split_scan.rs::extract_split_scan_plan()` | (none, Plan-based) | ✅ | P273 P2 |
|
||||
| **Pattern8** | `pattern8_scan_bool_predicate.rs` (can_lower) | (none, ExtractionBased) | ✅ | P259 |
|
||||
| **Pattern9** | `pattern9_accum_const_loop.rs` (can_lower) | (none, ExtractionBased) | ✅ | P270 |
|
||||
|
||||
**pattern_kind の正しい使い方**:
|
||||
- ✅ **O(1) guard**: `if pattern_kind != Expected { return false }` (perf最適化)
|
||||
- ✅ **Debug logging**: `pattern_kind={:?}` (診断情報)
|
||||
- ❌ **検出ロジック**: `if pattern_kind == X then lower_X()` (禁止、SSOT違反)
|
||||
- ❌ **CFG 分岐**: `match pattern_kind { ... }` (禁止、extract が SSOT)
|
||||
|
||||
**移行完了状態** (Phase 282 P8):
|
||||
- すべての Pattern が extract_*() を SSOT として使用
|
||||
- pattern_kind は早期reject の補助にすぎない
|
||||
- lower() は必ず re-extract して SSOT 強制(二重検証)
|
||||
|
||||
**SSOT 参照**:
|
||||
- Frag composition: `src/mir/builder/control_flow/edgecfg/api/compose.rs`
|
||||
@ -119,6 +151,23 @@ extract_scan_with_init_plan() → Ok(None) for unsupported cases
|
||||
|
||||
## P1 (code, minimal) — 配線の可視化
|
||||
|
||||
## Follow-up (design-first): Return as ExitKind SSOT
|
||||
|
||||
移行期間中に一番 “ズレやすい” のは `return` まわりなので、pattern 個別実装へ散らさず、
|
||||
`ExitKind` + `compose::*` / `emit_frag()` に収束させる方針を別フェーズで扱う。
|
||||
|
||||
- 入口: `docs/development/current/main/30-Backlog.md`(Phase 284)
|
||||
|
||||
## P9a (refactor, behavior-preserving) — Extractor 重複削減(Common helpers)
|
||||
|
||||
Pattern1–5 の extractor が持っていた “再帰カウント/検出/条件ヘルパ” の重複を、pure helper に集約する。
|
||||
|
||||
- 追加: `src/mir/builder/control_flow/joinir/patterns/extractors/common_helpers.rs`
|
||||
- 方針:
|
||||
- **SSOT=extract** は維持(判定は各 pattern extractor の責務)
|
||||
- helper は pure(builder 触らない)・**silent fallback を作らない**
|
||||
- Pattern3 の “if-else PHI” は専用ロジックが多いため、段階的に扱う(P9b 以降)
|
||||
|
||||
- router に “経路ログ” を追加(既定OFF、debugのみに限定)
|
||||
- pattern番号ではなく “entrypoint(Plan/JoinIR)” をログの主語にする
|
||||
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
# Phase 284 P0(docs-only): Return as ExitKind SSOT
|
||||
|
||||
目的: `return` を pattern 個別実装へ散らさず、`ExitKind::Return` と `compose::*` / `emit_frag()` に収束させるための SSOT を固定する。
|
||||
|
||||
## このP0でやること(コード変更なし)
|
||||
|
||||
1. SSOT を 1 枚にまとめる
|
||||
- `docs/development/current/main/phases/phase-284/README.md` を SSOT として整える(用語・責務・境界)。
|
||||
2. 既存SSOTとの整合を取る
|
||||
- Phase 282 の “SSOT=extract / pattern_kind=safety valve / lower re-extract” と矛盾しないこと。
|
||||
3. “移行期間の穴” を塞ぐ言い方にする
|
||||
- close-but-unsupported は `Ok(None)` ではなく `Err`(Fail-Fast)であることを明記。
|
||||
|
||||
## 文書に必ず入れる事項(チェックリスト)
|
||||
|
||||
- [ ] `return expr` は `ExitKind::Return` で表現する(pattern の特例は禁止)
|
||||
- [ ] Return edge の返り値は `EdgeArgs`(または Return 用 args)で運ぶ
|
||||
- [ ] terminator 生成は `emit_frag()` が SSOT(Return も例外なし)
|
||||
- [ ] extractor の返り値境界: `Ok(None)` と `Err` の意味を固定(黙殺禁止)
|
||||
- [ ] Phase 284 の P1+(実装)で “どこを触る” かの導線を箇条書きで残す(ただしコードは書かない)
|
||||
|
||||
## SSOTリンク
|
||||
|
||||
- `docs/development/current/main/phases/phase-284/README.md`
|
||||
- `docs/development/current/main/design/edgecfg-fragments.md`
|
||||
- `src/mir/builder/control_flow/edgecfg/api/compose.rs`
|
||||
- `src/mir/builder/control_flow/edgecfg/api/emit.rs`
|
||||
- `docs/development/current/main/phases/phase-282/README.md`
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
# Phase 284 P1(code): Return as ExitKind SSOT(実装)
|
||||
|
||||
目的: `return` を pattern 固有の特例にせず、`ExitKind::Return` と `compose::*` / `emit_frag()` へ収束させる。
|
||||
|
||||
前提SSOT(P0):
|
||||
- `docs/development/current/main/phases/phase-284/README.md`
|
||||
- Phase 282 の境界ルール(SSOT=extract / close-but-unsupported=Err): `docs/development/current/main/phases/phase-282/README.md`
|
||||
|
||||
## 実装方針(最小)
|
||||
|
||||
### 1) 返り値の運搬(ExitKind::Return + args)
|
||||
|
||||
- `return <expr>` は **`ExitKind::Return` の edge**として表現する。
|
||||
- Return edge が持つ値は `EdgeArgs` で運ぶ(Return terminator の operand)。
|
||||
- terminator は `emit_frag()` が生成する(pattern/box が直に Return 命令を生やさない)。
|
||||
|
||||
### 2) 「移行期間の穴」を消す
|
||||
|
||||
現状は Pattern4/5 などが `return` を `Err(close-but-unsupported)` にしている。
|
||||
P1 のゴールは:
|
||||
- `return` を含む loop-body が “別パターンへ静かに流れる” 状態をなくす
|
||||
- SSOT 経路で `ExitKind::Return` に落ちるようにする
|
||||
|
||||
## 実装タスク(推奨順)
|
||||
|
||||
### Step 1: 現状の `return` ハンドリングを棚卸し(read-only)
|
||||
|
||||
- joinir patterns extractors:
|
||||
- `src/mir/builder/control_flow/joinir/patterns/extractors/pattern4.rs`
|
||||
- `src/mir/builder/control_flow/joinir/patterns/extractors/pattern5.rs`
|
||||
- `return` を Err にしている箇所(close-but-unsupported の根拠)を列挙する
|
||||
|
||||
- control-flow lowering:
|
||||
- `emit_frag()` が Return edge をどう生成しているか確認する(target=None の Return wire/exit)
|
||||
- `compose::cleanup()` の Return wiring が想定どおりか確認する
|
||||
|
||||
成果物: `docs/development/current/main/phases/phase-284/P1-NOTES.md`(短い箇条書きでOK)
|
||||
|
||||
### Step 2: `return` を ExitKind に落とす “単一入口” を作る(root fix)
|
||||
|
||||
狙い:
|
||||
- loop body のどの位置でも `return` が現れたら `ExitKind::Return` で外へ出せること
|
||||
- これを **1 箇所**に寄せる(pattern 側に増やさない)
|
||||
|
||||
実装候補(どれか 1 つに決める):
|
||||
- A) loop lowering(Frag 構築)段で Return edge を first-class で追加
|
||||
- B) JoinIR conversion の merge 段で Return を ExitKind に正規化
|
||||
|
||||
要件:
|
||||
- Fail-Fast: “表現できない return” は Err(silent fallback 禁止)
|
||||
- 既定挙動は変えない(return を含む既存 fixture があれば、その期待値は明示して更新)
|
||||
|
||||
### Step 3: extractor の `return` ポリシーを更新(穴を埋める)
|
||||
|
||||
P1 で Return SSOT が通るようになったら、以下を更新する:
|
||||
- Pattern4/5 の extractor で `return` を **Err にしない**(close-but-unsupported ではなくなるため)
|
||||
- ただし “return があるせいでパターン形状が曖昧になる” 場合は Err を維持(Fail-Fast)
|
||||
|
||||
### Step 4: fixture + smoke(VM/LLVM)で SSOT を固定
|
||||
|
||||
最小 fixture の要件:
|
||||
- `return` が loop の then/else どちらかに現れる
|
||||
- exit code が安定(stdout 抑制の LLVM でも確認できる)
|
||||
|
||||
例(案):
|
||||
- `apps/tests/phase284_p1_return_in_loop_min.hako`
|
||||
- loop 内で条件により `return 7` / `continue` 等
|
||||
- 最終 exit code を 7 に固定
|
||||
|
||||
smoke:
|
||||
- VM: stdout/exit code を検証
|
||||
- LLVM: exit code + harness の `Result: <code>` を検証(stdout が出ない想定)
|
||||
|
||||
## 受け入れ基準
|
||||
|
||||
- `return` を含む loop fixture が VM/LLVM で同一動作
|
||||
- pattern 側に “return の特例 if” が増えていない(root fix のみ)
|
||||
- `Ok(None)` / `Err` の境界が崩れていない(silent fallback なし)
|
||||
|
||||
58
docs/development/current/main/phases/phase-284/README.md
Normal file
58
docs/development/current/main/phases/phase-284/README.md
Normal file
@ -0,0 +1,58 @@
|
||||
# Phase 284: Return as ExitKind SSOT(patternに散らさない)
|
||||
|
||||
Status: Planned (design-first)
|
||||
|
||||
## Goal
|
||||
|
||||
`return` を “pattern 個別の特例” として増やさず、`ExitKind::Return` と `compose::*` / `emit_frag()` に収束させる。
|
||||
移行期間中の検出穴(Ok(None) による黙殺)を消し、Fail-Fast を構造で担保する。
|
||||
|
||||
## SSOT References
|
||||
|
||||
- Frag/ExitKind 設計: `docs/development/current/main/design/edgecfg-fragments.md`
|
||||
- Composition API: `src/mir/builder/control_flow/edgecfg/api/compose.rs`
|
||||
- Terminator emission: `src/mir/builder/control_flow/edgecfg/api/emit.rs`(`emit_frag()`)
|
||||
- Router SSOT(SSOT=extract / safety valve): `docs/development/current/main/phases/phase-282/README.md`
|
||||
|
||||
## Problem(移行期間の弱さ)
|
||||
|
||||
- Pattern 単位で `return` を “未対応” にすると、検出戦略(Ok(None)/Err)次第で **静かに別経路へ落ちる**。
|
||||
- その結果、同じソースでも「どの lowering が `return` を解釈したか」が曖昧になり、SSOT が割れる。
|
||||
|
||||
## Core SSOT(決めること)
|
||||
|
||||
### 1) 返り値の意味(ExitKind)
|
||||
|
||||
- `return expr` は `ExitKind::Return` として表現する。
|
||||
- 返り値(ValueId)は `EdgeArgs` で運ぶ(Return edge が value を持つ)。
|
||||
- Return は **必ず emit 側で terminator になる**(pattern 側で命令を直に生成しない)。
|
||||
|
||||
### 2) Detect の境界(Ok(None) / Err)
|
||||
|
||||
- `Ok(None)`: 一致しない(次の extractor へ)
|
||||
- `Err(...)`: 一致したが未対応(close-but-unsupported)→ **Fail-Fast**
|
||||
|
||||
Phase 284 の完了条件は「`return` を含むケースが close-but-unsupported ではなく SSOT 経路で処理される」状態に寄せること。
|
||||
|
||||
### 3) 実装の集約点(どこに寄せるか)
|
||||
|
||||
- `return` の lowering は **ExitKind + compose + emit_frag** に集約する。
|
||||
- pattern の extractor は “認識” のみ(SSOT=extract)。`return` の解釈ロジックを増やさない。
|
||||
|
||||
## Scope
|
||||
|
||||
### P0(docs-only)
|
||||
|
||||
- `return` を ExitKind として扱う SSOT を文章で固定する(本ファイル + 参照先リンク)。
|
||||
- 移行期間のルール(Ok(None)/Err の境界、黙殺禁止)を Phase 282 と整合させる。
|
||||
|
||||
### P1+(code)
|
||||
|
||||
- `return` を含む loop body を、JoinIR/Plan のどちらの経路でも **同じ ExitKind::Return** に落とす。
|
||||
- VM/LLVM の両方で、`return` を含む fixture を smoke 化して SSOT を固定する。
|
||||
|
||||
## Acceptance
|
||||
|
||||
- P0: `return` の SSOT(ExitKind/compose/emit)と detect 境界が明文化されている
|
||||
- P1+: `return` を含む loop fixture が VM/LLVM で同一結果になり、smoke で固定されている
|
||||
|
||||
Reference in New Issue
Block a user