# Phase 284: Return as ExitKind SSOT(patternに散らさない) Status: P1 Complete (2025-12-23) ## 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/mod.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` の解釈ロジックを増やさない。 補足: Phase 284 は “return だけのため” ではない。ここで固定するのは **Exit 正規化**(ExitKind の語彙化)で、 `return/break/continue/(将来の unwind)` を同じ土台に載せるのが狙い。 「Jump/Branch の配線で exit を表現できる」状態ができると、return はその一例として自然に入る。 ## Responsibility Map(迷子防止) このフェーズで一番起きやすい事故は「`return` をどこで処理するべきか分からず、pattern 側へ散布してしまう」こと。 そこで、**どの経路で lower されるか**を前提に責務を固定する。 ### A) Plan line(Pattern6/7) - 入口: `src/mir/builder/control_flow/joinir/patterns/router.rs`(route=plan) - SSOT: - `src/mir/builder/control_flow/plan/normalizer.rs`(Frag 構築: branches/wires/exits) - `src/mir/builder/control_flow/edgecfg/api/compose/mod.rs`(合成 SSOT) - `src/mir/builder/control_flow/edgecfg/api/emit.rs`(`emit_frag()` terminator SSOT) - ここでは `return` を **Return edge(ExitKind::Return)**として組み立てるのが自然。 ### B) JoinIR line(Pattern1–5,9) - 入口: `src/mir/builder/control_flow/joinir/patterns/router.rs`(route=joinir) - SSOT: - JoinIR 生成(pattern 固有の JoinIR lowerer) - `src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs`(JoinIR→MIR→merge の唯一入口) - `src/mir/builder/control_flow/joinir/merge/mod.rs`(Return merge / exit block SSOT) - **注意**: `src/mir/builder/control_flow/plan/normalizer.rs` は Plan line 専用なので、 Pattern4/5 の return 問題の root fix をここへ寄せても効かない。 ### 禁止事項(Phase 284 の憲法) - ❌ Pattern4/5 の `lower()` へ「return を特別扱いする if」を散布しない(SSOTが割れる) - ❌ Extractor が `return` を見つけた時に `Ok(None)` で黙殺しない(silent reroute 禁止) - ✅ `return` の “対応/非対応” は **共通入口の Fail-Fast**で固定する(P1 で実装) ## Scope ### P0(docs-only) ✅ COMPLETE - `return` を ExitKind として扱う SSOT を文章で固定する(本ファイル + 参照先リンク)。 - 移行期間のルール(Ok(None)/Err の境界、黙殺禁止)を Phase 282 と整合させる。 ### P1(code) ✅ COMPLETE (2025-12-23) **実装完了内容**: 1. **return_collector.rs** - Return statement detection SSOT (既存) 2. **return_jump_emitter.rs** - Return jump emission helper (Pattern4/5 reuse) ⭐NEW 3. **block_remapper.rs** - Block ID remap SSOT (Phase 284 P1 Fix) ⭐NEW 4. **Loop refactoring** - loop_with_continue_minimal.rs simplified (~100 lines removed) 5. **Instruction/terminator updates** - Use block_remapper SSOT **コード品質向上**: - Return handling: ~100 lines inline code → 1 function call - Block remapping: Duplicate logic → SSOT function - Future reusability: Pattern5 can now reuse return_jump_emitter ### P2(smoke 固定) ✅ COMPLETE (2025-12-26) **目的**: return を含む loop を VM/LLVM 両方で同一結果にし、integration smoke で固定。 **対象 fixture(既存再利用優先)**: - `apps/tests/phase286_pattern5_return_min.hako` (exit 7) - Return-in-infinite-loop **smoke スクリプト**: - `tools/smokes/v2/profiles/integration/apps/phase284_p2_return_in_loop_vm.sh` (VM) - `tools/smokes/v2/profiles/integration/apps/phase284_p2_return_in_loop_llvm.sh` (LLVM harness) **受け入れ条件**: - integration(VM)PASS - integration(LLVM harness)PASS(または理由付き段階完了) - quick 154/154 PASS 維持 **詳細手順**: `P2-INSTRUCTIONS.md` ### P3+(将来) - 他の return パターン(Pattern8 等)の smoke 追加 - LLVM AOT 経路での return 検証 ## Acceptance - P0: `return` の SSOT(ExitKind/compose/emit)と detect 境界が明文化されている - P1+: `return` を含む loop fixture が VM/LLVM で同一結果になり、smoke で固定されている ## P1 の実装方針(design-first 注記) P1 の root fix は「PlanNormalizer へ寄せる」ではなく、**JoinIR line の共通入口**へ寄せる: - 入口候補: - `src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs`(最終的な “ここで統一したい”) - もしくは JoinIR lowerer 側に “Return collector” を 1 箇所だけ作り、Pattern4/5 はそれを呼ぶだけにする どちらにしても、目的は同じ: - pattern 側へロジックを増やさず(散布しない) - `ExitKind::Return` へ収束させる(MIR では Return 終端として生成される)