Skip to main content

melior/
diagnostic.rs

1//! Diagnostics.
2
3mod handler_id;
4mod severity;
5
6pub use self::{handler_id::DiagnosticHandlerId, severity::DiagnosticSeverity};
7use crate::{ir::Location, utility::print_callback, Error};
8use mlir_sys::{
9    mlirDiagnosticGetLocation, mlirDiagnosticGetNote, mlirDiagnosticGetNumNotes,
10    mlirDiagnosticGetSeverity, mlirDiagnosticPrint, MlirDiagnostic,
11};
12use std::{
13    ffi::c_void,
14    fmt::{self, Display, Formatter},
15    marker::PhantomData,
16};
17
18#[derive(Debug)]
19pub struct Diagnostic<'c> {
20    raw: MlirDiagnostic,
21    phantom: PhantomData<&'c ()>,
22}
23
24impl Diagnostic<'_> {
25    pub fn location(&self) -> Location {
26        unsafe { Location::from_raw(mlirDiagnosticGetLocation(self.raw)) }
27    }
28
29    pub fn severity(&self) -> DiagnosticSeverity {
30        DiagnosticSeverity::try_from(unsafe { mlirDiagnosticGetSeverity(self.raw) })
31            .unwrap_or_else(|error| unreachable!("{}", error))
32    }
33
34    pub fn note_count(&self) -> usize {
35        (unsafe { mlirDiagnosticGetNumNotes(self.raw) }) as usize
36    }
37
38    pub fn note(&self, index: usize) -> Result<Self, Error> {
39        if index < self.note_count() {
40            Ok(unsafe { Self::from_raw(mlirDiagnosticGetNote(self.raw, index as isize)) })
41        } else {
42            Err(Error::PositionOutOfBounds {
43                name: "diagnostic note",
44                value: self.to_string(),
45                index,
46            })
47        }
48    }
49
50    /// Creates a diagnostic from a raw object.
51    ///
52    /// # Safety
53    ///
54    /// A raw object must be valid.
55    pub unsafe fn from_raw(raw: MlirDiagnostic) -> Self {
56        Self {
57            raw,
58            phantom: Default::default(),
59        }
60    }
61}
62
63impl Display for Diagnostic<'_> {
64    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
65        let mut data = (formatter, Ok(()));
66
67        unsafe {
68            mlirDiagnosticPrint(
69                self.raw,
70                Some(print_callback),
71                &mut data as *mut _ as *mut c_void,
72            );
73        }
74
75        data.1
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use crate::{ir::Module, Context};
82
83    #[test]
84    fn handle_diagnostic() {
85        let mut message = None;
86        let context = Context::new();
87
88        context.attach_diagnostic_handler(|diagnostic| {
89            message = Some(diagnostic.to_string());
90            true
91        });
92
93        Module::parse(&context, "foo");
94
95        assert_eq!(
96            message.unwrap(),
97            "custom op 'foo' is unknown (tried 'builtin.foo' as well)"
98        );
99    }
100}