Files
hakorune/docs/development/current/main/design/exception-cleanup-async.md

116 lines
5.2 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.

# Catch / Cleanup / Async — Join-Explicit CFG extensions
Status: Draftdesign SSOT candidate
Last updated: 2025-12-20
Related:
- North star: `docs/development/current/main/design/join-explicit-cfg-construction.md`
- Phase 260 roadmap: `docs/development/current/main/phases/phase-260/README.md`
## 目的
Nyash/Hakorune の表面文法(主に postfix `catch/cleanup`)に合わせて、例外/後始末/中断asyncを追加するときに JoinIR→MIR の暗黙ABI推測/メタ/例外的分岐)を再増殖させないための設計メモ。
注: `try { ... }` は言語資料上は legacy/非推奨として扱われることがあるが、この設計は **`try` の存在を前提にしない**catch/cleanup を正規化の入口にする)。
ポイントは 2 つだけ:
1. **制御フローは edge を明示し、値は edge-argsblock paramsで運ぶ**
2. **“意味SSOT” と “配線SSOT” を分離し、Fail-Fast の verify を常設する**
## 実装タイミング(推奨)
前提Phase 260 で固める):
- MIR で edge-args が terminator operand にあり、`BasicBlock.jump_args` に依存しない(併存→移行→削除の P2 到達が理想)
- “読む側” の参照点が `out_edges()`/`edge_args_to(target)` に一本化されているBranch 含む)
- “書く側” の terminator 設定が API で一元化されているsuccessors キャッシュ同期漏れを構造で潰している)
- DCE/verify/printer が terminator operand を SSOT として扱う(メタ追いが不要)
順序(迷子が減る順):
1. `catch/cleanup`(例外): `Invoke(ok_edge, err_edge)` を追加(例外 edge を明示)
2. `cleanup/defer`(後始末): “脱出 edge 正規化” を追加Return/Throw/Break/Continue を cleanup に寄せる)
3. `async/await`: CFG 語彙に混ぜず **state-machine lowering**AsyncLowerBoxで分離
## 用語(この文書の範囲)
- **edge-args**: branch/jump の edge に紐づく引数。ターゲット block の params と 1:1 で対応する。
- **Invoke**: 正常継続okと例外継続errを持つ呼び出し terminator。
- **cleanup normalizer**: cleanup/defer を実現するために「スコープ外へ出る edge」を cleanup ブロックに集約する正規化箱。
- **async lowering**: `await` を state machine に落としてから CFGMIRにする箱。
## catch最小語彙例外 edge
### 目標
- 例外経路を “暗黙” にせず、CFG の edge として明示する。
- 例外値は catch block の paramsedge-argsで受ける。
### 最小追加語彙(案)
- `MirTerminator::Invoke { callee, args, ok: (bb_ok, ok_args), err: (bb_err, err_args) }`
設計ノート:
- ok/err 両方が必須(片側欠落を許さない)
- ok/err の args は “役割付きABI” で解釈する(将来 `JoinAbi`/`ContSigId` へ)
### throw の扱い(最小)
MIR で `Throw` を増やさずに済む形:
- 正規化Normalizerが “現在の例外継続” を知っており、`throw e``Jump(unwind_bb, [e, ...])` に正規化する
### verifyFail-Fast
- `Invoke` は terminatorblock の最後)であること
- ok/err のターゲット block params と args の数が一致すること
- err 側の先頭 param は例外値role=Exceptionであること最低限の役割固定
- “may_throw な呼び出し” を `Call` で表していないこと(暫定: 当面は全部 Invoke に倒しても良い)
## cleanup脱出 edge 正規化)
### 目標finally の後継としての cleanup
- return/break/continue/throw 等の “脱出” を cleanup 経由に統一して、後始末漏れを構造で潰す。
- 例外/return の payload は edge-argsblock paramsで運ぶPHI/メタに逃げない)。
### 最小形(案)
スコープ S ごとに次の 2 ブロック(または 1 ブロック + dispatchを作る:
- `cleanup_entry_S(tag, payload..., carriers...)`
- `cleanup_dispatch_S(tag, payload..., carriers...)`
`ExitTag`(例):
- `Return`
- `Throw`
- `Break`
- `Continue`
- `Cancel`async の drop/cancel 用に予約)
### verifyFail-Fast
- S の内部ブロックから “S の外” への edge が存在したら落とす(例外: cleanup_dispatch のみ)
- `Invoke.err` など “例外 edge” も漏れなく cleanup に寄せられていること
- `ExitTag` の分岐が未処理になっていないことUnknown は即死)
## async/awaitstate machine lowering
### 目標
- `await` を CFG 語彙に混ぜず、AsyncLowerBox が責務として消す(残ったら verify で即死)。
- cancel/drop が必要なら `ExitTag::Cancel` と cleanup を接続して後始末を一貫化する。
### 最小インターフェース(案)
- `await` は “前段IRAsyncPrep” にのみ存在してよい
- AsyncLowerBox で state machine 化した後、MIR は `Jump/Branch/Return/Invoke/Call` の語彙だけにする
### verifyFail-Fast
- AsyncLowerBox 後に `await` が 1 つでも残っていたら落とす
- state dispatch が全 state をカバーしていること(未到達 state は削除可)