phase29ai(p3): typed Freeze + candidate-set planner boundary
This commit is contained in:
@ -7,6 +7,7 @@ use crate::ast::ASTNode;
|
||||
use crate::mir::builder::control_flow::plan::facts::try_build_loop_facts;
|
||||
use crate::mir::builder::control_flow::plan::normalize::{canonicalize_loop_facts, CanonicalLoopFacts};
|
||||
|
||||
use super::candidates::CandidateSet;
|
||||
use super::{Freeze, Plan};
|
||||
|
||||
/// Phase 29ai P0: External-ish SSOT entrypoint (skeleton)
|
||||
@ -20,12 +21,25 @@ pub(in crate::mir::builder) fn build_plan(
|
||||
return Ok(None);
|
||||
};
|
||||
let canonical = canonicalize_loop_facts(facts);
|
||||
let plan = build_plan_from_facts(canonical)?;
|
||||
Ok(Some(plan))
|
||||
build_plan_from_facts(canonical)
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn build_plan_from_facts(
|
||||
_facts: CanonicalLoopFacts,
|
||||
) -> Result<Plan, Freeze> {
|
||||
Err("freeze[phase29ai/p0]: build_plan_from_facts not implemented".to_string())
|
||||
) -> Result<Option<Plan>, Freeze> {
|
||||
// Phase 29ai P3: CandidateSet-based boundary (SSOT)
|
||||
//
|
||||
// P3 note: Facts are currently `Ok(None)` (P0 skeleton), so this function is
|
||||
// unreachable in normal execution today. We still implement the SSOT
|
||||
// boundary here so that future Facts work cannot drift.
|
||||
|
||||
let candidates = CandidateSet::new();
|
||||
|
||||
// No candidates in P3 (unreachable today); boundary remains stable.
|
||||
match candidates.finalize()? {
|
||||
Some(plan) => Ok(Some(plan)),
|
||||
None => Err(Freeze::unsupported(
|
||||
"facts were provided but no planner rule produced a candidate (P3 placeholder)",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
52
src/mir/builder/control_flow/plan/planner/candidates.rs
Normal file
52
src/mir/builder/control_flow/plan/planner/candidates.rs
Normal file
@ -0,0 +1,52 @@
|
||||
//! Phase 29ai P3: CandidateSet — SSOT implementation
|
||||
//!
|
||||
//! SSOT: "0 candidates = Ok(None), 1 = Ok(Some), 2+ = Freeze(ambiguous)"
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::{Freeze, Plan, PlanKind};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct PlanCandidate {
|
||||
pub kind: PlanKind,
|
||||
pub rule: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(in crate::mir::builder) struct CandidateSet {
|
||||
candidates: Vec<PlanCandidate>,
|
||||
}
|
||||
|
||||
impl CandidateSet {
|
||||
pub(in crate::mir::builder) fn new() -> Self {
|
||||
Self {
|
||||
candidates: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn push(&mut self, candidate: PlanCandidate) {
|
||||
self.candidates.push(candidate);
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn finalize(self) -> Result<Option<Plan>, Freeze> {
|
||||
match self.candidates.len() {
|
||||
0 => Ok(None),
|
||||
1 => {
|
||||
let c = self.candidates.into_iter().next().expect("len == 1");
|
||||
Ok(Some(Plan { kind: c.kind }))
|
||||
}
|
||||
n => {
|
||||
let rules = self
|
||||
.candidates
|
||||
.iter()
|
||||
.map(|c| c.rule)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
Err(Freeze::ambiguous(format!(
|
||||
"multiple plan candidates (count={}): {}",
|
||||
n, rules
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/mir/builder/control_flow/plan/planner/freeze.rs
Normal file
66
src/mir/builder/control_flow/plan/planner/freeze.rs
Normal file
@ -0,0 +1,66 @@
|
||||
//! Phase 29ai P3: Typed Freeze (Fail-Fast) — SSOT implementation
|
||||
//!
|
||||
//! Tag taxonomy SSOT:
|
||||
//! - docs/development/current/main/design/planfrag-freeze-taxonomy.md
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct Freeze {
|
||||
pub tag: &'static str,
|
||||
pub message: String,
|
||||
pub hint: Option<String>,
|
||||
}
|
||||
|
||||
impl Freeze {
|
||||
pub(in crate::mir::builder) fn contract(message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
tag: "contract",
|
||||
message: message.into(),
|
||||
hint: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn ambiguous(message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
tag: "ambiguous",
|
||||
message: message.into(),
|
||||
hint: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn unsupported(message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
tag: "unsupported",
|
||||
message: message.into(),
|
||||
hint: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn bug(message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
tag: "bug",
|
||||
message: message.into(),
|
||||
hint: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) fn with_hint(mut self, hint: impl Into<String>) -> Self {
|
||||
self.hint = Some(hint.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Freeze {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "[plan/freeze:{}] {}", self.tag, self.message)?;
|
||||
if let Some(hint) = &self.hint {
|
||||
write!(f, "\n hint: {}", hint)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Freeze {}
|
||||
@ -6,8 +6,10 @@
|
||||
#![allow(dead_code, unused_imports)]
|
||||
|
||||
pub(in crate::mir::builder) mod build;
|
||||
pub(in crate::mir::builder) mod candidates;
|
||||
pub(in crate::mir::builder) mod freeze;
|
||||
|
||||
pub(in crate::mir::builder) type Freeze = String;
|
||||
pub(in crate::mir::builder) use freeze::Freeze;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(in crate::mir::builder) struct Plan {
|
||||
@ -19,4 +21,4 @@ pub(in crate::mir::builder) enum PlanKind {
|
||||
Placeholder,
|
||||
}
|
||||
|
||||
pub(in crate::mir::builder) use build::{build_plan, build_plan_from_facts};
|
||||
pub(in crate::mir::builder) use build::build_plan;
|
||||
|
||||
Reference in New Issue
Block a user