# Phase 286: JoinIR Line Absorption(JoinIR→CorePlan/Frag 収束) Status: Planned (design-first) ## Goal 移行期間に残っている「2本の lowering」を、構造で 1 本に収束させる。 - Plan line(Pattern6/7): `CorePlan → Frag(compose) → emit_frag()` が SSOT - JoinIR line(Pattern1–5,9): `JoinIR → bridge → merge` が SSOT Phase 286 では JoinIR line を “第2の lowerer” として放置せず、**Plan/Frag SSOT へ吸収**する道筋を固定する。 ## Why(なぜ今) - `return` のような「大きな出口語彙」は、責務が分散すると実装場所が揺れて事故りやすい - 移行期間の弱点は「同じASTでも経路により意味論が割れる可能性がある」こと - pattern を溶かしていく思想の最後の壁が “JoinIR line の残存” になりやすい ## SSOT(Phase 286 で守る憲法) - **SSOT=extract**(Phase 282): 検出は extract の成功でのみ決める。`pattern_kind` は O(1) safety valve のみ。 - **CFG/terminator SSOT**(Phase 280/281): `Frag + compose::* + emit_frag()` が唯一の terminator 生成点。 - **Fail-Fast**: close-but-unsupported を `Ok(None)` で黙殺しない(silent reroute 禁止)。 ## Responsibility Map(どこを触るか) - JoinIR line の共通入口(現状): - `src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs` - `src/mir/join_ir_vm_bridge/bridge.rs` - `src/mir/builder/control_flow/joinir/merge/mod.rs` - Plan/Frag SSOT(収束先): - `src/mir/builder/control_flow/plan/*` - `src/mir/builder/control_flow/edgecfg/api/compose.rs` - `src/mir/builder/control_flow/edgecfg/api/emit.rs` ## Scope(提案) ### P0(docs-only) - 「JoinIR line をどの粒度で吸収するか」を SSOT として決める - 例: JoinIR は DomainPlan 生成の補助へ降格 / JoinIR→MIR merge を段階撤去 - “禁止事項” を明文化(pattern 側への散布、二重 SSOT の再発) ### P1(investigation) - JoinIR line が持っている「本当は SSOT に寄せたい責務」を棚卸し - return/break/continue の扱い - exit phi / boundary の責務 - optimizer/type propagation の入り口 ### P2(PoC) - 代表 1 パターン(例: Pattern4)を “JoinIR 生成 → CorePlan/Frag” に変換する PoC - 目的: merge を通さずに `emit_frag()` 経由で終端が生成できることの証明 ## Acceptance(P0) - 2本の lowering が “設計として” どこで 1 本に収束するかが明文化されている - Phase 284(Return)/ Phase 285(GC)と矛盾しない