hax_frontend_exporter/utils/
error_macros.rs

1macro_rules! format_with_context {
2    ($format_str:expr $(,$arg:expr)* $(; {$($x:expr),*})?) => {
3        format!(
4            concat!(
5                $format_str
6                $(, "\n\nContext:\n", $(concat!(" - ", stringify!($x), ": "), "{:#?}", "\n",)*)?
7            ),
8            $($arg,)*
9            $($($x,)*)?
10        )
11    };
12    ($($tt:tt)*) => {format!($($tt)*)};
13}
14
15mod internal_helpers {
16    macro_rules! _verb {
17        (fatal, $o:expr, $message:expr) => {
18            $o.struct_fatal($message)
19        };
20        (error, $o:expr, $message:expr) => {
21            $o.struct_err($message)
22        };
23        (warn, $o:expr, $message:expr) => {
24            $o.struct_warn($message)
25        };
26    }
27    macro_rules! _span_verb_base {
28        ($verb:ident, $s:ident, $span:expr, $message:expr) => {{
29            let backtrace = std::backtrace::Backtrace::capture();
30            eprintln!("{}", backtrace);
31            let mut builder = $crate::utils::_verb!($verb, $s.base().tcx.dcx(), $message);
32            if let Some(span) = $span {
33                builder.span(span.clone());
34            }
35            builder.code(rustc_errors::codes::ErrCode::MAX);
36            builder.note(
37                "⚠️ This is a bug in Hax's frontend.
38Please report this error to https://github.com/hacspec/hax/issues with some context (e.g. the current crate)!",
39            );
40            builder.emit()
41        }};
42    }
43
44    pub(crate) use _span_verb_base;
45    pub(crate) use _verb;
46}
47
48macro_rules! report {
49    ($verb:ident, $s:ident [$span:expr], $($tt:tt)*) => {
50        $crate::utils::_span_verb_base!($verb, $s, Some($span), $crate::utils::format_with_context!($($tt)*))
51    };
52    ($verb:ident, $s:ident, $($tt:tt)*) => {
53        $crate::utils::_span_verb_base!(
54            $verb,
55            $s,
56            $s.base().opt_def_id.map(|did| $s.base().tcx.def_span(did)),
57            $crate::utils::format_with_context!($($tt)*)
58        )
59    };
60}
61
62macro_rules! error { ($($tt:tt)*) => {$crate::utils::report!(error, $($tt)*)} }
63#[allow(unused_macros)]
64macro_rules! warning { ($($tt:tt)*) => {$crate::utils::report!(warn, $($tt)*)} }
65macro_rules! fatal { ($($tt:tt)*) => {$crate::utils::report!(fatal, $($tt)*)} }
66
67pub(crate) use format_with_context;
68pub(crate) use internal_helpers::_span_verb_base;
69pub(crate) use internal_helpers::_verb;
70pub(crate) use report;
71
72macro_rules! supposely_unreachable_message {
73    ($label:literal) => {
74        concat!(
75            "Supposely unreachable place in the Rust AST. The label is ",
76            stringify!($label),
77            ".\nThis error report happend because some assumption about the Rust AST was broken."
78        )
79    };
80}
81
82macro_rules! supposely_unreachable {
83    ($s:ident $([$span:expr])?, $label:literal $($tt:tt)*) => {
84        {
85            $crate::utils::error!($s$([$span])?, $crate::utils::supposely_unreachable_message!($label) $($tt)+)
86        }
87    };
88}
89macro_rules! supposely_unreachable_fatal {
90    ($s:ident $([$span:expr])?, $label:literal $($tt:tt)*) => {
91        $crate::utils::fatal!($s$([$span])?, $crate::utils::supposely_unreachable_message!($label) $($tt)+)
92    };
93}
94
95pub(crate) use error;
96pub(crate) use fatal;
97pub(crate) use supposely_unreachable;
98pub(crate) use supposely_unreachable_fatal;
99pub(crate) use supposely_unreachable_message;
100#[allow(unused_imports)]
101pub(crate) use warning;
102
103pub trait SExpect: Sized {
104    type Output;
105    fn s_expect<'tcx, S: crate::BaseState<'tcx>>(self, s: &S, message: &str) -> Self::Output;
106
107    fn s_unwrap<'tcx, S: crate::BaseState<'tcx>>(self, s: &S) -> Self::Output {
108        self.s_expect(s, "")
109    }
110}
111
112mod s_expect_impls {
113    use super::*;
114    struct Dummy;
115    impl std::fmt::Debug for Dummy {
116        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
117            write!(f, "...")
118        }
119    }
120
121    fn s_expect_error<'tcx>(
122        s: &impl crate::BaseState<'tcx>,
123        expected: impl std::fmt::Debug,
124        got: impl std::fmt::Debug,
125        message: &str,
126    ) -> ! {
127        fatal!(
128            s,
129            "s_expect: expected {:?}, got {:?}. {}",
130            expected,
131            got,
132            message
133        )
134    }
135
136    impl<T: std::fmt::Debug> SExpect for Option<T> {
137        type Output = T;
138        fn s_expect<'tcx, S: crate::BaseState<'tcx>>(self, s: &S, message: &str) -> Self::Output {
139            self.unwrap_or_else(|| s_expect_error(s, Some(Dummy), None::<()>, message))
140        }
141    }
142
143    impl<T: std::fmt::Debug, E: std::fmt::Debug> SExpect for Result<T, E> {
144        type Output = T;
145        fn s_expect<'tcx, S: crate::BaseState<'tcx>>(self, s: &S, message: &str) -> Self::Output {
146            self.unwrap_or_else(|e| s_expect_error(s, Ok::<_, ()>(Dummy), Err::<(), _>(e), message))
147        }
148    }
149}
150
151macro_rules! s_assert {
152    ($s:ident, $assertion:expr) => {{
153        if !($assertion) {
154            fatal!($s, "assertion failed: {}", stringify!($assertion))
155        }
156    }};
157}
158pub(crate) use s_assert;