Files
hakorune/docs/development/current/main/phases/phase-284/README.md
tomoaki b0eeb14c54 refactor(phase284): P1 SSOT Consolidation - Block Remapper & Return Emitter
## 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>
2025-12-23 14:37:01 +09:00

5.9 KiB
Raw Blame History

Phase 284: Return as ExitKind SSOTpatternに散らさない

Status: P1 Complete (2025-12-23)

Goal

return を “pattern 個別の特例” として増やさず、ExitKind::Returncompose::* / 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.rsemit_frag()
  • Router SSOTSSOT=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 exprExitKind::Return として表現する。
  • 返り値ValueIdEdgeArgs で運ぶReturn edge が value を持つ)。
  • Return は 必ず emit 側で terminator になるpattern 側で命令を直に生成しない)。

2) Detect の境界Ok(None) / Err

  • Ok(None): 一致しない(次の extractor へ)
  • Err(...): 一致したが未対応close-but-unsupportedFail-Fast

Phase 284 の完了条件は「return を含むケースが close-but-unsupported ではなく SSOT 経路で処理される」状態に寄せること。

3) 実装の集約点(どこに寄せるか)

  • return の lowering は ExitKind + compose + emit_frag に集約する。
  • pattern の extractor は “認識” のみSSOT=extractreturn の解釈ロジックを増やさない。

補足: Phase 284 は “return だけのため” ではない。ここで固定するのは Exit 正規化ExitKind の語彙化)で、 return/break/continue/(将来の unwind) を同じ土台に載せるのが狙い。 「Jump/Branch の配線で exit を表現できる」状態ができると、return はその一例として自然に入る。

Responsibility Map迷子防止

このフェーズで一番起きやすい事故は「return をどこで処理するべきか分からず、pattern 側へ散布してしまう」こと。 そこで、どの経路で lower されるかを前提に責務を固定する。

A) Plan linePattern6/7

  • 入口: src/mir/builder/control_flow/joinir/patterns/router.rsroute=plan
  • SSOT:
    • src/mir/builder/control_flow/plan/normalizer.rsFrag 構築: branches/wires/exits
    • src/mir/builder/control_flow/edgecfg/api/compose.rs(合成 SSOT
    • src/mir/builder/control_flow/edgecfg/api/emit.rsemit_frag() terminator SSOT
  • ここでは return を **Return edgeExitKind::Return**として組み立てるのが自然。

B) JoinIR linePattern15,9

  • 入口: src/mir/builder/control_flow/joinir/patterns/router.rsroute=joinir
  • SSOT:
    • JoinIR 生成pattern 固有の JoinIR lowerer
    • src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rsJoinIR→MIR→merge の唯一入口)
    • src/mir/builder/control_flow/joinir/merge/mod.rsReturn 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

P0docs-only COMPLETE

  • return を ExitKind として扱う SSOT を文章で固定する(本ファイル + 参照先リンク)。
  • 移行期間のルールOk(None)/Err の境界、黙殺禁止)を Phase 282 と整合させる。

P1code 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+(未実装)

  • return を含む loop body を、Plan line でも ExitKind::Return に落とす。
  • VM/LLVM の両方で、return を含む fixture を smoke 化して SSOT を固定する。

Acceptance

  • P0: return の SSOTExitKind/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 終端として生成される)