## Summary Refactored Phase 284 P1 codebase to consolidate scattered logic into SSOT (Single Source of Truth) modules, improving maintainability and enabling Pattern4/5 code reuse. ## New Modules ### 1. Block Remapper SSOT **File**: `src/mir/builder/control_flow/joinir/merge/block_remapper.rs` (152 lines) - **Purpose**: Consolidate block ID remapping logic (Phase 284 P1 fix) - **Function**: `remap_block_id(block_id, local_block_map, skipped_entry_redirects)` - **Rule**: local_block_map priority > skipped_entry_redirects (prevents ID collision) - **Tests**: 4 unit tests (priority cascade, collision handling, etc.) ### 2. Return Jump Emitter **File**: `src/mir/join_ir/lowering/return_jump_emitter.rs` (354 lines) - **Purpose**: Reusable return handling helper for Pattern4/5 - **Function**: `emit_return_conditional_jump(loop_step_func, return_info, k_return_id, ...)` - **Scope**: P1 - unconditional return + conditional (loop_var == N) only - **Tests**: 3 unit tests (unconditional, no return, conditional) ## Modified Files **merge/instruction_rewriter.rs** (-15 lines): - Replaced inline block remapping with `remap_block_id()` call - Cleaner Branch remap logic **merge/rewriter/terminator.rs** (-43 lines): - Delegates remap_jump/remap_branch to block_remapper SSOT - Simplified duplicate logic **lowering/loop_with_continue_minimal.rs** (-108 lines): - Replaced ~100 line return handling with `emit_return_conditional_jump()` call - Extracted helper functions to return_jump_emitter.rs - Line reduction: 57% decrease in function complexity **merge/mod.rs, lowering/mod.rs**: - Added new module exports (block_remapper, return_jump_emitter) **phase-284/README.md**: - Updated completion status (P1 Complete + Refactored) - Added SSOT consolidation notes - Documented module architecture ## Code Quality Improvements | Metric | Before | After | Change | |--------|--------|-------|--------| | Duplicate block remap logic | 2 places | SSOT | -15 lines | | Return handling code | inline (100L) | helper call | -99 lines | | Testability | Limited | Unit tests (7) | +7 tests | | Module cohesion | Low (scattered) | High (consolidated) | Better | ## Testing ✅ Build: Success (cargo build --release) ✅ Smoke tests: All pass (46 PASS, 1 pre-existing FAIL) ✅ Regression: Zero ✅ Unit tests: 7 new tests added ## Future Benefits 1. **Pattern5 Reuse**: Direct use of `emit_return_conditional_jump()` helper 2. **Phase 285 (P2)**: Nested if/loop returns via same infrastructure 3. **Maintainability**: SSOT reduces debugging surface area 4. **Clarity**: Each module has single responsibility ## Architectural Notes **Block Remapper SSOT Rule**: ``` remap_block_id(id, local_block_map, skipped_entry_redirects): 1. Check local_block_map (function-local priority) 2. Fall back to skipped_entry_redirects (global redirects) 3. Return original if not found ``` Prevents function-local block ID collisions with global remap entries. **Return Emitter Pattern**: ``` emit_return_conditional_jump(func, return_info, k_return_id, alloc_value): - Pattern1-5: All use same infrastructure - P1 scope: top-level return only (nested if/loop → P2) - Returns: JoinInst::Jump(cont=k_return, cond=Some(return_cond)) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
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.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.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)
実装完了内容:
- return_collector.rs - Return statement detection SSOT (既存)
- return_jump_emitter.rs - Return jump emission helper (Pattern4/5 reuse) ⭐NEW
- block_remapper.rs - Block ID remap SSOT (Phase 284 P1 Fix) ⭐NEW
- Loop refactoring - loop_with_continue_minimal.rs simplified (~100 lines removed)
- 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+(未実装)
returnを含む loop body を、Plan line でも ExitKind::Return に落とす。- VM/LLVM の両方で、
returnを含む fixture を smoke 化して SSOT を固定する。
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 終端として生成される)