From 93022e7e10ae80aa2d04fb1a624c7e67895d82ac Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sun, 21 Dec 2025 10:23:38 +0900 Subject: [PATCH] fix(pattern2): abort entire Pattern2 on unpromoted LoopBodyLocal instead of partial execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 263 P0: Pattern2 で処理できない LoopBodyLocal を検出したら Pattern2 全体を早期終了 Changes: - promote_step_box.rs: 戻り値を Result, String> に変更 - Reject を二分化: 対象外(not_readonly等)→ Ok(None)、対象だが未対応 → Err - pattern2_lowering_orchestrator.rs: Ok(None) 検出で早期 return - apps/tests/phase263_p0_pattern2_seg_min.hako: test simplification 後続経路(legacy binding等)へ fallback させる(detection→extract→lower SSOT 維持) Fail-Fast 原則: 対象外は Ok(None) で後続経路へ、対象だが未対応は Err で即座に失敗 Fixes: core_direct_array_oob_set_rc_vm smoke test FAIL 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- apps/tests/phase263_p0_pattern2_seg_min.hako | 36 +++++++------------ .../pattern2_lowering_orchestrator.rs | 10 +++++- .../pattern2_steps/promote_step_box.rs | 36 ++++++++++++++----- 3 files changed, 49 insertions(+), 33 deletions(-) diff --git a/apps/tests/phase263_p0_pattern2_seg_min.hako b/apps/tests/phase263_p0_pattern2_seg_min.hako index 6a95b0bb..da570397 100644 --- a/apps/tests/phase263_p0_pattern2_seg_min.hako +++ b/apps/tests/phase263_p0_pattern2_seg_min.hako @@ -7,29 +7,19 @@ static box Main { main() { - local result = parse_segments() + local i = 0 + local seg = "" + + loop(i < 5) { + seg = "segment" // ← loop body で代入(ReadOnlySlot 契約違反) + + if seg == "end" { + break + } + + i = i + 1 + } + return 0 } } - -// Pattern2 が検出するループ構造 -method parse_segments() { - local i = 0 - local seg = "" - - loop(i < 5) { - seg = get_segment(i) // ← loop body で代入(ReadOnlySlot 契約違反) - - if seg == "end" { - break - } - - i = i + 1 - } - - return i -} - -method get_segment(idx) { - return "seg" -} 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 52ff83dd..d38d874f 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 @@ -63,7 +63,15 @@ impl Pattern2LoweringOrchestrator { let inputs = ApplyPolicyStepBox::apply(condition, body, facts)?; let promoted = PromoteStepBox::run(builder, condition, body, inputs, debug, verbose)?; - let mut inputs = promoted.inputs; + let mut inputs = match promoted { + Some(result) => result.inputs, + None => { + // Phase 263 P0: 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"); + return Ok(None); + } + }; // Phase 256.5: Wire current_static_box_name from builder context or function name inputs.current_static_box_name = current_box_name_for_lowering(builder); 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 e3e7e0db..a67e8593 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 @@ -26,9 +26,11 @@ impl PromoteStepBox { mut inputs: Pattern2Inputs, debug: bool, verbose: bool, - ) -> Result { - Self::promote_and_prepare_carriers(builder, condition, body, &mut inputs, debug, verbose)?; - Ok(PromoteStepResult { inputs }) + ) -> 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 + } } pub(in crate::mir::builder) fn promote_and_prepare_carriers( @@ -38,7 +40,7 @@ impl PromoteStepBox { inputs: &mut Pattern2Inputs, debug: bool, verbose: bool, - ) -> Result<(), String> { + ) -> Result, String> { use crate::mir::join_ir::lowering::digitpos_condition_normalizer::DigitPosConditionNormalizer; use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox; @@ -119,10 +121,26 @@ impl PromoteStepBox { inputs.read_only_body_local_slot = Some(slot); } PolicyDecision::Reject(reason) => { - return Err(error_messages::format_error_pattern2_promotion_failed( - &cond_body_local_vars, - &reason, - )); + // Phase 263 P0 + Step 2.5: Reject を二分化 + if reason.contains("not_readonly") + || reason.contains("No promotable pattern detected") + { + // 対象外: Pattern2 で処理できない形 → Ok(None) で後続経路へ + #[cfg(debug_assertions)] + { + eprintln!( + "[pattern2/promote_step] Pattern2 対象外(LoopBodyLocal {:?}): {}. 後続経路へfallback.", + cond_body_local_vars, reason + ); + } + return Ok(None); // Pattern2 全体を中止 + } else { + // 対象だが未対応(freeze級): 実装バグ or 将来実装予定 → Err で Fail-Fast + return Err(format!( + "[pattern2/promote_step] Pattern2 未対応エラー(LoopBodyLocal {:?}): {}", + cond_body_local_vars, reason + )); + } } PolicyDecision::None => {} } @@ -174,7 +192,7 @@ impl PromoteStepBox { } } - Ok(()) + Ok(Some(())) } }