From 59df6c8eb917cba41c15e3366f29ee780c9c74df Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 22 Oct 2021 12:21:10 -0500 Subject: [PATCH 01/21] Try commiting again --- library/std/src/error.rs | 245 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 1 deletion(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 6ae0bc47a9462..9fb8f2b9b8bc5 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}; +use crate::fmt::{self, Debug, Display, Write}; use crate::mem::transmute; use crate::num; use crate::str; @@ -807,3 +807,246 @@ impl dyn Error + Send + Sync { }) } } + +/// An error reporter that exposes the entire error chain for printing. +/// It also exposes options for formatting the error chain, either entirely on a single line, +/// or in multi-line format with each cause in the error chain on a new line. +/// +/// # Examples +/// +/// ``` +/// #![feature(error_reporter)] +/// +/// use std::error::{Error, Report}; +/// use std::fmt; +/// +/// #[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 {} +/// +/// fn main() { +/// let error = SuperError { side: SuperErrorSideKick }; +/// let report = Report::new(&error).pretty(); +/// +/// println!("{}", report); +/// } +/// ``` +#[unstable(feature = "error_reporter", issue = "90172")] +pub struct Report { + source: E, + show_backtrace: bool, + pretty: bool, +} + +impl Report +where + E: Error, +{ + /// Create a new `Report` from an input error. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn new(source: E) -> Report { + Report { source, show_backtrace: false, pretty: false } + } + + /// Enable pretty-printing the report. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn pretty(mut self) -> Self { + self.pretty = true; + self + } + + /// Enable showing a backtrace for the report. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn show_backtrace(mut self) -> Self { + self.show_backtrace = true; + self + } + + /// Format the report as a single line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.source)?; + + let sources = self.source.source().into_iter().flat_map(::chain); + + for cause in sources { + write!(f, ": {}", cause)?; + } + + Ok(()) + } + + /// Format the report as multiple lines, with each error cause on its own line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let error = &self.source; + + write!(f, "{}", error)?; + + if let Some(cause) = error.source() { + 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() { + writeln!(f)?; + + let mut indented = Indented { inner: f, needs_indent: true, format }; + + write!(indented, "{}", error)?; + } + } + + if self.show_backtrace { + let backtrace = error.backtrace(); + + if let Some(backtrace) = backtrace { + let mut backtrace = backtrace.to_string(); + + write!(f, "\n\n")?; + writeln!(f, "Stack backtrace:")?; + + backtrace.truncate(backtrace.trim_end().len()); + + write!(f, "{}", backtrace)?; + } + } + + Ok(()) + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl From for Report +where + E: Error, +{ + fn from(source: E) -> Self { + Report::new(source) + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Display for Report +where + E: Error, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } + } +} + +// This type intentionally outputs the same format for `Display` and `Debug`for +// situations where you unwrap a `Report` or return it from main. +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Debug for Report +where + E: Error, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +/// 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, + }, +} + +impl Write for Indented<'_, D> +where + D: Write + ?Sized, +{ + 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; + } + + self.format.insert_indentation(ind, &mut self.inner)?; + self.needs_indent = false; + } + + 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, " ") + } + } + } + } +} From 6a59d0e3aa26543fc4d3eaae1fa4cd48522045d2 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 22 Oct 2021 13:43:42 -0500 Subject: [PATCH 02/21] Have `pretty` and `show_backtrace` accept booleans --- library/std/src/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 9fb8f2b9b8bc5..5988075836d54 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -850,7 +850,7 @@ impl dyn Error + Send + Sync { /// /// fn main() { /// let error = SuperError { side: SuperErrorSideKick }; -/// let report = Report::new(&error).pretty(); +/// let report = Report::new(&error).pretty(true); /// /// println!("{}", report); /// } @@ -874,15 +874,15 @@ where /// Enable pretty-printing the report. #[unstable(feature = "error_reporter", issue = "90172")] - pub fn pretty(mut self) -> Self { - self.pretty = true; + pub fn pretty(mut self, pretty: bool) -> Self { + self.pretty = pretty; self } /// Enable showing a backtrace for the report. #[unstable(feature = "error_reporter", issue = "90172")] - pub fn show_backtrace(mut self) -> Self { - self.show_backtrace = true; + pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { + self.show_backtrace = show_backtrace; self } From c6de41331c732a8f70088ceab12a5049e3db0caa Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 22 Oct 2021 13:47:05 -0500 Subject: [PATCH 03/21] Change `source` field to `error` --- library/std/src/error.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 5988075836d54..52f3ebbdee47e 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -857,7 +857,7 @@ impl dyn Error + Send + Sync { /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { - source: E, + error: E, show_backtrace: bool, pretty: bool, } @@ -868,8 +868,8 @@ where { /// Create a new `Report` from an input error. #[unstable(feature = "error_reporter", issue = "90172")] - pub fn new(source: E) -> Report { - Report { source, show_backtrace: false, pretty: false } + pub fn new(error: E) -> Report { + Report { error, show_backtrace: false, pretty: false } } /// Enable pretty-printing the report. @@ -889,9 +889,9 @@ where /// Format the report as a single line. #[unstable(feature = "error_reporter", issue = "90172")] fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.source)?; + write!(f, "{}", self.error)?; - let sources = self.source.source().into_iter().flat_map(::chain); + let sources = self.error.source().into_iter().flat_map(::chain); for cause in sources { write!(f, ": {}", cause)?; @@ -903,7 +903,7 @@ where /// Format the report as multiple lines, with each error cause on its own line. #[unstable(feature = "error_reporter", issue = "90172")] fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let error = &self.source; + let error = &self.error; write!(f, "{}", error)?; @@ -950,8 +950,8 @@ impl From for Report where E: Error, { - fn from(source: E) -> Self { - Report::new(source) + fn from(error: E) -> Self { + Report::new(error) } } From c0f14cb9301eacb51fc660f1d461cbc783f4aaa7 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:03:53 -0500 Subject: [PATCH 04/21] Attempt to fix tidy errors --- library/std/src/error.rs | 133 ++++++--------- library/std/src/error/tests.rs | 291 +++++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+), 79 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 52f3ebbdee47e..d8859cf1e552e 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 { + /// 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 { + source: D, } -impl Write for Indented<'_, D> +impl fmt::Display for Indented 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 66d6924f34d2b..c408915ca71a9 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::().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 { + message: D, + source: Option>, +} + +impl GenericError { + fn new(message: D) -> GenericError { + Self { message, source: None } + } + + fn new_with_source(message: D, source: E) -> GenericError + where + E: Error + 'static, + { + let source: Box = Box::new(source); + let source = Some(source); + GenericError { message, source } + } +} + +impl fmt::Display for GenericError +where + D: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.message, f) + } +} + +impl Error for GenericError +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); +} From aa853bd31775db7fcb5074f78d8b989053ae101d Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:04:42 -0500 Subject: [PATCH 05/21] Add `rust` annotation to doctest --- library/std/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index d8859cf1e552e..a6d36dbe5c794 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -814,7 +814,7 @@ impl dyn Error + Send + Sync { /// /// # Examples /// -/// ``` +/// ```rust /// #![feature(error_reporter)] /// #![feature(negative_impls)] /// From d2f49eeb176a670c76f3c8c6005208a9d3cc30ee Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:18:22 -0500 Subject: [PATCH 06/21] Format doctest --- library/std/src/error.rs | 55 ++++++++-------------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index a6d36dbe5c794..26fa6c38549d3 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -811,6 +811,8 @@ impl dyn Error + Send + Sync { /// An error reporter that exposes the entire error chain for printing. /// It also exposes options for formatting the error chain, either entirely on a single line, /// or in multi-line format with each cause in the error chain on a new line. +/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the +/// wrapped error be `Send`, `Sync`, or `'static`. /// /// # Examples /// @@ -822,68 +824,31 @@ impl dyn Error + Send + Sync { /// use std::fmt; /// /// #[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) -/// } +/// struct SuperError<'a> { +/// side: &'a str, /// } /// -/// #[derive(Debug)] -/// struct SuperErrorSideKick; -/// -/// impl fmt::Display for SuperErrorSideKick { +/// impl<'a> fmt::Display for SuperError<'a> { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperErrorSideKick is here!") +/// write!(f, "SuperError is here: {}", self.side) /// } /// } /// -/// impl Error for SuperErrorSideKick {} +/// impl<'a> Error for SuperError<'a> {} /// /// // 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 msg = String::from("Huzzah!"); +/// let error = SuperError { side: &msg }; /// let report = Report::new(&error).pretty(true); /// /// 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 { /// The error being reported. From 32bcb8113f750db36b9590b516a9fc40c0fa99df Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:59:02 -0500 Subject: [PATCH 07/21] Fix broken doctest --- library/std/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 26fa6c38549d3..b45cfa3450684 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -837,8 +837,8 @@ impl dyn Error + Send + Sync { /// impl<'a> Error for SuperError<'a> {} /// /// // Note that the error doesn't need to be `Send` or `Sync`. -/// impl !Send for SuperError {} -/// impl !Sync for SuperError {} +/// impl<'a> !Send for SuperError<'a> {} +/// impl<'a> !Sync for SuperError<'a> {} /// /// fn main() { /// let msg = String::from("Huzzah!"); From 1386a15529f5241402125b37eda7a5bb03fbd247 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Tue, 14 Dec 2021 13:56:49 -0800 Subject: [PATCH 08/21] Update std::error::Report based on feedback --- library/std/src/error.rs | 74 +++++++++----- library/std/src/error/tests.rs | 178 +++++++++++++++++++++++---------- 2 files changed, 171 insertions(+), 81 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index b45cfa3450684..10de248c3d7ec 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}; +use crate::fmt::{self, Debug, Display, Write}; use crate::mem::transmute; use crate::num; use crate::str; @@ -63,7 +63,7 @@ pub trait Error: Debug + Display { /// /// #[derive(Debug)] /// struct SuperError { - /// side: SuperErrorSideKick, + /// source: SuperErrorSideKick, /// } /// /// impl fmt::Display for SuperError { @@ -74,7 +74,7 @@ pub trait Error: Debug + Display { /// /// impl Error for SuperError { /// fn source(&self) -> Option<&(dyn Error + 'static)> { - /// Some(&self.side) + /// Some(&self.source) /// } /// } /// @@ -90,7 +90,7 @@ pub trait Error: Debug + Display { /// impl Error for SuperErrorSideKick {} /// /// fn get_super_error() -> Result<(), SuperError> { - /// Err(SuperError { side: SuperErrorSideKick }) + /// Err(SuperError { source: SuperErrorSideKick }) /// } /// /// fn main() { @@ -836,10 +836,6 @@ impl dyn Error + Send + Sync { /// /// impl<'a> Error for SuperError<'a> {} /// -/// // Note that the error doesn't need to be `Send` or `Sync`. -/// impl<'a> !Send for SuperError<'a> {} -/// impl<'a> !Sync for SuperError<'a> {} -/// /// fn main() { /// let msg = String::from("Huzzah!"); /// let error = SuperError { side: &msg }; @@ -883,6 +879,19 @@ where self } + fn backtrace(&self) -> Option<&Backtrace> { + // have to grab the backtrace on the first error directly since that error may not be + // 'static + let backtrace = self.error.backtrace(); + let backtrace = backtrace.or_else(|| { + self.error + .source() + .map(|source| source.chain().find_map(|source| source.backtrace())) + .flatten() + }); + backtrace + } + /// Format the report as a single line. #[unstable(feature = "error_reporter", issue = "90172")] fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -911,17 +920,17 @@ where for (ind, error) in cause.chain().enumerate() { writeln!(f)?; - - if multiple { - write!(f, "{: >4}: {}", ind, Indented { source: error })?; - } else { - write!(f, " {}", error)?; - } + let mut indented = Indented { + inner: f, + number: if multiple { Some(ind) } else { None }, + started: false, + }; + write!(indented, "{}", error)?; } } if self.show_backtrace { - let backtrace = error.backtrace(); + let backtrace = self.backtrace(); if let Some(backtrace) = backtrace { let backtrace = backtrace.to_string(); @@ -968,23 +977,34 @@ where } /// Wrapper type for indenting the inner source. -struct Indented { - source: D, +struct Indented<'a, D> { + inner: &'a mut D, + number: Option, + started: bool, } -impl fmt::Display for Indented +impl Write for Indented<'_, T> where - D: fmt::Display, + T: Write, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let source = self.source.to_string(); - - 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)?; + fn write_str(&mut self, s: &str) -> fmt::Result { + for (i, line) in s.split('\n').enumerate() { + if !self.started { + self.started = true; + match self.number { + Some(number) => write!(self.inner, "{: >5}: ", number)?, + None => self.inner.write_str(" ")?, + } + } else if i > 0 { + self.inner.write_char('\n')?; + if self.number.is_some() { + self.inner.write_str(" ")?; + } else { + self.inner.write_str(" ")?; + } } + + self.inner.write_str(line)?; } Ok(()) diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index c408915ca71a9..82ef39ae90fb6 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -36,13 +36,12 @@ fn downcasting() { } } -use crate::backtrace; -use crate::env; +use crate::backtrace::Backtrace; use crate::error::Report; #[derive(Debug)] struct SuperError { - side: SuperErrorSideKick, + source: SuperErrorSideKick, } impl fmt::Display for SuperError { @@ -53,7 +52,7 @@ impl fmt::Display for SuperError { impl Error for SuperError { fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(&self.side) + Some(&self.source) } } @@ -70,7 +69,7 @@ impl Error for SuperErrorSideKick {} #[test] fn single_line_formatting() { - let error = SuperError { side: SuperErrorSideKick }; + let error = SuperError { source: SuperErrorSideKick }; let report = Report::new(&error); let actual = report.to_string(); let expected = String::from("SuperError is here!: SuperErrorSideKick is here!"); @@ -80,7 +79,7 @@ fn single_line_formatting() { #[test] fn multi_line_formatting() { - let error = SuperError { side: SuperErrorSideKick }; + let error = SuperError { source: SuperErrorSideKick }; let report = Report::new(&error).pretty(true); let actual = report.to_string(); let expected = @@ -108,50 +107,57 @@ fn error_with_no_sources_formats_multi_line_correctly() { } #[test] -fn error_with_backtrace_outputs_correctly() { - use backtrace::Backtrace; +fn error_with_backtrace_outputs_correctly_with_one_source() { + let trace = Backtrace::force_capture(); + let expected = format!("The source of the error - env::remove_var("RUST_BACKTRACE"); +Caused by: + Error with backtrace - #[derive(Debug)] - struct ErrorWithBacktrace<'a> { - msg: &'a str, - trace: Backtrace, - } +Stack backtrace: +{}", trace); + let error = GenericError::new("Error with backtrace"); + let mut error = GenericError::new_with_source("The source of the error", error); + error.backtrace = Some(trace); + let report = Report::new(error).pretty(true).show_backtrace(true); - 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) - } - } + println!("Error: {}", report); + assert_eq!(expected.trim_end(), report.to_string()); +} + +#[test] +fn error_with_backtrace_outputs_correctly_with_two_sources() { + let trace = Backtrace::force_capture(); + let expected = format!("Error with two sources - let msg = String::from("The source of the error"); - let report = Report::new(ErrorWithBacktrace { msg: &msg, trace: Backtrace::capture() }) - .pretty(true) - .show_backtrace(true); +Caused by: + 0: The source of the error + 1: Error with backtrace - let expected = String::from( - "Error with backtrace: The source of the error\n\nStack backtrace:\ndisabled backtrace", - ); +Stack backtrace: +{}", trace); + let mut error = GenericError::new("Error with backtrace"); + error.backtrace = Some(trace); + let error = GenericError::new_with_source("The source of the error", error); + let error = GenericError::new_with_source("Error with two sources", error); + let report = Report::new(error).pretty(true).show_backtrace(true); - assert_eq!(expected, report.to_string()); + + println!("Error: {}", report); + assert_eq!(expected.trim_end(), report.to_string()); } #[derive(Debug)] struct GenericError { message: D, + backtrace: Option, source: Option>, } impl GenericError { fn new(message: D) -> GenericError { - Self { message, source: None } + Self { message, backtrace: None, source: None } } fn new_with_source(message: D, source: E) -> GenericError @@ -160,7 +166,7 @@ impl GenericError { { let source: Box = Box::new(source); let source = Some(source); - GenericError { message, source } + GenericError { message, backtrace: None, source } } } @@ -180,6 +186,10 @@ where fn source(&self) -> Option<&(dyn Error + 'static)> { self.source.as_deref() } + + fn backtrace(&self) -> Option<&Backtrace> { + self.backtrace.as_ref() + } } #[test] @@ -254,24 +264,24 @@ 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"#; + 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); @@ -297,8 +307,12 @@ The message Caused by: - 0: The message - 1: The message"#; + 0: + The message + + 1: + The message + "#; let actual = report.to_string(); assert_eq!(expected, actual); @@ -326,3 +340,59 @@ Caused by: let actual = report.to_string(); assert_eq!(expected, actual); } + +#[test] +fn empty_lines_mid_message() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("line 1\n\nline 2") + } + } + + 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#"line 1 + +line 2 + +Caused by: + 0: line 1 + + line 2 + 1: line 1 + + line 2"#; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} + +#[test] +fn only_one_source() { + #[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") + } + } + + let error = GenericError::new(MyMessage); + let error = GenericError::new_with_source(MyMessage, error); + let report = Report::new(error).pretty(true); + let expected = r#"line 1 +line 2 + +Caused by: + line 1 + line 2"#; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} From 4420cc33d6686c9d4ae6bf490b977fc47e56d340 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 14:06:28 -0800 Subject: [PATCH 09/21] Update report output and fix examples --- library/std/src/error.rs | 195 +++++++++++++++++++++++++++------ library/std/src/error/tests.rs | 132 ++++++++++++++-------- 2 files changed, 245 insertions(+), 82 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 10de248c3d7ec..a2b4eb2117dcc 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -808,9 +808,11 @@ impl dyn Error + Send + Sync { } } -/// An error reporter that exposes the entire error chain for printing. -/// It also exposes options for formatting the error chain, either entirely on a single line, -/// or in multi-line format with each cause in the error chain on a new line. +/// An error reporter that print's an error and its sources. +/// +/// Report also exposes configuration options for formatting the error chain, either entirely on a +/// single line, or in multi-line format with each cause in the error chain on a new line. +/// /// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the /// wrapped error be `Send`, `Sync`, or `'static`. /// @@ -818,33 +820,51 @@ impl dyn Error + Send + Sync { /// /// ```rust /// #![feature(error_reporter)] -/// #![feature(negative_impls)] -/// /// use std::error::{Error, Report}; /// use std::fmt; /// /// #[derive(Debug)] -/// struct SuperError<'a> { -/// side: &'a str, +/// struct SuperError { +/// source: SuperErrorSideKick, /// } /// -/// impl<'a> fmt::Display for SuperError<'a> { +/// impl fmt::Display for SuperError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperError is here: {}", self.side) +/// write!(f, "SuperError is here!") /// } /// } /// -/// impl<'a> Error for SuperError<'a> {} +/// impl Error for SuperError { +/// fn source(&self) -> Option<&(dyn Error + 'static)> { +/// Some(&self.source) +/// } +/// } /// -/// fn main() { -/// let msg = String::from("Huzzah!"); -/// let error = SuperError { side: &msg }; -/// let report = Report::new(&error).pretty(true); +/// #[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 {} /// -/// println!("{}", report); +/// fn get_super_error() -> Result<(), SuperError> { +/// Err(SuperError { source: SuperErrorSideKick }) +/// } +/// +/// fn main() { +/// match get_super_error() { +/// Err(e) => { +/// let report = Report::new(e).pretty(true); +/// println!("Error: {}", report); +/// } +/// _ => println!("No error"), +/// } /// } /// ``` - #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { /// The error being reported. @@ -865,14 +885,129 @@ where Report { error, show_backtrace: false, pretty: false } } - /// Enable pretty-printing the report. + /// Enable pretty-printing the report across multiple lines. + /// + /// # Examples + /// + /// ```rust + /// #![feature(error_reporter)] + /// use std::error::Report; + /// # use std::error::Error; + /// # use std::fmt; + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: 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.source) + /// # } + /// # } + /// # #[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 {} + /// + /// let error = SuperError { source: SuperErrorSideKick }; + /// let report = Report::new(error).pretty(true); + /// eprintln!("Error: {:?}", report); + /// ``` + /// + /// This example produces the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// SuperErrorSideKick is here! + /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn pretty(mut self, pretty: bool) -> Self { self.pretty = pretty; self } - /// Enable showing a backtrace for the report. + /// Display backtrace if available when using pretty output format. + /// + /// # Examples + /// + /// ```rust + /// #![feature(error_reporter)] + /// #![feature(backtrace)] + /// use std::error::{Error, Report}; + /// use std::backtrace::Backtrace; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct SuperError { + /// source: 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.source) + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SuperErrorSideKick { + /// backtrace: Backtrace, + /// } + /// + /// impl fmt::Display for SuperErrorSideKick { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperErrorSideKick is here!") + /// } + /// } + /// + /// impl Error for SuperErrorSideKick { + /// fn backtrace(&self) -> Option<&Backtrace> { + /// Some(&self.backtrace) + /// } + /// } + /// + /// let source = SuperErrorSideKick { backtrace: Backtrace::force_capture() }; + /// let error = SuperError { source }; + /// let report = Report::new(error).pretty(true).show_backtrace(true); + /// eprintln!("Error: {:?}", report); + /// ``` + /// + /// This example produces something similar to the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// SuperErrorSideKick is here! + /// + /// Stack backtrace: + /// 0: rust_out::main::_doctest_main_src_error_rs_943_0 + /// 1: rust_out::main + /// 2: core::ops::function::FnOnce::call_once + /// 3: std::sys_common::backtrace::__rust_begin_short_backtrace + /// 4: std::rt::lang_start::{{closure}} + /// 5: std::panicking::try + /// 6: std::rt::lang_start_internal + /// 7: std::rt::lang_start + /// 8: main + /// 9: __libc_start_main + /// 10: _start + /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { self.show_backtrace = show_backtrace; @@ -922,10 +1057,12 @@ where writeln!(f)?; let mut indented = Indented { inner: f, - number: if multiple { Some(ind) } else { None }, - started: false, }; - write!(indented, "{}", error)?; + if multiple { + write!(indented, "{: >4}: {}", ind, error)?; + } else { + write!(indented, " {}", error)?; + } } } @@ -979,8 +1116,6 @@ where /// Wrapper type for indenting the inner source. struct Indented<'a, D> { inner: &'a mut D, - number: Option, - started: bool, } impl Write for Indented<'_, T> @@ -989,19 +1124,9 @@ where { fn write_str(&mut self, s: &str) -> fmt::Result { for (i, line) in s.split('\n').enumerate() { - if !self.started { - self.started = true; - match self.number { - Some(number) => write!(self.inner, "{: >5}: ", number)?, - None => self.inner.write_str(" ")?, - } - } else if i > 0 { + if i > 0 { self.inner.write_char('\n')?; - if self.number.is_some() { - self.inner.write_str(" ")?; - } else { - self.inner.write_str(" ")?; - } + self.inner.write_str(" ")?; } self.inner.write_str(line)?; diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index 82ef39ae90fb6..0835e282c46c3 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -82,8 +82,11 @@ fn multi_line_formatting() { let error = SuperError { source: 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!"); + let expected = String::from("\ +SuperError is here! + +Caused by: + SuperErrorSideKick is here!"); assert_eq!(expected, actual); } @@ -109,10 +112,11 @@ fn error_with_no_sources_formats_multi_line_correctly() { #[test] fn error_with_backtrace_outputs_correctly_with_one_source() { let trace = Backtrace::force_capture(); - let expected = format!("The source of the error + let expected = format!("\ +The source of the error Caused by: - Error with backtrace + Error with backtrace Stack backtrace: {}", trace); @@ -129,11 +133,12 @@ Stack backtrace: #[test] fn error_with_backtrace_outputs_correctly_with_two_sources() { let trace = Backtrace::force_capture(); - let expected = format!("Error with two sources + let expected = format!("\ +Error with two sources Caused by: - 0: The source of the error - 1: Error with backtrace + 0: The source of the error + 1: Error with backtrace Stack backtrace: {}", trace); @@ -211,7 +216,8 @@ fn error_formats_single_line_with_rude_display_impl() { 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 + let expected = "\ +line 1 line 2 line 3 line 4 @@ -231,7 +237,7 @@ line 2 line 3 line 4 line 5 -line 6"#; +line 6"; let actual = report.to_string(); assert_eq!(expected, actual); @@ -256,7 +262,7 @@ fn error_formats_multi_line_with_rude_display_impl() { 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 + let expected = "line 1 line 2 line 3 line 4 @@ -264,24 +270,24 @@ 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"#; + 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); @@ -302,19 +308,48 @@ fn errors_that_start_with_newline_formats_correctly() { 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#" + let expected = " The message Caused by: - 0: - The message - - 1: - The message - "#; + 0: + The message + + 1: + The message + "; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} + +#[test] +fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("The message")?; + f.write_str(" goes on")?; + f.write_str(" and on.") + } + } + + 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 = "\ +The message goes on and on. + +Caused by: + 0: The message goes on and on. + 1: The message goes on and on."; let actual = report.to_string(); + println!("{}", actual); assert_eq!(expected, actual); } @@ -333,10 +368,11 @@ fn errors_with_string_interpolation_formats_correctly() { 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? + let expected = "\ +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?"#; + Got an error code: (10). What would you like to do in response?"; let actual = report.to_string(); assert_eq!(expected, actual); } @@ -356,17 +392,18 @@ fn empty_lines_mid_message() { 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 + let expected = "\ +line 1 line 2 Caused by: - 0: line 1 - - line 2 - 1: line 1 - - line 2"#; + 0: line 1 + + line 2 + 1: line 1 + + line 2"; let actual = report.to_string(); assert_eq!(expected, actual); @@ -386,12 +423,13 @@ fn only_one_source() { let error = GenericError::new(MyMessage); let error = GenericError::new_with_source(MyMessage, error); let report = Report::new(error).pretty(true); - let expected = r#"line 1 + let expected = "\ +line 1 line 2 Caused by: - line 1 - line 2"#; + line 1 + line 2"; let actual = report.to_string(); assert_eq!(expected, actual); From 078b112d9452eb24cf6d5dffe8f4479cbe830d4e Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 14:22:35 -0800 Subject: [PATCH 10/21] add a panicking example --- library/std/src/error.rs | 55 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index a2b4eb2117dcc..cb74a0084c66d 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -857,14 +857,61 @@ impl dyn Error + Send + Sync { /// /// fn main() { /// match get_super_error() { -/// Err(e) => { -/// let report = Report::new(e).pretty(true); -/// println!("Error: {}", report); -/// } +/// Err(e) => println!("Error: {}", Report::new(e)), /// _ => println!("No error"), /// } /// } /// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here!: SuperErrorSideKick is here! +/// ``` +/// +/// Report prints the same output via `Display` and `Debug`, so it works well with +/// [`unwrap`]/[`expect`]: +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: 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.source) +/// # } +/// # } +/// # #[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 {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// get_super_error().map_err(Report::new).unwrap(); +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 +/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +/// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { /// The error being reported. From 9be1cc9b6133fc8341ab605d426e675746144f29 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 15:32:31 -0800 Subject: [PATCH 11/21] more docs improvements --- library/std/src/error.rs | 242 +++++++++++++++++++++++++++++++++------ 1 file changed, 207 insertions(+), 35 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index cb74a0084c66d..07f04aa2b911b 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -869,8 +869,10 @@ impl dyn Error + Send + Sync { /// Error: SuperError is here!: SuperErrorSideKick is here! /// ``` /// +/// ## Output consistency +/// /// Report prints the same output via `Display` and `Debug`, so it works well with -/// [`unwrap`]/[`expect`]: +/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: /// /// ```should_panic /// #![feature(error_reporter)] @@ -912,6 +914,104 @@ impl dyn Error + Send + Sync { /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace /// ``` +// /// TODO: Report doesn't yet support return from `main` gracefully, fix in followup (yaahc) +// /// ## Return from `main` +// /// +// /// `Report` also implements `From` for all types that implement [`Error`], this when combined with +// /// the `Debug` output means `Report` is an ideal starting place for formatting errors returned +// /// from `main`. +// /// +// /// ``` +// /// #![feature(error_reporter)] +// /// use std::error::Report; +// /// # use std::error::Error; +// /// # use std::fmt; +// /// # #[derive(Debug)] +// /// # struct SuperError { +// /// # source: 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.source) +// /// # } +// /// # } +// /// # #[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 {} +// /// # fn get_super_error() -> Result<(), SuperError> { +// /// # Err(SuperError { source: SuperErrorSideKick }) +// /// # } +// /// +// /// fn main() -> Result<(), Report> { +// /// get_super_error()?; +// /// } +// /// ``` +// /// +// /// This example produces the following output: +// /// +// /// ```console +// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 +// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +// /// ``` +// /// +// /// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line +// /// output format, if you want to make sure your `Report`s are pretty printed and include backtrace +// /// you will need to manually convert and enable those flags. +// /// +// /// ``` +// /// #![feature(error_reporter)] +// /// use std::error::Report; +// /// # use std::error::Error; +// /// # use std::fmt; +// /// # #[derive(Debug)] +// /// # struct SuperError { +// /// # source: 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.source) +// /// # } +// /// # } +// /// # #[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 {} +// /// # fn get_super_error() -> Result<(), SuperError> { +// /// # Err(SuperError { source: SuperErrorSideKick }) +// /// # } +// /// +// /// fn main() -> Result<(), Report> { +// /// get_super_error() +// /// .map_err(Report::new) +// /// .map_err(|r| r.pretty(true).show_backtrace(true))?; +// /// } +// /// ``` +// /// +// /// This example produces the following output: +// /// +// /// ```console +// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 +// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +// /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { /// The error being reported. @@ -977,6 +1077,68 @@ where /// Caused by: /// SuperErrorSideKick is here! /// ``` + /// + /// When there are multiple source errors the causes will be numbered in order of iteration + /// starting from the outermost error. + /// + /// ```rust + /// #![feature(error_reporter)] + /// use std::error::Report; + /// # use std::error::Error; + /// # use std::fmt; + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: 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.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKick { + /// # source: SuperErrorSideKickSideKick, + /// # } + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKick { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKickSideKick; + /// # impl fmt::Display for SuperErrorSideKickSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKickSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKickSideKick { } + /// + /// let source = SuperErrorSideKickSideKick; + /// let source = SuperErrorSideKick { source }; + /// let error = SuperError { source }; + /// let report = Report::new(error).pretty(true); + /// eprintln!("Error: {:?}", report); + /// ``` + /// + /// This example produces the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// 0: SuperErrorSideKick is here! + /// 1: SuperErrorSideKickSideKick is here! + /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn pretty(mut self, pretty: bool) -> Self { self.pretty = pretty; @@ -987,38 +1149,40 @@ where /// /// # Examples /// + /// **Note**: Report will search for the first `Backtrace` it can find starting from the + /// outermost error. In this example it will display the backtrace from the second error in the + /// chain, `SuperErrorSideKick`. + /// /// ```rust /// #![feature(error_reporter)] /// #![feature(backtrace)] - /// use std::error::{Error, Report}; + /// # use std::error::Error; + /// # use std::fmt; + /// use std::error::Report; /// use std::backtrace::Backtrace; - /// use std::fmt; - /// - /// #[derive(Debug)] - /// struct SuperError { - /// source: 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.source) - /// } - /// } /// + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: 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.source) + /// # } + /// # } /// #[derive(Debug)] /// struct SuperErrorSideKick { /// backtrace: Backtrace, /// } /// - /// impl fmt::Display for SuperErrorSideKick { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "SuperErrorSideKick is here!") + /// impl SuperErrorSideKick { + /// fn new() -> SuperErrorSideKick { + /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } /// } /// } /// @@ -1028,7 +1192,14 @@ where /// } /// } /// - /// let source = SuperErrorSideKick { backtrace: Backtrace::force_capture() }; + /// // The rest of the example is unchanged ... + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// + /// let source = SuperErrorSideKick::new(); /// let error = SuperError { source }; /// let report = Report::new(error).pretty(true).show_backtrace(true); /// eprintln!("Error: {:?}", report); @@ -1043,17 +1214,18 @@ where /// SuperErrorSideKick is here! /// /// Stack backtrace: - /// 0: rust_out::main::_doctest_main_src_error_rs_943_0 - /// 1: rust_out::main - /// 2: core::ops::function::FnOnce::call_once - /// 3: std::sys_common::backtrace::__rust_begin_short_backtrace - /// 4: std::rt::lang_start::{{closure}} - /// 5: std::panicking::try - /// 6: std::rt::lang_start_internal - /// 7: std::rt::lang_start - /// 8: main - /// 9: __libc_start_main - /// 10: _start + /// 0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new + /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0 + /// 2: rust_out::main + /// 3: core::ops::function::FnOnce::call_once + /// 4: std::sys_common::backtrace::__rust_begin_short_backtrace + /// 5: std::rt::lang_start::{{closure}} + /// 6: std::panicking::try + /// 7: std::rt::lang_start_internal + /// 8: std::rt::lang_start + /// 9: main + /// 10: __libc_start_main + /// 11: _start /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { From 5b3902fc6550f7646c4612c7ff8f4d8712f13334 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 16:08:30 -0800 Subject: [PATCH 12/21] attempt to make Report usable with Box dyn Error and fn main --- library/std/src/error.rs | 304 ++++++++++++++++++++++++++------------- 1 file changed, 201 insertions(+), 103 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 07f04aa2b911b..5514876c5d3b8 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -914,106 +914,109 @@ impl dyn Error + Send + Sync { /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace /// ``` -// /// TODO: Report doesn't yet support return from `main` gracefully, fix in followup (yaahc) -// /// ## Return from `main` -// /// -// /// `Report` also implements `From` for all types that implement [`Error`], this when combined with -// /// the `Debug` output means `Report` is an ideal starting place for formatting errors returned -// /// from `main`. -// /// -// /// ``` -// /// #![feature(error_reporter)] -// /// use std::error::Report; -// /// # use std::error::Error; -// /// # use std::fmt; -// /// # #[derive(Debug)] -// /// # struct SuperError { -// /// # source: 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.source) -// /// # } -// /// # } -// /// # #[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 {} -// /// # fn get_super_error() -> Result<(), SuperError> { -// /// # Err(SuperError { source: SuperErrorSideKick }) -// /// # } -// /// -// /// fn main() -> Result<(), Report> { -// /// get_super_error()?; -// /// } -// /// ``` -// /// -// /// This example produces the following output: -// /// -// /// ```console -// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 -// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -// /// ``` -// /// -// /// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line -// /// output format, if you want to make sure your `Report`s are pretty printed and include backtrace -// /// you will need to manually convert and enable those flags. -// /// -// /// ``` -// /// #![feature(error_reporter)] -// /// use std::error::Report; -// /// # use std::error::Error; -// /// # use std::fmt; -// /// # #[derive(Debug)] -// /// # struct SuperError { -// /// # source: 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.source) -// /// # } -// /// # } -// /// # #[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 {} -// /// # fn get_super_error() -> Result<(), SuperError> { -// /// # Err(SuperError { source: SuperErrorSideKick }) -// /// # } -// /// -// /// fn main() -> Result<(), Report> { -// /// get_super_error() -// /// .map_err(Report::new) -// /// .map_err(|r| r.pretty(true).show_backtrace(true))?; -// /// } -// /// ``` -// /// -// /// This example produces the following output: -// /// -// /// ```console -// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 -// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -// /// ``` +/// +/// ## Return from `main` +/// +/// `Report` also implements `From` for all types that implement [`Error`], this when combined with +/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned +/// from `main`. +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: 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.source) +/// # } +/// # } +/// # #[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 {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// fn main() -> Result<(), Report> { +/// get_super_error()?; +/// Ok(()) +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here!: SuperErrorSideKick is here! +/// ``` +/// +/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line +/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace +/// you will need to manually convert and enable those flags. +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: 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.source) +/// # } +/// # } +/// # #[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 {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// fn main() -> Result<(), Report> { +/// get_super_error() +/// .map_err(Report::from) +/// .map_err(|r| r.pretty(true).show_backtrace(true))?; +/// Ok(()) +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here! +/// +/// Caused by: +/// SuperErrorSideKick is here! +/// ``` #[unstable(feature = "error_reporter", issue = "90172")] -pub struct Report { +pub struct Report> { /// The error being reported. error: E, /// Whether a backtrace should be included as part of the report. @@ -1024,14 +1027,16 @@ pub struct Report { impl Report where - E: Error, + Report: From, { /// Create a new `Report` from an input error. #[unstable(feature = "error_reporter", issue = "90172")] pub fn new(error: E) -> Report { - Report { error, show_backtrace: false, pretty: false } + Self::from(error) } +} +impl Report { /// Enable pretty-printing the report across multiple lines. /// /// # Examples @@ -1232,7 +1237,81 @@ where self.show_backtrace = show_backtrace; self } +} + +impl Report +where + E: Error, +{ + fn backtrace(&self) -> Option<&Backtrace> { + // have to grab the backtrace on the first error directly since that error may not be + // 'static + let backtrace = self.error.backtrace(); + let backtrace = backtrace.or_else(|| { + self.error + .source() + .map(|source| source.chain().find_map(|source| source.backtrace())) + .flatten() + }); + backtrace + } + + /// Format the report as a single line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.error)?; + + let sources = self.error.source().into_iter().flat_map(::chain); + + for cause in sources { + write!(f, ": {}", cause)?; + } + + Ok(()) + } + + /// Format the report as multiple lines, with each error cause on its own line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let error = &self.error; + + write!(f, "{}", error)?; + + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; + + let multiple = cause.source().is_some(); + + for (ind, error) in cause.chain().enumerate() { + writeln!(f)?; + let mut indented = Indented { + inner: f, + }; + if multiple { + write!(indented, "{: >4}: {}", ind, error)?; + } else { + write!(indented, " {}", error)?; + } + } + } + + if self.show_backtrace { + let backtrace = self.backtrace(); + + if let Some(backtrace) = backtrace { + let backtrace = backtrace.to_string(); + + f.write_str("\n\nStack backtrace:\n")?; + f.write_str(backtrace.trim_end())?; + } + } + + Ok(()) + } +} +impl Report> +{ fn backtrace(&self) -> Option<&Backtrace> { // have to grab the backtrace on the first error directly since that error may not be // 'static @@ -1306,7 +1385,18 @@ where E: Error, { fn from(error: E) -> Self { - Report::new(error) + Report { error, show_backtrace: false, pretty: false } + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl<'a, E> From for Report> +where + E: Error + 'a, +{ + fn from(error: E) -> Self { + let error = box error; + Report { error, show_backtrace: false, pretty: false } } } @@ -1320,12 +1410,20 @@ where } } +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Display for Report> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } + } +} + // This type intentionally outputs the same format for `Display` and `Debug`for // situations where you unwrap a `Report` or return it from main. #[unstable(feature = "error_reporter", issue = "90172")] impl fmt::Debug for Report where - E: Error, + Report: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) From e9fbe79292783972a222afd270db3f77c0b4f3c8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 27 Dec 2021 16:20:50 -0800 Subject: [PATCH 13/21] Remove &self from PrintState::to_string --- compiler/rustc_ast_pretty/src/pprust/mod.rs | 4 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 44 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 4b5703a429e71..ac9e7d06c4e40 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -73,11 +73,11 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String { } pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { - State::new().to_string(f) + State::to_string(f) } pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String { - State::new().to_string(|s| { + State::to_string(|s| { s.print_inner_attributes(&krate.attrs); for item in &krate.items { s.print_item(item); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6c5b38bc4bb15..95615164ac751 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -211,7 +211,7 @@ pub fn literal_to_string(lit: token::Lit) -> String { } fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { - format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s) + format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s) } impl std::ops::Deref for State<'_> { @@ -792,55 +792,55 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } fn ty_to_string(&self, ty: &ast::Ty) -> String { - self.to_string(|s| s.print_type(ty)) + Self::to_string(|s| s.print_type(ty)) } fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String { - self.to_string(|s| s.print_type_bounds("", bounds)) + Self::to_string(|s| s.print_type_bounds("", bounds)) } fn pat_to_string(&self, pat: &ast::Pat) -> String { - self.to_string(|s| s.print_pat(pat)) + Self::to_string(|s| s.print_pat(pat)) } fn expr_to_string(&self, e: &ast::Expr) -> String { - self.to_string(|s| s.print_expr(e)) + Self::to_string(|s| s.print_expr(e)) } fn tt_to_string(&self, tt: &TokenTree) -> String { - self.to_string(|s| s.print_tt(tt, false)) + Self::to_string(|s| s.print_tt(tt, false)) } fn tts_to_string(&self, tokens: &TokenStream) -> String { - self.to_string(|s| s.print_tts(tokens, false)) + Self::to_string(|s| s.print_tts(tokens, false)) } fn stmt_to_string(&self, stmt: &ast::Stmt) -> String { - self.to_string(|s| s.print_stmt(stmt)) + Self::to_string(|s| s.print_stmt(stmt)) } fn item_to_string(&self, i: &ast::Item) -> String { - self.to_string(|s| s.print_item(i)) + Self::to_string(|s| s.print_item(i)) } fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String { - self.to_string(|s| s.print_generic_params(generic_params)) + Self::to_string(|s| s.print_generic_params(generic_params)) } fn path_to_string(&self, p: &ast::Path) -> String { - self.to_string(|s| s.print_path(p, false, 0)) + Self::to_string(|s| s.print_path(p, false, 0)) } fn path_segment_to_string(&self, p: &ast::PathSegment) -> String { - self.to_string(|s| s.print_path_segment(p, false)) + Self::to_string(|s| s.print_path_segment(p, false)) } fn vis_to_string(&self, v: &ast::Visibility) -> String { - self.to_string(|s| s.print_visibility(v)) + Self::to_string(|s| s.print_visibility(v)) } fn block_to_string(&self, blk: &ast::Block) -> String { - self.to_string(|s| { + Self::to_string(|s| { // Containing cbox, will be closed by `print_block` at `}`. s.cbox(INDENT_UNIT); // Head-ibox, will be closed by `print_block` after `{`. @@ -850,22 +850,22 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { - self.to_string(|s| s.print_meta_list_item(li)) + Self::to_string(|s| s.print_meta_list_item(li)) } fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String { - self.to_string(|s| s.print_attr_item(ai, ai.path.span)) + Self::to_string(|s| s.print_attr_item(ai, ai.path.span)) } fn attribute_to_string(&self, attr: &ast::Attribute) -> String { - self.to_string(|s| s.print_attribute(attr)) + Self::to_string(|s| s.print_attribute(attr)) } fn param_to_string(&self, arg: &ast::Param) -> String { - self.to_string(|s| s.print_param(arg, false)) + Self::to_string(|s| s.print_param(arg, false)) } - fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String { + fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { let mut printer = State::new(); f(&mut printer); printer.s.eof() @@ -1199,7 +1199,7 @@ impl<'a> State<'a> { ); } ast::ItemKind::Mod(unsafety, ref mod_kind) => { - self.head(self.to_string(|s| { + self.head(Self::to_string(|s| { s.print_visibility(&item.vis); s.print_unsafety(unsafety); s.word("mod"); @@ -1225,7 +1225,7 @@ impl<'a> State<'a> { } } ast::ItemKind::ForeignMod(ref nmod) => { - self.head(self.to_string(|s| { + self.head(Self::to_string(|s| { s.print_unsafety(nmod.unsafety); s.word("extern"); })); @@ -1444,7 +1444,7 @@ impl<'a> State<'a> { ast::CrateSugar::JustCrate => self.word_nbsp("crate"), }, ast::VisibilityKind::Restricted { ref path, .. } => { - let path = self.to_string(|s| s.print_path(path, false, 0)); + let path = Self::to_string(|s| s.print_path(path, false, 0)); if path == "self" || path == "super" { self.word_nbsp(format!("pub({})", path)) } else { From 65f7fbc12cd938910e909a74f64e4712b79e3543 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 26 Dec 2021 22:12:41 +0800 Subject: [PATCH 14/21] mangling_v0: Update tests for the rust-demangler tool --- src/tools/rust-demangler/tests/lib.rs | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tools/rust-demangler/tests/lib.rs b/src/tools/rust-demangler/tests/lib.rs index 5a67b42322535..85019df7867dd 100644 --- a/src/tools/rust-demangler/tests/lib.rs +++ b/src/tools/rust-demangler/tests/lib.rs @@ -29,14 +29,14 @@ cc[4d6468d6c9fd4bb3]::spawn::{closure#0}::{closure#0} as core[846817f741e54dfd]::iter::iterator::Iterator>::rposition::::{closure#0} alloc[f15a878b47eb696b]::alloc::box_free::> INtC8arrayvec8ArrayVechKj7b_E -> -> -> -> -> -> -> -> +> +> +> +> +> +> +> +> >::foo::FOO foo[0] foo[0] @@ -51,14 +51,14 @@ cc::spawn::{closure#0}::{closure#0} as core::iter::iterator::Iterator>::rposition::::{closure#0} alloc::alloc::box_free::> INtC8arrayvec8ArrayVechKj7b_E -> -> -> -> -> -> -> -> +> +> +> +> +> +> +> +> >::foo::FOO foo[0] foo[0] From 14cd80dd07bf51514c5de452da0a33e8940d454e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 27 Dec 2021 20:05:22 +0800 Subject: [PATCH 15/21] mangling_v0: Add a test for mangling of foreign types --- src/test/ui/symbol-names/foreign-types.rs | 19 ++++++++++++++++++ src/test/ui/symbol-names/foreign-types.stderr | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/test/ui/symbol-names/foreign-types.rs create mode 100644 src/test/ui/symbol-names/foreign-types.stderr diff --git a/src/test/ui/symbol-names/foreign-types.rs b/src/test/ui/symbol-names/foreign-types.rs new file mode 100644 index 0000000000000..33c5e6adfef29 --- /dev/null +++ b/src/test/ui/symbol-names/foreign-types.rs @@ -0,0 +1,19 @@ +// build-fail +// compile-flags: -Z symbol-mangling-version=v0 + +#![feature(extern_types)] +#![feature(rustc_attrs)] + +extern "C" { + type ForeignType; +} + +struct Check(T); + +#[rustc_symbol_name] +//~^ ERROR symbol-name(_RMCs +//~| ERROR demangling(>) +impl Check {} + +fn main() {} diff --git a/src/test/ui/symbol-names/foreign-types.stderr b/src/test/ui/symbol-names/foreign-types.stderr new file mode 100644 index 0000000000000..c6c59a6c82ea7 --- /dev/null +++ b/src/test/ui/symbol-names/foreign-types.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB_5CheckNvNtB_011ForeignTypeE) + --> $DIR/foreign-types.rs:13:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>) + --> $DIR/foreign-types.rs:13:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>) + --> $DIR/foreign-types.rs:13:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From 6bbbaf9c1fb0e867d43407da101f4e07f48ccec2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 27 Dec 2021 20:09:20 +0800 Subject: [PATCH 16/21] mangling_v0: Skip extern blocks during mangling --- compiler/rustc_symbol_mangling/src/v0.rs | 6 +++--- src/test/ui/symbol-names/foreign-types.stderr | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index c2519adcbe416..fbb9e28d182f8 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -771,9 +771,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result { let ns = match disambiguated_data.data { - // FIXME: It shouldn't be necessary to add anything for extern block segments, - // but we add 't' for backward compatibility. - DefPathData::ForeignMod => 't', + // Extern block segments can be skipped, names from extern blocks + // are effectively living in their parent modules. + DefPathData::ForeignMod => return print_prefix(self), // Uppercase categories are more stable than lowercase ones. DefPathData::TypeNs(_) => 't', diff --git a/src/test/ui/symbol-names/foreign-types.stderr b/src/test/ui/symbol-names/foreign-types.stderr index c6c59a6c82ea7..fcffdd2a8ec15 100644 --- a/src/test/ui/symbol-names/foreign-types.stderr +++ b/src/test/ui/symbol-names/foreign-types.stderr @@ -1,4 +1,4 @@ -error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB_5CheckNvNtB_011ForeignTypeE) +error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB_5CheckNvB_11ForeignTypeE) --> $DIR/foreign-types.rs:13:1 | LL | #[rustc_symbol_name] From 3632f41c78eb848f0ffae6bc347b27f7cf3eeda7 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Fri, 7 Jan 2022 01:04:37 +0100 Subject: [PATCH 17/21] Stabilize `#[feature(available_parallelism)]` --- library/std/src/thread/mod.rs | 3 +-- library/test/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 9f7f10d0d0081..ae4b65871ecb1 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1504,7 +1504,6 @@ fn _assert_sync_and_send() { /// /// ``` /// # #![allow(dead_code)] -/// #![feature(available_parallelism)] /// use std::{io, thread}; /// /// fn main() -> io::Result<()> { @@ -1516,7 +1515,7 @@ fn _assert_sync_and_send() { #[doc(alias = "available_concurrency")] // Alias for a previous name we gave this API on unstable. #[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`. #[doc(alias = "num_cpus")] // Alias for a popular ecosystem crate which provides similar functionality. -#[unstable(feature = "available_parallelism", issue = "74479")] +#[stable(feature = "available_parallelism", since = "1.59.0")] pub fn available_parallelism() -> io::Result { imp::available_parallelism() } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 608e587cf34f3..fad83094cdf8a 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -16,7 +16,6 @@ #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] #![feature(nll)] -#![feature(available_parallelism)] #![feature(bench_black_box)] #![feature(internal_output_capture)] #![feature(staged_api)] From 5ebe97b77a0f63b8646fd55f206c057f213040b4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 24 Dec 2021 14:34:30 +0800 Subject: [PATCH 18/21] rustc_metadata: Stop passing `CrateMetadataRef` by reference It's already a (fat) reference. Double referencing it creates lifetime issues for its methods that want to return iterators. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 192 +++++++++---------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index bb9a58a0b62aa..6183042cea63e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -218,40 +218,40 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) { } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> { +impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> { #[inline] fn blob(self) -> &'a MetadataBlob { - &self.blob + &self.cdata.blob } #[inline] fn cdata(self) -> Option> { - Some(*self) + Some(self) } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) { #[inline] fn blob(self) -> &'a MetadataBlob { - &self.0.blob + &self.0.cdata.blob } #[inline] fn cdata(self) -> Option> { - Some(*self.0) + Some(self.0) } #[inline] fn sess(self) -> Option<&'tcx Session> { - Some(&self.1) + Some(self.1) } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) { #[inline] fn blob(self) -> &'a MetadataBlob { - &self.0.blob + &self.0.cdata.blob } #[inline] fn cdata(self) -> Option> { - Some(*self.0) + Some(self.0) } #[inline] fn tcx(self) -> Option> { @@ -415,9 +415,9 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { Ok(cdata .root .syntax_contexts - .get(&cdata, id) + .get(cdata, id) .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname)) - .decode((&cdata, sess))) + .decode((cdata, sess))) }) } } @@ -443,15 +443,15 @@ impl<'a, 'tcx> Decodable> for ExpnId { let expn_data = crate_data .root .expn_data - .get(&crate_data, index) + .get(crate_data, index) .unwrap() - .decode((&crate_data, sess)); + .decode((crate_data, sess)); let expn_hash = crate_data .root .expn_hashes - .get(&crate_data, index) + .get(crate_data, index) .unwrap() - .decode((&crate_data, sess)); + .decode((crate_data, sess)); (expn_data, expn_hash) }); Ok(expn_id) @@ -707,7 +707,7 @@ impl CrateRoot<'_> { } impl<'a, 'tcx> CrateMetadataRef<'a> { - fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { + fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. let pos = self @@ -722,7 +722,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { &self.raw_proc_macros.unwrap()[pos] } - fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option { + fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option { let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?; let span = match self.root.tables.ident_span.get(self, item_index) { Some(lazy_span) => lazy_span.decode((self, sess)), @@ -738,15 +738,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { Some(Ident::new(name, span)) } - fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident { + fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident { self.opt_item_ident(item_index, sess).expect("no encoded ident for item") } - fn maybe_kind(&self, item_id: DefIndex) -> Option { + fn maybe_kind(self, item_id: DefIndex) -> Option { self.root.tables.kind.get(self, item_id).map(|k| k.decode(self)) } - fn kind(&self, item_id: DefIndex) -> EntryKind { + fn kind(self, item_id: DefIndex) -> EntryKind { self.maybe_kind(item_id).unwrap_or_else(|| { bug!( "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}", @@ -757,7 +757,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn def_kind(&self, item_id: DefIndex) -> DefKind { + fn def_kind(self, item_id: DefIndex) -> DefKind { self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| { bug!( "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}", @@ -768,7 +768,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn get_span(&self, index: DefIndex, sess: &Session) -> Span { + fn get_span(self, index: DefIndex, sess: &Session) -> Span { self.root .tables .span @@ -777,7 +777,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { + fn load_proc_macro(self, id: DefIndex, sess: &Session) -> SyntaxExtension { let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) { ProcMacro::CustomDerive { trait_name, attributes, client } => { let helper_attrs = @@ -808,7 +808,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { + fn get_trait_def(self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { match self.kind(item_id) { EntryKind::Trait(data) => { let data = data.decode((self, sess)); @@ -838,7 +838,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_variant( - &self, + self, kind: &EntryKind, index: DefIndex, parent_did: DefId, @@ -887,7 +887,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef { + fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef { let kind = self.kind(item_id); let did = self.local_def_id(item_id); @@ -915,7 +915,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_explicit_predicates( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { @@ -923,7 +923,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_inferred_outlives( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { @@ -936,7 +936,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_super_predicates( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { @@ -944,7 +944,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_explicit_item_bounds( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { @@ -956,11 +956,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .unwrap_or_default() } - fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics { + fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics { self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess)) } - fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + fn get_type(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { self.root .tables .ty @@ -969,59 +969,59 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_stability(&self, id: DefIndex) -> Option { + fn get_stability(self, id: DefIndex) -> Option { self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)) } - fn get_const_stability(&self, id: DefIndex) -> Option { + fn get_const_stability(self, id: DefIndex) -> Option { self.root.tables.const_stability.get(self, id).map(|stab| stab.decode(self)) } - fn get_deprecation(&self, id: DefIndex) -> Option { + fn get_deprecation(self, id: DefIndex) -> Option { self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self)) } - fn get_visibility(&self, id: DefIndex) -> ty::Visibility { + fn get_visibility(self, id: DefIndex) -> ty::Visibility { self.root.tables.visibility.get(self, id).unwrap().decode(self) } - fn get_impl_data(&self, id: DefIndex) -> ImplData { + fn get_impl_data(self, id: DefIndex) -> ImplData { match self.kind(id) { EntryKind::Impl(data) => data.decode(self), _ => bug!(), } } - fn get_parent_impl(&self, id: DefIndex) -> Option { + fn get_parent_impl(self, id: DefIndex) -> Option { self.get_impl_data(id).parent_impl } - fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity { + fn get_impl_polarity(self, id: DefIndex) -> ty::ImplPolarity { self.get_impl_data(id).polarity } - fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness { + fn get_impl_defaultness(self, id: DefIndex) -> hir::Defaultness { self.get_impl_data(id).defaultness } - fn get_impl_constness(&self, id: DefIndex) -> hir::Constness { + fn get_impl_constness(self, id: DefIndex) -> hir::Constness { self.get_impl_data(id).constness } - fn get_coerce_unsized_info(&self, id: DefIndex) -> Option { + fn get_coerce_unsized_info(self, id: DefIndex) -> Option { self.get_impl_data(id).coerce_unsized_info } - fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option> { + fn get_impl_trait(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option> { self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx))) } - fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId { + fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId { self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess)) } fn get_const_param_default( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> rustc_middle::ty::Const<'tcx> { @@ -1029,14 +1029,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over all the stability attributes in the given crate. - fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option)] { + fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option)] { // FIXME: For a proc macro crate, not sure whether we should return the "host" // features or an empty Vec. Both don't cause ICEs. tcx.arena.alloc_from_iter(self.root.lib_features.decode(self)) } /// Iterates over the language items in the given crate. - fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { + fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { if self.root.is_proc_macro_crate() { // Proc macro crates do not export any lang-items to the target. &[] @@ -1051,7 +1051,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over the diagnostic items in the given crate. - fn get_diagnostic_items(&self) -> DiagnosticItems { + fn get_diagnostic_items(self) -> DiagnosticItems { if self.root.is_proc_macro_crate() { // Proc macro crates do not export any diagnostic-items to the target. Default::default() @@ -1072,7 +1072,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over each child of the given item. - fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) { + fn each_child_of_item(self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) { if let Some(data) = &self.root.proc_macro_data { /* If we are loading as a proc macro, we want to return the view of this crate * as a proc macro crate. @@ -1165,15 +1165,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn is_ctfe_mir_available(&self, id: DefIndex) -> bool { + fn is_ctfe_mir_available(self, id: DefIndex) -> bool { self.root.tables.mir_for_ctfe.get(self, id).is_some() } - fn is_item_mir_available(&self, id: DefIndex) -> bool { + fn is_item_mir_available(self, id: DefIndex) -> bool { self.root.tables.mir.get(self, id).is_some() } - fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId { + fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId { match self.kind(id) { EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => { self.get_expn_that_defined(id, sess) @@ -1182,7 +1182,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { + fn get_optimized_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { self.root .tables .mir @@ -1193,7 +1193,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { + fn get_mir_for_ctfe(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { self.root .tables .mir_for_ctfe @@ -1205,7 +1205,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_thir_abstract_const( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> Result]>, ErrorReported> { @@ -1216,7 +1216,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } - fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { + fn get_unused_generic_params(self, id: DefIndex) -> FiniteBitSet { self.root .tables .unused_generic_params @@ -1225,7 +1225,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .unwrap_or_default() } - fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec> { + fn get_promoted_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec> { self.root .tables .promoted_mir @@ -1236,7 +1236,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs { + fn mir_const_qualif(self, id: DefIndex) -> mir::ConstQualifs { match self.kind(id) { EntryKind::AnonConst(qualif, _) | EntryKind::Const(qualif, _) @@ -1251,14 +1251,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_fn_has_self_parameter(&self, id: DefIndex) -> bool { + fn get_fn_has_self_parameter(self, id: DefIndex) -> bool { match self.kind(id) { EntryKind::AssocFn(data) => data.decode(self).has_self, _ => false, } } - fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem { + fn get_associated_item(self, id: DefIndex, sess: &Session) -> ty::AssocItem { let def_key = self.def_key(id); let parent = self.local_def_id(def_key.parent.unwrap()); let ident = self.item_ident(id, sess); @@ -1284,11 +1284,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_item_variances(&'a self, id: DefIndex) -> impl Iterator + 'a { + fn get_item_variances(self, id: DefIndex) -> impl Iterator + 'a { self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self) } - fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { + fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { match self.kind(node_id) { EntryKind::Struct(data, _) | EntryKind::Variant(data) => { let vdata = data.decode(self); @@ -1299,7 +1299,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_item_attrs( - &'a self, + self, id: DefIndex, sess: &'a Session, ) -> impl Iterator + 'a { @@ -1323,7 +1323,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec> { + fn get_struct_field_names(self, id: DefIndex, sess: &Session) -> Vec> { self.root .tables .children @@ -1334,7 +1334,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .collect() } - fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec { + fn get_struct_field_visibilities(self, id: DefIndex) -> Vec { self.root .tables .children @@ -1346,7 +1346,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_inherent_implementations_for_type( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> &'tcx [DefId] { @@ -1361,20 +1361,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_traits(&'a self) -> impl Iterator + 'a { - self.root.traits.decode(self).map(|index| self.local_def_id(index)) + fn get_traits(self) -> impl Iterator + 'a { + self.root.traits.decode(self).map(move |index| self.local_def_id(index)) } - fn get_trait_impls(&'a self) -> impl Iterator)> + 'a { - self.trait_impls.values().flat_map(move |impls| { + fn get_trait_impls(self) -> impl Iterator)> + 'a { + self.cdata.trait_impls.values().flat_map(move |impls| { impls .decode(self) - .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) + .map(move |(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) }) } fn get_implementations_of_trait( - &self, + self, tcx: TyCtxt<'tcx>, trait_def_id: DefId, ) -> &'tcx [(DefId, Option)] { @@ -1401,7 +1401,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_trait_of_item(&self, id: DefIndex) -> Option { + fn get_trait_of_item(self, id: DefIndex) -> Option { let def_key = self.def_key(id); match def_key.disambiguated_data.data { DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (), @@ -1414,7 +1414,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn get_native_libraries(&self, sess: &Session) -> Vec { + fn get_native_libraries(self, sess: &Session) -> Vec { if self.root.is_proc_macro_crate() { // Proc macro crates do not have any *target* native libraries. vec![] @@ -1423,7 +1423,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_proc_macro_quoted_span(&self, index: usize, sess: &Session) -> Span { + fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span { self.root .tables .proc_macro_quoted_spans @@ -1432,7 +1432,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc> { + fn get_foreign_modules(self, tcx: TyCtxt<'tcx>) -> Lrc> { if self.root.is_proc_macro_crate() { // Proc macro crates do not have any *target* foreign modules. Lrc::new(FxHashMap::default()) @@ -1444,7 +1444,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_dylib_dependency_formats( - &self, + self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(CrateNum, LinkagePreference)] { tcx.arena.alloc_from_iter( @@ -1455,7 +1455,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { + fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { if self.root.is_proc_macro_crate() { // Proc macro crates do not depend on any target weak lang-items. &[] @@ -1464,7 +1464,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] { + fn get_fn_param_names(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] { let param_names = match self.kind(id) { EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names, EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names, @@ -1474,7 +1474,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn exported_symbols( - &self, + self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { if self.root.is_proc_macro_crate() { @@ -1486,7 +1486,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_rendered_const(&self, id: DefIndex) -> String { + fn get_rendered_const(self, id: DefIndex) -> String { match self.kind(id) { EntryKind::AnonConst(_, data) | EntryKind::Const(_, data) @@ -1495,7 +1495,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_macro(&self, id: DefIndex, sess: &Session) -> MacroDef { + fn get_macro(self, id: DefIndex, sess: &Session) -> MacroDef { match self.kind(id) { EntryKind::MacroDef(macro_def) => macro_def.decode((self, sess)), _ => bug!(), @@ -1504,7 +1504,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // This replicates some of the logic of the crate-local `is_const_fn_raw` query, because we // don't serialize constness for tuple variant and tuple struct constructors. - fn is_const_fn_raw(&self, id: DefIndex) -> bool { + fn is_const_fn_raw(self, id: DefIndex) -> bool { let constness = match self.kind(id) { EntryKind::AssocFn(data) => data.decode(self).fn_data.constness, EntryKind::Fn(data) => data.decode(self).constness, @@ -1515,7 +1515,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { constness == hir::Constness::Const } - fn asyncness(&self, id: DefIndex) -> hir::IsAsync { + fn asyncness(self, id: DefIndex) -> hir::IsAsync { match self.kind(id) { EntryKind::Fn(data) => data.decode(self).asyncness, EntryKind::AssocFn(data) => data.decode(self).fn_data.asyncness, @@ -1524,7 +1524,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn is_foreign_item(&self, id: DefIndex) -> bool { + fn is_foreign_item(self, id: DefIndex) -> bool { match self.kind(id) { EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => { true @@ -1533,7 +1533,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn static_mutability(&self, id: DefIndex) -> Option { + fn static_mutability(self, id: DefIndex) -> Option { match self.kind(id) { EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Some(hir::Mutability::Not), EntryKind::MutStatic | EntryKind::ForeignMutStatic => Some(hir::Mutability::Mut), @@ -1541,19 +1541,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn generator_kind(&self, id: DefIndex) -> Option { + fn generator_kind(self, id: DefIndex) -> Option { match self.kind(id) { EntryKind::Generator(data) => Some(data), _ => None, } } - fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { + fn fn_sig(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { self.root.tables.fn_sig.get(self, id).unwrap().decode((self, tcx)) } #[inline] - fn def_key(&self, index: DefIndex) -> DefKey { + fn def_key(self, index: DefIndex) -> DefKey { *self .def_key_cache .lock() @@ -1562,13 +1562,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } // Returns the path leading to the thing with this `id`. - fn def_path(&self, id: DefIndex) -> DefPath { + fn def_path(self, id: DefIndex) -> DefPath { debug!("def_path(cnum={:?}, id={:?})", self.cnum, id); DefPath::make(self.cnum, id, |parent| self.def_key(parent)) } fn def_path_hash_unlocked( - &self, + self, index: DefIndex, def_path_hashes: &mut FxHashMap, ) -> DefPathHash { @@ -1578,17 +1578,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } #[inline] - fn def_path_hash(&self, index: DefIndex) -> DefPathHash { + fn def_path_hash(self, index: DefIndex) -> DefPathHash { let mut def_path_hashes = self.def_path_hash_cache.lock(); self.def_path_hash_unlocked(index, &mut def_path_hashes) } #[inline] - fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex { + fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex { self.def_path_hash_map.def_path_hash_to_def_index(&hash) } - fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId { + fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId { debug_assert_eq!(ExpnId::from_hash(hash), None); let index_guess = ExpnIndex::from_u32(index_guess); let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self)); @@ -1646,7 +1646,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { /// /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. - fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] { + fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] { // Translate the virtual `/rustc/$hash` prefix back to a real directory // that should hold actual sources, where possible. // From 130ba4718ece5d1c1f72f4ace679dbdcba4e328d Mon Sep 17 00:00:00 2001 From: pierwill <19642016+pierwill@users.noreply.github.com> Date: Fri, 7 Jan 2022 10:26:26 -0600 Subject: [PATCH 19/21] Fix typo in `StableCrateId` docs --- compiler/rustc_span/src/def_id.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index f6b0785a07c0e..24d2a8ac07382 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -136,8 +136,8 @@ impl Borrow for DefPathHash { /// collisions when loading crates and abort compilation in order to avoid /// further trouble. /// -/// See the discussion in [`DefId`] for more information -/// on the possibility of hash collisions in rustc, +/// For more information on the possibility of hash collisions in rustc, +/// see the discussion in [`DefId`]. #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(HashStable_Generic, Encodable, Decodable)] pub struct StableCrateId(pub(crate) u64); From 836addcbc4fa825e07c78c6feb7f6a0b776ed41a Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 28 Dec 2021 16:57:18 -0500 Subject: [PATCH 20/21] Consolidate checking for msvc when generating debuginfo If the target we're generating code for is msvc, then we do two main things differently: we generate type names in a C++ style instead of a Rust style and we generate debuginfo for enums differently. I've refactored the code so that there is one function (`cpp_like_debuginfo`) which determines if we should use the C++ style of naming types and other debuginfo generation or the regular Rust one. --- .../src/debuginfo/metadata.rs | 28 ++--- .../src/debuginfo/type_names.rs | 101 +++++++++--------- 2 files changed, 65 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 5f9c41891685b..5d60d9ab577a3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -18,6 +18,7 @@ use crate::llvm::debuginfo::{ use crate::value::Value; use cstr::cstr; +use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -933,16 +934,16 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l // When targeting MSVC, emit MSVC style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let msvc_like_names = cx.tcx.sess.target.is_like_msvc; + let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx); let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned), ty::Bool => ("bool", DW_ATE_boolean), ty::Char => ("char", DW_ATE_unsigned_char), - ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed), - ty::Uint(uint_ty) if msvc_like_names => (uint_ty.msvc_basic_name(), DW_ATE_unsigned), - ty::Float(float_ty) if msvc_like_names => (float_ty.msvc_basic_name(), DW_ATE_float), + ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed), + ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned), + ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float), ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed), ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned), ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float), @@ -959,7 +960,7 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l ) }; - if !msvc_like_names { + if !cpp_like_debuginfo { return ty_metadata; } @@ -1521,13 +1522,6 @@ fn prepare_union_metadata<'ll, 'tcx>( // Enums //=----------------------------------------------------------------------------- -/// DWARF variant support is only available starting in LLVM 8, but -/// on MSVC we have to use the fallback mode, because LLVM doesn't -/// lower variant parts to PDB. -fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool { - cx.sess().target.is_like_msvc -} - // FIXME(eddyb) maybe precompute this? Right now it's computed once // per generator monomorphization, but it doesn't depend on substs. fn generator_layout_and_saved_local_names<'tcx>( @@ -1602,7 +1596,10 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { _ => bug!(), }; - let fallback = use_enum_fallback(cx); + // While LLVM supports generating debuginfo for variant types (enums), it doesn't support + // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting + // msvc, then we need to use a different, fallback encoding of the debuginfo. + let fallback = cpp_like_debuginfo(cx.tcx); // This will always find the metadata in the type map. let self_metadata = type_metadata(cx, self.enum_type, self.span); @@ -2155,7 +2152,10 @@ fn prepare_enum_metadata<'ll, 'tcx>( return FinalMetadata(discriminant_type_metadata(tag.value)); } - if use_enum_fallback(cx) { + // While LLVM supports generating debuginfo for variant types (enums), it doesn't support + // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting + // msvc, then we need to use a different encoding of the debuginfo. + if cpp_like_debuginfo(tcx) { let discriminant_type_metadata = match layout.variants { Variants::Single { .. } => None, Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 00e76800d474c..93bb1aee25f7d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -53,14 +53,14 @@ fn push_debuginfo_type_name<'tcx>( ) { // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_names = cpp_like_names(tcx); + let cpp_like_debuginfo = cpp_like_debuginfo(tcx); match *t.kind() { ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), ty::Never => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("never$"); } else { output.push('!'); @@ -71,7 +71,7 @@ fn push_debuginfo_type_name<'tcx>( ty::Float(float_ty) => output.push_str(float_ty.name_str()), ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), ty::Adt(def, substs) => { - if def.is_enum() && cpp_like_names { + if def.is_enum() && cpp_like_debuginfo { msvc_enum_fallback(tcx, t, def, substs, output, visited); } else { push_item_name(tcx, def.did, qualified, output); @@ -79,7 +79,7 @@ fn push_debuginfo_type_name<'tcx>( } } ty::Tuple(component_types) => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("tuple$<"); } else { output.push('('); @@ -87,20 +87,20 @@ fn push_debuginfo_type_name<'tcx>( for component_type in component_types { push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited); - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); } if !component_types.is_empty() { pop_arg_separator(output); } - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } else { output.push(')'); } } ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => { - if cpp_like_names { + if cpp_like_debuginfo { match mutbl { hir::Mutability::Not => output.push_str("ptr_const$<"), hir::Mutability::Mut => output.push_str("ptr_mut$<"), @@ -115,8 +115,8 @@ fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } } ty::Ref(_, inner_type, mutbl) => { @@ -126,7 +126,7 @@ fn push_debuginfo_type_name<'tcx>( // types out to aid debugging in MSVC. let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str); - if !cpp_like_names { + if !cpp_like_debuginfo { output.push('&'); output.push_str(mutbl.prefix_str()); } else if !is_slice_or_str { @@ -138,12 +138,12 @@ fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); - if cpp_like_names && !is_slice_or_str { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo && !is_slice_or_str { + push_close_angle_bracket(cpp_like_debuginfo, output); } } ty::Array(inner_type, len) => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("array$<"); push_debuginfo_type_name(tcx, inner_type, true, output, visited); match len.val { @@ -162,7 +162,7 @@ fn push_debuginfo_type_name<'tcx>( } } ty::Slice(inner_type) => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("slice$<"); } else { output.push('['); @@ -170,8 +170,8 @@ fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, true, output, visited); - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } else { output.push(']'); } @@ -179,7 +179,7 @@ fn push_debuginfo_type_name<'tcx>( ty::Dynamic(ref trait_data, ..) => { let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect(); - let has_enclosing_parens = if cpp_like_names { + let has_enclosing_parens = if cpp_like_debuginfo { output.push_str("dyn$<"); false } else { @@ -216,14 +216,14 @@ fn push_debuginfo_type_name<'tcx>( } for (item_def_id, ty) in projection_bounds { - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("assoc$<"); push_item_name(tcx, item_def_id, false, output); - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); push_debuginfo_type_name(tcx, ty, true, output, visited); - push_close_angle_bracket(cpp_like_names, output); + push_close_angle_bracket(cpp_like_debuginfo, output); } else { push_item_name(tcx, item_def_id, false, output); output.push('='); @@ -231,11 +231,11 @@ fn push_debuginfo_type_name<'tcx>( } } - push_close_angle_bracket(cpp_like_names, output); + push_close_angle_bracket(cpp_like_debuginfo, output); } if auto_traits.len() != 0 { - push_auto_trait_separator(cpp_like_names, output); + push_auto_trait_separator(cpp_like_debuginfo, output); } } @@ -252,14 +252,14 @@ fn push_debuginfo_type_name<'tcx>( for auto_trait in auto_traits { output.push_str(&auto_trait); - push_auto_trait_separator(cpp_like_names, output); + push_auto_trait_separator(cpp_like_debuginfo, output); } pop_auto_trait_separator(output); } - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } else if has_enclosing_parens { output.push(')'); } @@ -279,7 +279,7 @@ fn push_debuginfo_type_name<'tcx>( // use a dummy string that should make it clear // that something unusual is going on if !visited.insert(t) { - output.push_str(if cpp_like_names { + output.push_str(if cpp_like_debuginfo { "recursive_type$" } else { "" @@ -290,7 +290,7 @@ fn push_debuginfo_type_name<'tcx>( let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx)); - if cpp_like_names { + if cpp_like_debuginfo { // Format as a C++ function pointer: return_type (*)(params...) if sig.output().is_unit() { output.push_str("void"); @@ -313,7 +313,7 @@ fn push_debuginfo_type_name<'tcx>( if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { push_debuginfo_type_name(tcx, parameter_type, true, output, visited); - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); } pop_arg_separator(output); } @@ -328,7 +328,7 @@ fn push_debuginfo_type_name<'tcx>( output.push(')'); - if !cpp_like_names && !sig.output().is_unit() { + if !cpp_like_debuginfo && !sig.output().is_unit() { output.push_str(" -> "); push_debuginfo_type_name(tcx, sig.output(), true, output, visited); } @@ -426,9 +426,9 @@ fn push_debuginfo_type_name<'tcx>( const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + "; - fn push_auto_trait_separator(cpp_like_names: bool, output: &mut String) { - if cpp_like_names { - push_arg_separator(cpp_like_names, output); + fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) { + if cpp_like_debuginfo { + push_arg_separator(cpp_like_debuginfo, output); } else { output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR); } @@ -457,11 +457,11 @@ pub fn compute_debuginfo_vtable_name<'tcx>( t: Ty<'tcx>, trait_ref: Option>, ) -> String { - let cpp_like_names = cpp_like_names(tcx); + let cpp_like_debuginfo = cpp_like_debuginfo(tcx); let mut vtable_name = String::with_capacity(64); - if cpp_like_names { + if cpp_like_debuginfo { vtable_name.push_str("impl$<"); } else { vtable_name.push('<'); @@ -470,7 +470,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>( let mut visited = FxHashSet::default(); push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited); - if cpp_like_names { + if cpp_like_debuginfo { vtable_name.push_str(", "); } else { vtable_name.push_str(" as "); @@ -486,9 +486,9 @@ pub fn compute_debuginfo_vtable_name<'tcx>( vtable_name.push_str("_"); } - push_close_angle_bracket(cpp_like_names, &mut vtable_name); + push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name); - let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" }; + let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" }; vtable_name.reserve_exact(suffix.len()); vtable_name.push_str(suffix); @@ -521,7 +521,7 @@ fn push_unqualified_item_name( DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => { // Generators look like closures, but we want to treat them differently // in the debug info. - if cpp_like_names(tcx) { + if cpp_like_debuginfo(tcx) { write!(output, "generator${}", disambiguated_data.disambiguator).unwrap(); } else { write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap(); @@ -532,7 +532,7 @@ fn push_unqualified_item_name( output.push_str(name.as_str()); } DefPathDataName::Anon { namespace } => { - if cpp_like_names(tcx) { + if cpp_like_debuginfo(tcx) { write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap(); } else { write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator) @@ -560,7 +560,7 @@ fn push_generic_params_internal<'tcx>( debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs)); - let cpp_like_names = cpp_like_names(tcx); + let cpp_like_debuginfo = cpp_like_debuginfo(tcx); output.push('<'); @@ -575,10 +575,10 @@ fn push_generic_params_internal<'tcx>( other => bug!("Unexpected non-erasable generic: {:?}", other), } - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); } pop_arg_separator(output); - push_close_angle_bracket(cpp_like_names, output); + push_close_angle_bracket(cpp_like_debuginfo, output); true } @@ -617,7 +617,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: // avoiding collisions and will make the emitted type names shorter. let hash: u64 = hasher.finish(); - if cpp_like_names(tcx) { + if cpp_like_debuginfo(tcx) { write!(output, "CONST${:x}", hash) } else { write!(output, "{{CONST#{:x}}}", hash) @@ -634,10 +634,10 @@ pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, out push_generic_params_internal(tcx, substs, output, &mut visited); } -fn push_close_angle_bracket(cpp_like_names: bool, output: &mut String) { +fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) { // MSVC debugger always treats `>>` as a shift, even when parsing templates, // so add a space to avoid confusion. - if cpp_like_names && output.ends_with('>') { + if cpp_like_debuginfo && output.ends_with('>') { output.push(' ') }; @@ -652,11 +652,11 @@ fn pop_close_angle_bracket(output: &mut String) { } } -fn push_arg_separator(cpp_like_names: bool, output: &mut String) { +fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) { // Natvis does not always like having spaces between parts of the type name // and this causes issues when we need to write a typename in natvis, for example // as part of a cast like the `HashMap` visualizer does. - if cpp_like_names { + if cpp_like_debuginfo { output.push(','); } else { output.push_str(", "); @@ -673,6 +673,7 @@ fn pop_arg_separator(output: &mut String) { output.pop(); } -fn cpp_like_names(tcx: TyCtxt<'_>) -> bool { +/// Check if we should generate C++ like names and debug information. +pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool { tcx.sess.target.is_like_msvc } From 72cb1bd06dfdcec7c707e46fff44b3351a6c5ea9 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 7 Jan 2022 10:10:30 -0800 Subject: [PATCH 21/21] silence tidy errors --- library/std/src/error.rs | 14 ++++-------- library/std/src/error/tests.rs | 40 +++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 5514876c5d3b8..613ec43a906e7 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1284,9 +1284,7 @@ where for (ind, error) in cause.chain().enumerate() { writeln!(f)?; - let mut indented = Indented { - inner: f, - }; + let mut indented = Indented { inner: f }; if multiple { write!(indented, "{: >4}: {}", ind, error)?; } else { @@ -1310,8 +1308,7 @@ where } } -impl Report> -{ +impl Report> { fn backtrace(&self) -> Option<&Backtrace> { // have to grab the backtrace on the first error directly since that error may not be // 'static @@ -1353,9 +1350,7 @@ impl Report> for (ind, error) in cause.chain().enumerate() { writeln!(f)?; - let mut indented = Indented { - inner: f, - }; + let mut indented = Indented { inner: f }; if multiple { write!(indented, "{: >4}: {}", ind, error)?; } else { @@ -1411,8 +1406,7 @@ where } #[unstable(feature = "error_reporter", issue = "90172")] -impl fmt::Display for Report> -{ +impl fmt::Display for Report> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } } diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index 0835e282c46c3..eae5f43ff3cfb 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -82,11 +82,13 @@ fn multi_line_formatting() { let error = SuperError { source: SuperErrorSideKick }; let report = Report::new(&error).pretty(true); let actual = report.to_string(); - let expected = String::from("\ + let expected = String::from( + "\ SuperError is here! Caused by: - SuperErrorSideKick is here!"); + SuperErrorSideKick is here!", + ); assert_eq!(expected, actual); } @@ -112,20 +114,22 @@ fn error_with_no_sources_formats_multi_line_correctly() { #[test] fn error_with_backtrace_outputs_correctly_with_one_source() { let trace = Backtrace::force_capture(); - let expected = format!("\ + let expected = format!( + "\ The source of the error Caused by: Error with backtrace Stack backtrace: -{}", trace); +{}", + trace + ); let error = GenericError::new("Error with backtrace"); let mut error = GenericError::new_with_source("The source of the error", error); error.backtrace = Some(trace); let report = Report::new(error).pretty(true).show_backtrace(true); - println!("Error: {}", report); assert_eq!(expected.trim_end(), report.to_string()); } @@ -133,7 +137,8 @@ Stack backtrace: #[test] fn error_with_backtrace_outputs_correctly_with_two_sources() { let trace = Backtrace::force_capture(); - let expected = format!("\ + let expected = format!( + "\ Error with two sources Caused by: @@ -141,14 +146,15 @@ Caused by: 1: Error with backtrace Stack backtrace: -{}", trace); +{}", + trace + ); let mut error = GenericError::new("Error with backtrace"); error.backtrace = Some(trace); let error = GenericError::new_with_source("The source of the error", error); let error = GenericError::new_with_source("Error with two sources", error); let report = Report::new(error).pretty(true).show_backtrace(true); - println!("Error: {}", report); assert_eq!(expected.trim_end(), report.to_string()); } @@ -313,11 +319,11 @@ The message Caused by: - 0: - The message - - 1: - The message + 0: \ +\n The message + \ +\n 1: \ +\n The message "; let actual = report.to_string(); @@ -399,11 +405,11 @@ line 2 Caused by: 0: line 1 - - line 2 + \ +\n line 2 1: line 1 - - line 2"; + \ +\n line 2"; let actual = report.to_string(); assert_eq!(expected, actual);