Skip to main content

pliron_mlir_builtin/
error.rs

1use std::error::Error as StdError;
2use thiserror::Error;
3
4/// Recovery guidance for shared representation errors.
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6#[non_exhaustive]
7pub enum RecoveryCategory {
8    /// Correct the input type, attribute, or evaluation arguments.
9    InvalidInput,
10    /// Use a supported representation or numeric domain.
11    Unsupported,
12}
13
14/// Structured representation errors carried by the shared pliron envelope.
15#[derive(Debug, Error)]
16#[non_exhaustive]
17pub enum Diagnostic {
18    /// An affine dimension index exceeds the map's dimension count.
19    #[error("affine dimension {position} is outside {dimensions} dimensions")]
20    DimensionOutOfBounds {
21        /// Referenced dimension.
22        position: usize,
23        /// Available dimensions.
24        dimensions: usize,
25    },
26    /// An affine symbol index exceeds the map's symbol count.
27    #[error("affine symbol {position} is outside {symbols} symbols")]
28    SymbolOutOfBounds {
29        /// Referenced symbol.
30        position: usize,
31        /// Available symbols.
32        symbols: usize,
33    },
34    /// A product contains two nonsymbolic expressions.
35    #[error("affine product is not affine")]
36    NonAffineProduct,
37    /// An affine divisor is not symbolic.
38    #[error("affine divisor for {op:?} is not symbolic")]
39    NonSymbolicDivisor {
40        /// Operator with an invalid divisor.
41        op: crate::attributes::AffineBinaryOp,
42    },
43    /// An expression exceeds the supported nesting depth.
44    #[error("affine expression exceeds the nesting limit")]
45    NestingLimit,
46    /// The evaluation arguments do not match the map signature.
47    #[error(
48        "affine argument count mismatch: expected {expected}, got {actual} (symbols: {symbols})"
49    )]
50    ArgumentCount {
51        /// Whether these are symbol rather than dimension arguments.
52        symbols: bool,
53        /// Required argument count.
54        expected: usize,
55        /// Supplied argument count.
56        actual: usize,
57    },
58    /// An affine evaluation attempted division by zero.
59    #[error("division by zero in affine expression")]
60    DivisionByZero,
61    /// An affine evaluation overflowed.
62    #[error("arithmetic overflow in affine expression")]
63    ArithmeticOverflow,
64    /// An affine expression has malformed storage.
65    #[error("malformed affine expression")]
66    MalformedExpression,
67    /// A native type violates its representation constraints.
68    #[error("invalid {ty}: {reason}")]
69    InvalidType {
70        /// Type or type family.
71        ty: &'static str,
72        /// Violated constraint.
73        reason: &'static str,
74    },
75    /// An attribute violates its representation constraints.
76    #[error("invalid {attribute}: {reason}")]
77    InvalidAttribute {
78        /// Attribute or attribute family.
79        attribute: &'static str,
80        /// Violated constraint.
81        reason: &'static str,
82    },
83    /// The requested integer conversion would lose information.
84    #[error("integer value cannot be represented as {target}")]
85    IntegerOutOfRange {
86        /// Destination integer type.
87        target: &'static str,
88    },
89    /// No lossless MLIR assembly representation is implemented.
90    #[error("cannot serialize {entity} as MLIR: {reason}")]
91    UnsupportedSerialization {
92        /// Entity requiring a dialect-specific representation.
93        entity: String,
94        /// Missing representation or unsupported syntax.
95        reason: &'static str,
96    },
97}
98
99impl Diagnostic {
100    /// Returns recovery guidance without parsing diagnostic text.
101    pub fn recovery_category(&self) -> RecoveryCategory {
102        match self {
103            Self::UnsupportedSerialization { .. } => RecoveryCategory::Unsupported,
104            _ => RecoveryCategory::InvalidInput,
105        }
106    }
107
108    /// Wraps this diagnostic in pliron's error envelope.
109    pub fn into_error(self) -> pliron::result::Error {
110        self.into()
111    }
112
113    /// Finds a builtin diagnostic in an error's source chain.
114    pub fn from_error(error: &pliron::result::Error) -> Option<&Self> {
115        let mut source: &(dyn StdError + 'static) = error;
116        loop {
117            if let Some(diagnostic) = source.downcast_ref::<Self>() {
118                return Some(diagnostic);
119            }
120            source = if let Some(envelope) = source.downcast_ref::<pliron::result::Error>() {
121                envelope.err.as_ref()
122            } else {
123                source.source()?
124            };
125        }
126    }
127}
128impl From<crate::integer::IntegerParseError> for pliron::result::Error {
129    fn from(error: crate::integer::IntegerParseError) -> Self {
130        pliron::arg_error_noloc!(error)
131    }
132}
133
134impl From<Diagnostic> for pliron::result::Error {
135    fn from(error: Diagnostic) -> Self {
136        match error.recovery_category() {
137            RecoveryCategory::InvalidInput => pliron::arg_error_noloc!(error),
138            RecoveryCategory::Unsupported => pliron::input_error_noloc!(error),
139        }
140    }
141}