Files
hakorune/docs/development/current/main/phases/phase-284/README.md

6.5 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/mod.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/mod.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

P2smoke 固定) 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)

受け入れ条件:

  • integrationVMPASS
  • integrationLLVM harnessPASSまたは理由付き段階完了
  • quick 154/154 PASS 維持

詳細手順: P2-INSTRUCTIONS.md

P3+(将来)

  • 他の return パターンPattern8 等)の smoke 追加
  • LLVM AOT 経路での return 検証

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 終端として生成される)