Skip to main content

pliron_arith/
error.rs

1use thiserror::Error;
2
3/// Broad recovery strategy for an `arith` diagnostic.
4///
5/// Use this classification to distinguish invalid caller input from missing
6/// implementation support or an internal bug, 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    /// Choose a supported representation before retrying.
13    Unsupported,
14    /// Report an implementation bug; changing otherwise valid input is not a fix.
15    InternalInvariant,
16}
17
18/// Structured failures raised by `arith` construction and verification.
19///
20/// These errors are wrapped in [`pliron::result::Error`]. Use
21/// [`Diagnostic::from_error`] to recover the structured details.
22#[derive(Debug, Error)]
23#[non_exhaustive]
24pub enum Diagnostic {
25    /// An operation's attributes, types, or structure violate its contract.
26    #[error("operation {operation} at {location}: {reason}")]
27    InvalidOperation {
28        /// Operation name identifying the failed check.
29        operation: String,
30        /// Rendered source location, or a placeholder when no source is available.
31        location: String,
32        /// Specific violated constraint; correct the IR before retrying.
33        reason: &'static str,
34    },
35    /// Valid IR that has no representation in the requested output.
36    #[error("cannot represent {operation}: {reason}")]
37    Unsupported {
38        /// Operation or attribute that could not be represented.
39        operation: String,
40        /// Missing capability.
41        reason: &'static str,
42    },
43}
44
45impl Diagnostic {
46    /// Finds the first `arith` diagnostic in an error and its source chain.
47    ///
48    /// Traverses framework `err` payloads as well as standard error sources.
49    pub fn from_error(error: &pliron::result::Error) -> Option<&Self> {
50        let mut source: &dyn std::error::Error = error;
51        loop {
52            if let Some(diagnostic) = source.downcast_ref::<Self>() {
53                return Some(diagnostic);
54            }
55            source = if let Some(envelope) = source.downcast_ref::<pliron::result::Error>() {
56                envelope.err.as_ref()
57            } else {
58                source.source()?
59            };
60        }
61    }
62
63    /// Classifies the action a caller should take before retrying.
64    pub fn recovery_category(&self) -> RecoveryCategory {
65        match self {
66            Self::InvalidOperation { .. } => RecoveryCategory::InvalidInput,
67            Self::Unsupported { .. } => RecoveryCategory::Unsupported,
68        }
69    }
70}
71
72impl From<crate::attributes::EnumParseError> for pliron::result::Error {
73    fn from(error: crate::attributes::EnumParseError) -> Self {
74        pliron::arg_error_noloc!(error)
75    }
76}
77
78impl From<crate::attributes::EnumValueError> for pliron::result::Error {
79    fn from(error: crate::attributes::EnumValueError) -> Self {
80        pliron::arg_error_noloc!(error)
81    }
82}
83
84impl From<Diagnostic> for pliron::result::Error {
85    fn from(diagnostic: Diagnostic) -> Self {
86        pliron::arg_error_noloc!(diagnostic)
87    }
88}