Skip to main content

pliron_math/
error.rs

1use thiserror::Error;
2
3/// Broad recovery strategy for a `math` diagnostic.
4///
5/// Use this classification to distinguish invalid caller input from missing
6/// implementation support, rather than parsing error text.
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum RecoveryCategory {
10    /// Correct the operand types, attributes, or operation structure and retry.
11    InvalidInput,
12}
13
14/// Structured failures raised by `math` verification.
15///
16/// These errors are wrapped in [`pliron::result::Error`]. Use
17/// [`Diagnostic::from_error`] to recover the structured details.
18#[derive(Debug, Error)]
19#[non_exhaustive]
20pub enum Diagnostic {
21    /// An operation's attributes, types, or structure violate its contract.
22    #[error("operation {operation} at {location}: {reason}")]
23    InvalidOperation {
24        /// Operation name identifying the failed check.
25        operation: String,
26        /// Rendered source location, or a placeholder when no source is available.
27        location: String,
28        /// Specific violated constraint; correct the IR before retrying.
29        reason: &'static str,
30    },
31}
32
33impl Diagnostic {
34    /// Finds the first `math` diagnostic in an error and its source chain.
35    ///
36    /// Traverses framework `err` payloads as well as standard error sources.
37    pub fn from_error(error: &pliron::result::Error) -> Option<&Self> {
38        let mut source: &dyn std::error::Error = error;
39        loop {
40            if let Some(diagnostic) = source.downcast_ref::<Self>() {
41                return Some(diagnostic);
42            }
43            source = if let Some(envelope) = source.downcast_ref::<pliron::result::Error>() {
44                envelope.err.as_ref()
45            } else {
46                source.source()?
47            };
48        }
49    }
50
51    /// Classifies the action a caller should take before retrying.
52    pub fn recovery_category(&self) -> RecoveryCategory {
53        match self {
54            Self::InvalidOperation { .. } => RecoveryCategory::InvalidInput,
55        }
56    }
57}
58
59impl From<Diagnostic> for pliron::result::Error {
60    fn from(diagnostic: Diagnostic) -> Self {
61        pliron::arg_error_noloc!(diagnostic)
62    }
63}