phase29ab(p3): fix PromoteDecision contract and add negative smokes
This commit is contained in:
@ -0,0 +1,31 @@
|
||||
# Pattern2 Promotion API Contract (SSOT)
|
||||
|
||||
This directory is the single entry point for Pattern2 LoopBodyLocal promotion.
|
||||
All callers must go through `try_promote()` and must honor the decision contract
|
||||
below.
|
||||
|
||||
## PromoteDecision Contract
|
||||
|
||||
- `Promoted`
|
||||
- All contract checks satisfied.
|
||||
- Pattern2 continues in the JoinIR path.
|
||||
|
||||
- `NotApplicable`
|
||||
- Promotion not applicable (no LoopBodyLocal in conditions).
|
||||
- The caller continues Pattern2 with unchanged inputs.
|
||||
- Example causes:
|
||||
- No LoopBodyLocal variables in the break condition.
|
||||
|
||||
- `Freeze`
|
||||
- Contract violation or unimplemented behavior.
|
||||
- Fail-fast with a clear error tag, no fallback.
|
||||
- Example causes:
|
||||
- Read-only contract broken (assignment detected).
|
||||
- Missing required metadata (loop scope/break guard).
|
||||
|
||||
## Reject Mapping Rules (PolicyDecision::Reject -> PromoteDecision)
|
||||
|
||||
The mapping lives in `promote_runner.rs` and must remain stable:
|
||||
|
||||
- Any `PolicyDecision::Reject` becomes `Freeze`
|
||||
- Promotion not applicable (no LoopBodyLocal vars) uses `NotApplicable`
|
||||
@ -16,11 +16,11 @@ 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,
|
||||
/// Promotion not applicable (e.g., no LoopBodyLocal in conditions)
|
||||
/// → Continue Pattern2 with unchanged inputs
|
||||
NotApplicable(PromoteStepResult),
|
||||
|
||||
/// Pattern2 should handle this but implementation is missing
|
||||
/// Contract violation or unimplemented behavior
|
||||
/// → Fail-Fast with error message
|
||||
Freeze(String),
|
||||
}
|
||||
|
||||
@ -42,7 +42,9 @@ pub(in crate::mir::builder) fn try_promote(
|
||||
.map(|v| v.name.clone())
|
||||
.collect();
|
||||
|
||||
if cond_scope.has_loop_body_local() {
|
||||
let has_body_locals_in_conditions = cond_scope.has_loop_body_local();
|
||||
|
||||
if has_body_locals_in_conditions {
|
||||
// Policy-controlled: some families must not run promotion/slot heuristics here.
|
||||
// Example: balanced depth-scan uses derived vars and doesn't have a break-guard node.
|
||||
if matches!(
|
||||
@ -106,25 +108,11 @@ pub(in crate::mir::builder) fn try_promote(
|
||||
}
|
||||
PolicyDecision::Reject(reason) => {
|
||||
// Phase 263 P0.1: Reject を PromoteDecision で二分化(型安全)
|
||||
if reason.contains("not_readonly")
|
||||
|| reason.contains("No promotable pattern detected")
|
||||
{
|
||||
// 対象外: Pattern2 で処理できない形 → NotApplicable で後続経路へ
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
eprintln!(
|
||||
"[pattern2/api/promote] Pattern2 対象外(LoopBodyLocal {:?}): {}. 後続経路へfallback.",
|
||||
cond_body_local_vars, reason
|
||||
);
|
||||
}
|
||||
return Ok(PromoteDecision::NotApplicable);
|
||||
} else {
|
||||
// 対象だが未対応(freeze級): 実装バグ or 将来実装予定 → Freeze で Fail-Fast
|
||||
return Ok(PromoteDecision::Freeze(format!(
|
||||
"[pattern2/api/promote] Pattern2 未対応エラー(LoopBodyLocal {:?}): {}",
|
||||
cond_body_local_vars, reason
|
||||
)));
|
||||
}
|
||||
// 対象だが未対応(freeze級): 実装バグ or 将来実装予定 → Freeze で Fail-Fast
|
||||
return Ok(PromoteDecision::Freeze(format!(
|
||||
"[pattern2/api/promote] Pattern2 未対応エラー(LoopBodyLocal {:?}): {}",
|
||||
cond_body_local_vars, reason
|
||||
)));
|
||||
}
|
||||
PolicyDecision::None => {}
|
||||
}
|
||||
@ -176,5 +164,9 @@ pub(in crate::mir::builder) fn try_promote(
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PromoteDecision::Promoted(PromoteStepResult { inputs }))
|
||||
if has_body_locals_in_conditions {
|
||||
Ok(PromoteDecision::Promoted(PromoteStepResult { inputs }))
|
||||
} else {
|
||||
Ok(PromoteDecision::NotApplicable(PromoteStepResult { inputs }))
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,11 +67,12 @@ impl Pattern2LoweringOrchestrator {
|
||||
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 (not applicable), allowing fallback");
|
||||
return Ok(None);
|
||||
PromoteDecision::NotApplicable(result) => {
|
||||
super::super::trace::trace().debug(
|
||||
"pattern2",
|
||||
"Pattern2 promotion not applicable, continuing without promotion",
|
||||
);
|
||||
result.inputs
|
||||
}
|
||||
PromoteDecision::Freeze(reason) => {
|
||||
// Pattern2 should handle this but implementation is missing → Fail-Fast
|
||||
|
||||
Reference in New Issue
Block a user