foundry_common/errors/
mod.rs

1//! Commonly used errors
2
3mod fs;
4pub use fs::FsPathError;
5
6mod private {
7    use eyre::Chain;
8    use std::error::Error;
9
10    pub trait ErrorChain {
11        fn chain(&self) -> Chain<'_>;
12    }
13
14    impl ErrorChain for dyn Error + 'static {
15        fn chain(&self) -> Chain<'_> {
16            Chain::new(self)
17        }
18    }
19
20    impl ErrorChain for eyre::Report {
21        fn chain(&self) -> Chain<'_> {
22            self.chain()
23        }
24    }
25}
26
27/// Displays a chain of errors in a single line.
28pub fn display_chain<E: private::ErrorChain + ?Sized>(error: &E) -> String {
29    dedup_chain(error).join("; ")
30}
31
32/// Deduplicates a chain of errors.
33pub fn dedup_chain<E: private::ErrorChain + ?Sized>(error: &E) -> Vec<String> {
34    let mut causes = all_sources(error);
35    // Deduplicate the common pattern `msg1: msg2; msg2` -> `msg1: msg2`.
36    causes.dedup_by(|b, a| a.contains(b.as_str()));
37    causes
38}
39
40fn all_sources<E: private::ErrorChain + ?Sized>(err: &E) -> Vec<String> {
41    err.chain().map(|cause| cause.to_string().trim().to_string()).collect()
42}
43
44/// Converts solar errors to an eyre error.
45pub fn convert_solar_errors(dcx: &solar::interface::diagnostics::DiagCtxt) -> eyre::Result<()> {
46    match dcx.emitted_errors() {
47        Some(Ok(())) => Ok(()),
48        Some(Err(e)) if !e.is_empty() => eyre::bail!("solar run failed:\n\n{e}"),
49        _ if dcx.has_errors().is_err() => eyre::bail!("solar run failed"),
50        _ => Ok(()),
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn dedups_contained() {
60        #[derive(thiserror::Error, Debug)]
61        #[error("my error: {0}")]
62        struct A(#[from] B);
63
64        #[derive(thiserror::Error, Debug)]
65        #[error("{0}")]
66        struct B(String);
67
68        let ee = eyre::Report::from(A(B("hello".into())));
69        assert_eq!(ee.chain().count(), 2, "{ee:?}");
70        let full = all_sources(&ee).join("; ");
71        assert_eq!(full, "my error: hello; hello");
72        let chained = display_chain(&ee);
73        assert_eq!(chained, "my error: hello");
74    }
75}