From abdb860e7e3b31e0c9d3a51f5249d2dce71e7ffc Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sun, 21 Dec 2025 10:54:46 +0900 Subject: [PATCH] refactor(pattern2): introduce PromoteDecision enum to eliminate Option wrapping ambiguity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 263 P0.1: PromoteDecision API hardening 目的: Result, String> の揺れを型で固定し、迷子をゼロに Changes: - promote_step_box.rs: - PromoteDecision enum を導入(Promoted/NotApplicable/Freeze) - PromoteStepBox::run() の戻り値を Result に統一 - promote_and_prepare_carriers() が inputs の所有権を受け取り、PromoteDecision を直接構築 - Reject 分岐を型安全に二分化(文字列マッチング維持、型で意図を明確化) - pattern2_lowering_orchestrator.rs: - orchestrator 側の分岐を1箇所に固定(match PromoteDecision {...}) - NotApplicable → Ok(None) で後続経路へ - Freeze → Err で Fail-Fast 受け入れ: - quick smoke: 45/46 PASS ✅(悪化なし) - NotApplicable は必ず Ok(None) で Pattern2全体を抜ける - Freeze は必ず Err(fail-fast) Next: ファイル構造リファクタリング(pattern2/api/ フォルダ化)を別フェーズで検討 --- .../pattern2_lowering_orchestrator.rs | 19 +++++--- .../pattern2_steps/promote_step_box.rs | 44 ++++++++++++------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs index d38d874f..5003bca7 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs @@ -62,15 +62,22 @@ impl Pattern2LoweringOrchestrator { let facts = GatherFactsStepBox::gather(builder, condition, body, fn_body, &ctx, verbose)?; let inputs = ApplyPolicyStepBox::apply(condition, body, facts)?; - let promoted = PromoteStepBox::run(builder, condition, body, inputs, debug, verbose)?; - let mut inputs = match promoted { - Some(result) => result.inputs, - None => { - // Phase 263 P0: Pattern2 cannot handle this loop (e.g., reassigned LoopBodyLocal) + // Phase 263 P0.1: PromoteDecision で分岐を1箇所に固定(型安全) + use super::pattern2_steps::promote_step_box::PromoteDecision; + let mut inputs = match PromoteStepBox::run(builder, condition, body, inputs, debug, verbose)? { + PromoteDecision::Promoted(result) => { + result.inputs + } + PromoteDecision::NotApplicable => { + // Pattern2 cannot handle this loop (e.g., reassigned LoopBodyLocal) // Return Ok(None) to allow router to try next path (legacy binding) - super::super::trace::trace().debug("pattern2", "Pattern2 aborted (promotion failed), allowing fallback"); + super::super::trace::trace().debug("pattern2", "Pattern2 aborted (not applicable), allowing fallback"); return Ok(None); } + PromoteDecision::Freeze(reason) => { + // Pattern2 should handle this but implementation is missing → Fail-Fast + return Err(reason); + } }; // Phase 256.5: Wire current_static_box_name from builder context or function name diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/promote_step_box.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/promote_step_box.rs index a67e8593..26c7c9fa 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/promote_step_box.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/promote_step_box.rs @@ -16,6 +16,22 @@ pub(crate) struct PromoteStepResult { pub inputs: Pattern2Inputs, } +/// Phase 263 P0.1: Promotion decision for Pattern2 LoopBodyLocal handling +/// +/// Eliminates Option<_> wrapping ambiguity by making decision explicit. +pub(crate) enum PromoteDecision { + /// Promotion succeeded - Pattern2 can proceed + Promoted(PromoteStepResult), + + /// Pattern2 not applicable (e.g., reassigned LoopBodyLocal, no promotable pattern) + /// → Router should try next path (legacy binding, etc.) + NotApplicable, + + /// Pattern2 should handle this but implementation is missing + /// → Fail-Fast with error message + Freeze(String), +} + pub(crate) struct PromoteStepBox; impl PromoteStepBox { @@ -23,24 +39,22 @@ impl PromoteStepBox { builder: &mut MirBuilder, condition: &ASTNode, body: &[ASTNode], - mut inputs: Pattern2Inputs, + inputs: Pattern2Inputs, debug: bool, verbose: bool, - ) -> Result, String> { - match Self::promote_and_prepare_carriers(builder, condition, body, &mut inputs, debug, verbose)? { - Some(()) => Ok(Some(PromoteStepResult { inputs })), - None => Ok(None), // Pattern2 cannot handle this loop - } + ) -> Result { + Self::promote_and_prepare_carriers(builder, condition, body, inputs, debug, verbose) } pub(in crate::mir::builder) fn promote_and_prepare_carriers( builder: &mut MirBuilder, condition: &ASTNode, body: &[ASTNode], - inputs: &mut Pattern2Inputs, + inputs: Pattern2Inputs, debug: bool, verbose: bool, - ) -> Result, String> { + ) -> Result { + let mut inputs = inputs; use crate::mir::join_ir::lowering::digitpos_condition_normalizer::DigitPosConditionNormalizer; use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox; @@ -121,11 +135,11 @@ impl PromoteStepBox { inputs.read_only_body_local_slot = Some(slot); } PolicyDecision::Reject(reason) => { - // Phase 263 P0 + Step 2.5: Reject を二分化 + // Phase 263 P0.1: Reject を PromoteDecision で二分化(型安全) if reason.contains("not_readonly") || reason.contains("No promotable pattern detected") { - // 対象外: Pattern2 で処理できない形 → Ok(None) で後続経路へ + // 対象外: Pattern2 で処理できない形 → NotApplicable で後続経路へ #[cfg(debug_assertions)] { eprintln!( @@ -133,13 +147,13 @@ impl PromoteStepBox { cond_body_local_vars, reason ); } - return Ok(None); // Pattern2 全体を中止 + return Ok(PromoteDecision::NotApplicable); } else { - // 対象だが未対応(freeze級): 実装バグ or 将来実装予定 → Err で Fail-Fast - return Err(format!( + // 対象だが未対応(freeze級): 実装バグ or 将来実装予定 → Freeze で Fail-Fast + return Ok(PromoteDecision::Freeze(format!( "[pattern2/promote_step] Pattern2 未対応エラー(LoopBodyLocal {:?}): {}", cond_body_local_vars, reason - )); + ))); } } PolicyDecision::None => {} @@ -192,7 +206,7 @@ impl PromoteStepBox { } } - Ok(Some(())) + Ok(PromoteDecision::Promoted(PromoteStepResult { inputs })) } }