refactor(edgecfg): add Frag/ExitKind API entrypoint (Phase 264 design-first)

Phase 264 P0: EdgeCFG Fragment 入口API作成(実装置換なし)

- 入口フォルダ作成: src/mir/builder/control_flow/edgecfg/api/
- コア型定義: ExitKind, EdgeStub, Frag
- 合成関数シグネチャ: seq, if_, loop_, cleanup(中身TODO、pub(crate))
- 最小テスト: 3個のユニットテスト追加(frag.rs)
- ドキュメント連動: edgecfg-fragments.md に実装入口追記

制約遵守:
- 既存 pattern6/7/8 未改変
- merge/EdgeCFG 未改変
- 既存LoopId使用(control_form.rs に PartialOrd, Ord 追加)
- MIR側EdgeArgs使用(JoinIRと混線回避)
- BTreeMap採用(決定的順序保証、Phase 69-3 教訓)

次フェーズ: Phase 265 で Pattern8 適用時に compose::loop_ を実装

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-21 12:49:53 +09:00
parent be4de67601
commit 923a442326
12 changed files with 630 additions and 22 deletions

View File

@ -1,24 +1,46 @@
# Self Current Task — Now (main)
## 2025-12-21Phase 263 P0Pattern2 LoopBodyLocal fallback 修正)✅
## 2025-12-21Phase 263 P0.2Pattern2 promotion API SSOT)✅
- **Goal**: Pattern2 で処理できない LoopBodyLocal を検出したら Pattern2 全体を早期終了(部分的な処理続行は禁止)
- **修正内容**:
- `promote_step_box.rs`: 戻り値を `Result<Option<_>, String>` に変更、Reject を二分化(対象外 → Ok(None)、対象だが未対応 → Err
- `pattern2_lowering_orchestrator.rs`: Ok(None) 検出で早期 return
- Fail-Fast 原則: 対象外は Ok(None) で後続経路へ、対象だが未対応は Err で即座に失敗
- **Goal**: Pattern2 の “Reject/continue/fallback の揺れ” を **型 + 入口SSOT**で封じ、部分続行(後段で落ちる)を構造で不可能にする
- **実装**:
- `PromoteDecision::{Promoted, NotApplicable, Freeze}`Option 多重を撤去
- `pattern2/api/` を入口SSOTとして新設し、`try_promote(...)` を **単一参照点**に固定
- **効果**:
- `NotApplicable`**必ず** `Ok(None)` で Pattern2 全体を抜ける(後続経路へ)
- `Freeze`**必ず** Fail-Fastclose-but-unsupported のみ即死)
- **検証結果**:
- cargo test --lib: **1368/1368 PASS** (1367→1368 に改善)
- quick smoke: **45/46 PASS** (大幅改善!)
- エラーメッセージ変化: `[cf_loop/pattern2] Variable not found: seg``[joinir/freeze] Loop lowering failed` (Pattern2 が正しく abort)
- **Commit**: `93022e7e1` - fix(pattern2): abort entire Pattern2 on unpromoted LoopBodyLocal instead of partial execution
- cargo test --lib: **1368/1368 PASS**
- quick smoke: **45/46 PASS**(既知 1 件は別論点)
- **Commits**:
- `abdb860e7`P0.1: PromoteDecision 導入Option 揺れの撤去)
- `e17902a44`P0.2: `pattern2/api/` で入口SSOT物理固定
- **詳細**: `docs/development/current/main/phases/phase-263/README.md`
## 2025-12-21Phase 264 P0EdgeCFG Fragment 入口作成)✅
**目的**: Frag/ExitKind を一次概念にする入口APIを用意実装置換は次フェーズ
**完了内容**:
- 入口フォルダ作成: `src/mir/builder/control_flow/edgecfg/api/`
- コア型定義: `ExitKind`, `EdgeStub`, `Frag`
- 合成関数シグネチャ: `seq`, `if_`, `loop_`, `cleanup`中身TODO
- 最小テスト: 3個のユニットテスト追加
- ドキュメント連動: `edgecfg-fragments.md` に入口情報追記
**重要**: 既存実装pattern6/7/8, merge/EdgeCFGは未改変。
入口だけ固定し、適用は quick 復旧後の次フェーズで実施。
**次のステップ**:
- Phase 265: Pattern8 を Frag 合成に移行(最小適用)
- Phase 266: Pattern6/7 への展開(再利用確認)
**詳細**: `docs/development/current/main/phases/phase-264/README.md` + `docs/development/current/main/design/edgecfg-fragments.md`
## Next (planned)
- Phase 259: `StringUtils.is_integer/1`nested-if + loopを JoinIR で受理して `--profile quick` を進める
- Phase 260: block-parameterized CFG へ向けた "edge-args terminator 併存導入"(大工事 / Strangler
- Phase 259.x: Me receiver SSOT`variable_map["me"]`)を API 化して `"this"`/`"me"` 混同を構造で潰す
- Phase 265planned: Pattern8 を Frag 合成に移行し、ExitKind+Frag の実装適用を開始(`compose::loop_` 実装)
- Phase 266planned: catch/cleanup / cleanup/defer / async を "exit-edge 正規化" で追加できる形へ(設計: `docs/development/current/main/design/exception-cleanup-async.md`
- Phase 141 P2+: Call/MethodCall 対応effects + typing を分離して段階投入、ANF を前提に順序固定)
- Phase 143-loopvocab P3+: 条件スコープ拡張impure conditions 対応)
- 詳細: `docs/development/current/main/30-Backlog.md`

View File

@ -64,14 +64,25 @@ Related:
- 最小再現 fixture + smoke で固定(先に失敗を SSOT 化)
- Pattern2 が不成立のときは “部分続行” せず `Ok(None)` で fallback既定挙動不変
- **Phase 263+planned / refactor: Pattern2 PromoteDecision API hardening**
- ねらい: “Reject でも続行して後段で落ちる” を構造で不可能にする(迷子防止)
- 形(最小):
- `PromoteStepBox::try_promote(...) -> Result<PromoteDecision, String>`
- `PromoteDecision::{Promoted, NotApplicable, Freeze}`
- 受け入れ条件:
- orchestrator が `NotApplicable` を受け取ったら Pattern2 を `Ok(None)` で抜けて fallbackSSOT
- “Reject=continue” のような曖昧挙動がコードから消える
- **DONEPhase 263 P0.2: Pattern2 PromoteDecision API hardening**
- 入口SSOT: `src/mir/builder/control_flow/joinir/patterns/pattern2/api/`
- `PromoteDecision::{Promoted, NotApplicable, Freeze}``try_promote(...)` に参照点を収束Option揺れを撤去
- **Phase 264✅ 入口作成完了): EdgeCFG Fragment 入口作成design-first**
- **ステータス**: ✅ 入口作成完了(適用は次フェーズ)
- **実装内容**:
- `edgecfg/api/` フォルダに SSOT 入口作成
- `ExitKind`, `EdgeStub`, `Frag` の型定義
- `seq`, `if_`, `loop_`, `cleanup` のシグネチャ固定pub(crate)
- 最小ユニットテスト 3個
- ドキュメント連動edgecfg-fragments.md
- **制約遵守**:
- 既存 pattern6/7/8 未改変
- merge/EdgeCFG 未改変
- cargo test -p nyash-rust --lib --no-run 成功確認
- **次フェーズへの橋渡し**:
- Phase 265 で Pattern8 適用時に `compose::loop_` を実装
- 再利用確認後、pattern番号分岐を段階的に削減
- **real-app loop regression の横展開VM + LLVM EXE**
- ねらい: 実コード由来ループを 1 本ずつ最小抽出して fixture/smoke で固定する(段階投入)。

View File

@ -0,0 +1,142 @@
# EdgeCFG Flow FragmentsFrag / ExitKind— Structured→CFG lowering SSOT
Status: Draftdesign SSOT candidate
Last updated: 2025-12-21
Related:
- North starCFG/ABI: `docs/development/current/main/design/join-explicit-cfg-construction.md`
- Catch/Cleanup/Async: `docs/development/current/main/design/exception-cleanup-async.md`
## 目的(なぜ必要?)
EdgeCFGblock-parameterized CFG / edge-args SSOTが固まると、次に残る “泥沼” はここだけになる:
- **構造化制御if/loop + catch/cleanup→ CFG** の lowering で起きる **exit 配線問題**
- 「pattern番号で推測分岐」が増殖しやすい領域長期的には消したい
この文書は「pattern番号の列挙」を設計の中心にしないために、Structured→CFG の lowering を
**合成代数fragment composition**として SSOT 化する。
結論(本書の北極星):
- “分岐の中心” は pattern番号ではなく **ExitKind****Fragfragment** に置く
- 値の合流は EdgeCFG の **block params + edge-args** で表し、PHI/推測/メタに逃げない
- pattern は「Extractor形の認識/ Plan最小要件の抽出」までに縮退し、merge/配線層へ逆流させない
## “フロー” は 2 層ある(混ぜると崩れる)
1. **CFG層EdgeCFG / plumbing**
- terminator 語彙: `Jump/Branch/Return/Invoke`
- edge-args: terminator operand が SSOT
- out_edges の参照点が SSOT複数 edge 前提)
2. **Structured→CFG lowering 層flow composition**
- `if/loop/catch/cleanup/seq` を “Frag の合成” として書く
- 難しさの本体は **exit脱出の種類****ネスト****合流**
## コア概念(最小の強い箱)
### ExitKind脱出の種類を一次概念にする
最低限の ExitKind:
- `Normal`fallthrough
- `Break(loop_id)` / `Continue(loop_id)`
- `Return`
- `Unwind`Invoke.err / catch へ)
- `Cancel`async の drop/cancel 用。今は予約)
### EdgeStub未配線の脱出エッジ
“どこへ飛ぶべきか未確定” な edge を表す。最終的に EdgeCFG の terminator edge に落ちる。
例(概念):
- `from: BlockId`
- `kind: ExitKind`
- `args: EdgeArgs`(ターゲット params に対応する値。target が未確定でも “役割” はここで決める)
### Fragfragment
```text
Frag = { entry_block, exits: Map<ExitKind, Vec<EdgeStub>> }
```
- `entry_block`: 断片の入口
- `exits`: 断片から外へ出る未配線 edge の集合
## 合成則pattern列挙を写像へ落とす
### seq(a, b)
- `a.exits[Normal]``b.entry` へ接続するedge-args を必要に応じて写像)
- それ以外の exit は上位へ伝搬する
### if(cond, t, e)
- header に `Branch(cond, t.entry, e.entry)` を置く
- `t.Normal``e.Normal` は join へ集める(必要なら join block params を作る)
- `Break/Continue/Return/Unwind` は上位へ伝搬
### loop(body)
- header / latch / after を組み、`Continue` を header に戻す
- `Break` を after へ出す
- `Return/Unwind` は上位へ伝搬
### cleanup(body, cleanup_block)finally の後継)
狙い: “脱出 edge 正規化”
- body の全 exitNormal/Break/Continue/Return/Unwind/Cancelを cleanup 経由へリライトする
- cleanup 後に “元の exit” を再発射するExitTag + payload を block params で運ぶ)
重要: 例外 edgeInvoke.errも漏れなく cleanup に寄せる。
## pattern は最終的に消える?(設計としての答え)
消える(実装の中心概念から降格する)。
- pattern番号は **回帰テスト名/症状ラベル**としては残して良い
- 実装の中心は `Frag/ExitKind/join(block params)` の合成則になる
- 各 pattern 実装は “Extractor形の認識→ Frag 合成呼び出し” の薄い層へ縮退する
## 実装の入口SSOT API を先に作る)
目的: “どこを触ればいいか” を 1 箇所に固定し、推測・部分続行・場当たり分岐を減らす。
推奨の入口:
- `EdgeCFG` の plumbing API既存: `BasicBlock::out_edges()`
- Structured→CFG の入口 API新規: `Frag` / `ExitKind` / `compose::{seq, if_, loop_ , cleanup}`
物理配置(案):
- `src/mir/builder/control_flow/edgecfg/api/`(または `.../joinir/api/` に併設してもよい)
- `frag.rs` / `exit_kind.rs` / `compose.rs` / `patch.rs`
## verifyFail-Fast の置き場所)
- **NormalizeBox 直後**: terminator 語彙固定・edge-args 長さ一致・cond付きJump禁止など “意味SSOT” を確定
- **merge直前**: boundary/ABI/edge-args の矛盾を即死させ “配線SSOT” を確定
- **--verify**: PHI predecessor / CFG cache 整合 / edge-args の長さ一致を常設
## 直近の導入ステップ(最小で始める)
1. `Frag/ExitKind/EdgeStub` の型を追加docs+code 入口 SSOT
2. `seq/if/loop` の合成だけ実装cleanup/Invoke は後段)
3. 既存 pattern のうち 1 本だけ `Frag` 合成に寄せるPattern8 推奨)
4. 2 本目で再利用が見えたら "pattern番号での枝刈り" を削って合成側へ寄せる
## 実装入口(コード SSOT
**Phase 264 で入口API を作成完了**
- 物理配置: `src/mir/builder/control_flow/edgecfg/api/`
- コア型: `ExitKind`, `EdgeStub`, `Frag`
- 合成関数: `seq`, `if_`, `loop_`, `cleanup`シグネチャのみ、中身TODO
- 検証: `verify_frag_invariants`(空実装)
次フェーズPhase 265+)で既存 pattern への適用を開始。
現時点では既存 pattern6/7/8 や merge/EdgeCFG は未改変(入口だけ用意)。