foundry_common/errors/
mod.rs

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