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}