about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSean Chen <seanchen11235@gmail.com>2021-10-27 13:03:53 -0500
committerSean Chen <seanchen11235@gmail.com>2021-10-27 13:03:53 -0500
commitc0f14cb9301eacb51fc660f1d461cbc783f4aaa7 (patch)
tree4496d773b78de506776e6756e6acf17c04b3896a
parentc6de41331c732a8f70088ceab12a5049e3db0caa (diff)
downloadrust-c0f14cb9301eacb51fc660f1d461cbc783f4aaa7.tar.gz
rust-c0f14cb9301eacb51fc660f1d461cbc783f4aaa7.zip
Attempt to fix tidy errors
-rw-r--r--library/std/src/error.rs133
-rw-r--r--library/std/src/error/tests.rs291
2 files changed, 345 insertions, 79 deletions
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 52f3ebbdee4..d8859cf1e55 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -25,7 +25,7 @@ use crate::backtrace::Backtrace;
 use crate::borrow::Cow;
 use crate::cell;
 use crate::char;
-use crate::fmt::{self, Debug, Display, Write};
+use crate::fmt::{self, Debug, Display};
 use crate::mem::transmute;
 use crate::num;
 use crate::str;
@@ -816,6 +816,7 @@ impl dyn Error + Send + Sync {
 ///
 /// ```
 /// #![feature(error_reporter)]
+/// #![feature(negative_impls)]
 ///
 /// use std::error::{Error, Report};
 /// use std::fmt;
@@ -848,6 +849,10 @@ impl dyn Error + Send + Sync {
 ///
 /// impl Error for SuperErrorSideKick {}
 ///
+/// // Note that the error doesn't need to be `Send` or `Sync`.
+/// impl !Send for SuperError {}
+/// impl !Sync for SuperError {}
+///
 /// fn main() {
 ///     let error = SuperError { side: SuperErrorSideKick };
 ///     let report = Report::new(&error).pretty(true);
@@ -855,10 +860,37 @@ impl dyn Error + Send + Sync {
 ///     println!("{}", report);
 /// }
 /// ```
+///
+/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the
+/// wrapped error be `Send`, `Sync`, or `'static`.
+///
+/// ```rust
+/// # #![feature(error_reporter)]
+/// # use std::fmt;
+/// # use std::error::{Error, Report};
+/// #[derive(Debug)]
+/// struct SuperError<'a> {
+///     side: &'a str,
+/// }
+/// impl<'a> fmt::Display for SuperError<'a> {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "SuperError is here: {}", self.side)
+///     }
+/// }
+/// impl<'a> Error for SuperError<'a> {}
+/// fn main() {
+///     let msg = String::from("Huzzah!");
+///     let report = Report::new(SuperError { side: &msg });
+///     println!("{}", report);
+/// }
+/// ```
 #[unstable(feature = "error_reporter", issue = "90172")]
 pub struct Report<E> {
+    /// The error being reported.
     error: E,
+    /// Whether a backtrace should be included as part of the report.
     show_backtrace: bool,
+    /// Whether the report should be pretty-printed.
     pretty: bool,
 }
 
@@ -911,18 +943,15 @@ where
             write!(f, "\n\nCaused by:")?;
 
             let multiple = cause.source().is_some();
-            let format = if multiple {
-                Format::Numbered { ind: 0 }
-            } else {
-                Format::Uniform { indentation: "    " }
-            };
 
-            for error in cause.chain() {
+            for (ind, error) in cause.chain().enumerate() {
                 writeln!(f)?;
 
-                let mut indented = Indented { inner: f, needs_indent: true, format };
-
-                write!(indented, "{}", error)?;
+                if multiple {
+                    write!(f, "{: >4}: {}", ind, Indented { source: error })?;
+                } else {
+                    write!(f, "    {}", error)?;
+                }
             }
         }
 
@@ -930,14 +959,10 @@ where
             let backtrace = error.backtrace();
 
             if let Some(backtrace) = backtrace {
-                let mut backtrace = backtrace.to_string();
-
-                write!(f, "\n\n")?;
-                writeln!(f, "Stack backtrace:")?;
+                let backtrace = backtrace.to_string();
 
-                backtrace.truncate(backtrace.trim_end().len());
-
-                write!(f, "{}", backtrace)?;
+                f.write_str("\n\nStack backtrace:\n")?;
+                f.write_str(backtrace.trim_end())?;
             }
         }
 
@@ -977,76 +1002,26 @@ where
     }
 }
 
-/// Encapsulates how error sources are indented and formatted.
-struct Indented<'a, D: ?Sized> {
-    inner: &'a mut D,
-    needs_indent: bool,
-    format: Format,
-}
-
-/// The possible variants that error sources can be formatted as.
-#[derive(Clone, Copy)]
-enum Format {
-    /// Insert uniform indentation before every line.
-    ///
-    /// This format takes a static string as input and inserts it after every newline.
-    Uniform {
-        /// The string to insert as indentation.
-        indentation: &'static str,
-    },
-    /// Inserts a number before the first line.
-    ///
-    /// This format hard codes the indentation level to match the indentation from
-    /// `std::backtrace::Backtrace`.
-    Numbered {
-        /// The index to insert before the first line of output.
-        ind: usize,
-    },
+/// Wrapper type for indenting the inner source.
+struct Indented<D> {
+    source: D,
 }
 
-impl<D> Write for Indented<'_, D>
+impl<D> fmt::Display for Indented<D>
 where
-    D: Write + ?Sized,
+    D: fmt::Display,
 {
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        for (ind, line) in s.split('\n').enumerate() {
-            if ind > 0 {
-                self.inner.write_char('\n')?;
-                self.needs_indent = true;
-            }
-
-            if self.needs_indent {
-                if line.is_empty() {
-                    continue;
-                }
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let source = self.source.to_string();
 
-                self.format.insert_indentation(ind, &mut self.inner)?;
-                self.needs_indent = false;
+        for (ind, line) in source.trim().split('\n').filter(|l| !l.is_empty()).enumerate() {
+            if ind > 0 {
+                write!(f, "\n      {}", line)?;
+            } else {
+                write!(f, "{}", line)?;
             }
-
-            self.inner.write_fmt(format_args!("{}", line))?;
         }
 
         Ok(())
     }
 }
-
-impl Format {
-    /// Write the specified formatting to the write buffer.
-    fn insert_indentation(&mut self, line: usize, f: &mut dyn Write) -> fmt::Result {
-        match self {
-            Format::Uniform { indentation } => {
-                write!(f, "{}", indentation)
-            }
-            Format::Numbered { ind } => {
-                if line == 0 {
-                    write!(f, "{: >4}: ", ind)?;
-                    *ind += 1;
-                    Ok(())
-                } else {
-                    write!(f, "      ")
-                }
-            }
-        }
-    }
-}
diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs
index 66d6924f34d..c408915ca71 100644
--- a/library/std/src/error/tests.rs
+++ b/library/std/src/error/tests.rs
@@ -35,3 +35,294 @@ fn downcasting() {
         Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
     }
 }
+
+use crate::backtrace;
+use crate::env;
+use crate::error::Report;
+
+#[derive(Debug)]
+struct SuperError {
+    side: SuperErrorSideKick,
+}
+
+impl fmt::Display for SuperError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "SuperError is here!")
+    }
+}
+
+impl Error for SuperError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        Some(&self.side)
+    }
+}
+
+#[derive(Debug)]
+struct SuperErrorSideKick;
+
+impl fmt::Display for SuperErrorSideKick {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "SuperErrorSideKick is here!")
+    }
+}
+
+impl Error for SuperErrorSideKick {}
+
+#[test]
+fn single_line_formatting() {
+    let error = SuperError { side: SuperErrorSideKick };
+    let report = Report::new(&error);
+    let actual = report.to_string();
+    let expected = String::from("SuperError is here!: SuperErrorSideKick is here!");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn multi_line_formatting() {
+    let error = SuperError { side: SuperErrorSideKick };
+    let report = Report::new(&error).pretty(true);
+    let actual = report.to_string();
+    let expected =
+        String::from("SuperError is here!\n\nCaused by:\n    SuperErrorSideKick is here!");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_no_sources_formats_single_line_correctly() {
+    let report = Report::new(SuperErrorSideKick);
+    let actual = report.to_string();
+    let expected = String::from("SuperErrorSideKick is here!");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_no_sources_formats_multi_line_correctly() {
+    let report = Report::new(SuperErrorSideKick).pretty(true);
+    let actual = report.to_string();
+    let expected = String::from("SuperErrorSideKick is here!");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_backtrace_outputs_correctly() {
+    use backtrace::Backtrace;
+
+    env::remove_var("RUST_BACKTRACE");
+
+    #[derive(Debug)]
+    struct ErrorWithBacktrace<'a> {
+        msg: &'a str,
+        trace: Backtrace,
+    }
+
+    impl<'a> fmt::Display for ErrorWithBacktrace<'a> {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            write!(f, "Error with backtrace: {}", self.msg)
+        }
+    }
+
+    impl<'a> Error for ErrorWithBacktrace<'a> {
+        fn backtrace(&self) -> Option<&Backtrace> {
+            Some(&self.trace)
+        }
+    }
+
+    let msg = String::from("The source of the error");
+    let report = Report::new(ErrorWithBacktrace { msg: &msg, trace: Backtrace::capture() })
+        .pretty(true)
+        .show_backtrace(true);
+
+    let expected = String::from(
+        "Error with backtrace: The source of the error\n\nStack backtrace:\ndisabled backtrace",
+    );
+
+    assert_eq!(expected, report.to_string());
+}
+
+#[derive(Debug)]
+struct GenericError<D> {
+    message: D,
+    source: Option<Box<dyn Error + 'static>>,
+}
+
+impl<D> GenericError<D> {
+    fn new(message: D) -> GenericError<D> {
+        Self { message, source: None }
+    }
+
+    fn new_with_source<E>(message: D, source: E) -> GenericError<D>
+    where
+        E: Error + 'static,
+    {
+        let source: Box<dyn Error + 'static> = Box::new(source);
+        let source = Some(source);
+        GenericError { message, source }
+    }
+}
+
+impl<D> fmt::Display for GenericError<D>
+where
+    D: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.message, f)
+    }
+}
+
+impl<D> Error for GenericError<D>
+where
+    D: fmt::Debug + fmt::Display,
+{
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        self.source.as_deref()
+    }
+}
+
+#[test]
+fn error_formats_single_line_with_rude_display_impl() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("line 1\nline 2")?;
+            f.write_str("\nline 3\nline 4\n")?;
+            f.write_str("line 5\nline 6")?;
+            Ok(())
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error);
+    let expected = r#"line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6"#;
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_formats_multi_line_with_rude_display_impl() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("line 1\nline 2")?;
+            f.write_str("\nline 3\nline 4\n")?;
+            f.write_str("line 5\nline 6")?;
+            Ok(())
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error).pretty(true);
+    let expected = r#"line 1
+line 2
+line 3
+line 4
+line 5
+line 6
+
+Caused by:
+   0: line 1
+      line 2
+      line 3
+      line 4
+      line 5
+      line 6
+   1: line 1
+      line 2
+      line 3
+      line 4
+      line 5
+      line 6
+   2: line 1
+      line 2
+      line 3
+      line 4
+      line 5
+      line 6"#;
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_that_start_with_newline_formats_correctly() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("\nThe message\n")
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error).pretty(true);
+    let expected = r#"
+The message
+
+
+Caused by:
+   0: The message
+   1: The message"#;
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_with_string_interpolation_formats_correctly() {
+    #[derive(Debug)]
+    struct MyMessage(usize);
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            write!(f, "Got an error code: ({}). ", self.0)?;
+            write!(f, "What would you like to do in response?")
+        }
+    }
+
+    let error = GenericError::new(MyMessage(10));
+    let error = GenericError::new_with_source(MyMessage(20), error);
+    let report = Report::new(error).pretty(true);
+    let expected = r#"Got an error code: (20). What would you like to do in response?
+
+Caused by:
+    Got an error code: (10). What would you like to do in response?"#;
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}