# Phase 29y: RC insertion SSOT（1箇所で決める）

Status: Ready (docs-first, post self-host)  
Scope: retain/release/weak_drop の発火点を “分散実装しない” ための SSOT を固定する。  

## 0. 目的

- RCイベント（retain/release/weak_drop）を **1箇所**で挿入し、backend差と hidden root を減らす
- 「SSA last-use = 寿命」にならないよう、drop点を **binding scope / explicit drop / 上書き**に限定する

## 1. 置き場所（SSOT）

推奨: `emit_frag()` で CFG が確定した後、codegen直前に **1回だけ**走る “RC insertion pass”

- ここなら PHI/loop/early-exit/cleanup を全部見た状態で挿入できる
- lowering 各所に retain/release を散らさない（SSOTを壊さない）

## 2. 入力と出力（概念）

入力:
- “CFG確定後” の IR（Frag / block graph）
- 変数スコープ境界（binding scope）の情報

出力:
- RCイベントが明示された IR（例: `rc.retain`, `rc.release`, `rc.weak_drop` の effect 列）

重要:
- RCイベント列は “見える化” であり、RCの実体（カウンタ値/Alive判定）は runtime（NyRT）に委譲する

## 3. drop点の規則（最小）

禁止（意味論を壊しやすい）:
- SSA last-use を根拠に release する（weak_to_strong で観測できて破綻し得る）

許可（意味論に沿う）:
- explicit drop: `x = null` の直前に “旧値の release”
- 上書き: `x = <new>` の直前に “旧値の release”
- スコープ終端: binding scope の終端で “そのスコープの binding が保持していた current value の release”

## 4. PHI / loop / early-exit の罠（最低限）

- PHI: “入力値” を間違って release すると破綻する。drop対象は binding の current value と一致する必要がある
- loop: back-edge とスコープ終端の相互作用（継続で生存する値/上書きされる値）を分類する
- early-exit（return/break/continue）: exit edge により “どのスコープが閉じるか” が変わるため、cleanupと統合する必要がある

## 5. 実装に切る時の最小タスク（3つ以内）

1) insertion pass の入口/出口を固定（どのIRを入力にし、何を出力するか）  
2) drop点の規則を最小実装（上書き/explicit drop/スコープ終端）  
3) verify（不変条件）を追加（PHI/edge数と drop点が矛盾しないこと）  
