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 ff12aed2f5e6ccf78d6ff150c9de1dea1f430c1d Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 8 Dec 2021 20:09:17 -0500 Subject: [PATCH 13/21] rustdoc: do not emit tuple variant fields if none are documented --- src/librustdoc/html/render/print_item.rs | 19 ++++++++++++++----- src/test/rustdoc/issue-88600.rs | 5 +++-- src/test/rustdoc/tuple-struct-fields-doc.rs | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 9943e23b9281c..1d54fcd01f076 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1133,18 +1133,27 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum w.write_str(""); use crate::clean::Variant; - if let Some((extra, fields)) = match *variant.kind { - clean::VariantItem(Variant::Struct(ref s)) => Some(("", &s.fields)), - clean::VariantItem(Variant::Tuple(ref fields)) => Some(("Tuple ", fields)), + + let heading_and_fields = match &*variant.kind { + clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)), + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + clean::VariantItem(Variant::Tuple(fields)) + if fields.iter().any(|f| cx.shared.maybe_collapsed_doc_value(f).is_some()) => + { + Some(("Tuple Fields", fields)) + } _ => None, - } { + }; + + if let Some((heading, fields)) = heading_and_fields { let variant_id = cx.derive_id(format!( "{}.{}.fields", ItemType::Variant, variant.name.as_ref().unwrap() )); write!(w, "
", id = variant_id); - write!(w, "

{extra}Fields

", extra = extra,); + write!(w, "

{heading}

", heading = heading); document_non_exhaustive(w, variant); for field in fields { match *field.kind { diff --git a/src/test/rustdoc/issue-88600.rs b/src/test/rustdoc/issue-88600.rs index 3761805b48b71..fc63ed343bda2 100644 --- a/src/test/rustdoc/issue-88600.rs +++ b/src/test/rustdoc/issue-88600.rs @@ -18,17 +18,18 @@ pub enum FooEnum { // @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)' // @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0 // @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S' - MixedHiddenFirst(#[doc(hidden)] H, S), + MixedHiddenFirst(#[doc(hidden)] H, /** dox */ S), // @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)' // @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S' // @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0 - MixedHiddenLast(S, #[doc(hidden)] H), + MixedHiddenLast(/** dox */ S, #[doc(hidden)] H), // @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct' // @count - '//*[@id="variant.HiddenStruct.field.h"]' 0 // @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S' HiddenStruct { #[doc(hidden)] h: H, + /// dox s: S, }, } diff --git a/src/test/rustdoc/tuple-struct-fields-doc.rs b/src/test/rustdoc/tuple-struct-fields-doc.rs index 2e339fe82649d..31426131bc2c1 100644 --- a/src/test/rustdoc/tuple-struct-fields-doc.rs +++ b/src/test/rustdoc/tuple-struct-fields-doc.rs @@ -24,6 +24,9 @@ pub struct Foo( // @has - '//*[@id="variant.BarVariant.field.0"]' '0: String' // @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs' // @matches - '//*[@id="variant.FooVariant.fields"]/h4' '^Fields$' +// @has - '//*[@id="variant.BazVariant.fields"]//*[@class="docblock"]' 'dox' +// @has - '//*[@id="variant.OtherVariant.fields"]//*[@class="docblock"]' 'dox' +// @!matches - '//*[@id="variant.QuuxVariant.fields"]/h4' '^Tuple Fields$' pub enum Bar { BarVariant( /// Hello docs @@ -33,4 +36,15 @@ pub enum Bar { /// hello x: u32, }, + BazVariant( + String, + /// dox + u32, + ), + OtherVariant( + /// dox + String, + u32, + ), + QuuxVariant(String), } From 336c85a053ff502fb2f42d2579fcff61efd6bdda Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 27 Dec 2021 13:44:14 -0800 Subject: [PATCH 14/21] rustdoc: Preserve rendering of macro_rules matchers when possible --- src/librustdoc/clean/utils.rs | 61 +++++++++++++++++++++++++++--- src/test/rustdoc/decl_macro.rs | 12 +++--- src/test/rustdoc/macros.rs | 8 ++-- src/test/rustdoc/reexports-priv.rs | 8 ++-- src/test/rustdoc/reexports.rs | 4 +- 5 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 7d5e2e36bd190..5fe7dd6c2bc83 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -16,6 +16,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; @@ -484,20 +486,67 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL"); /// Render a sequence of macro arms in a format suitable for displaying to the user /// as part of an item declaration. pub(super) fn render_macro_arms<'a>( + cx: &DocContext<'_>, matchers: impl Iterator, arm_delim: &str, ) -> String { let mut out = String::new(); for matcher in matchers { - writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(matcher), arm_delim).unwrap(); + writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(cx, matcher), arm_delim) + .unwrap(); } out } /// Render a macro matcher in a format suitable for displaying to the user /// as part of an item declaration. -pub(super) fn render_macro_matcher(matcher: &TokenTree) -> String { - rustc_ast_pretty::pprust::tt_to_string(matcher) +pub(super) fn render_macro_matcher(cx: &DocContext<'_>, matcher: &TokenTree) -> String { + if let Some(snippet) = snippet_equal_to_token(cx, matcher) { + snippet + } else { + rustc_ast_pretty::pprust::tt_to_string(matcher) + } +} + +/// Find the source snippet for this token's Span, reparse it, and return the +/// snippet if the reparsed TokenTree matches the argument TokenTree. +fn snippet_equal_to_token(cx: &DocContext<'_>, matcher: &TokenTree) -> Option { + // Find what rustc thinks is the source snippet. + // This may not actually be anything meaningful if this matcher was itself + // generated by a macro. + let source_map = cx.sess().source_map(); + let span = matcher.span(); + let snippet = source_map.span_to_snippet(span).ok()?; + + // Create a Parser. + let sess = ParseSess::new(FilePathMapping::empty()); + let file_name = source_map.span_to_filename(span); + let mut parser = + match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) { + Ok(parser) => parser, + Err(diagnostics) => { + for mut diagnostic in diagnostics { + diagnostic.cancel(); + } + return None; + } + }; + + // Reparse a single token tree. + let mut reparsed_trees = match parser.parse_all_token_trees() { + Ok(reparsed_trees) => reparsed_trees, + Err(mut diagnostic) => { + diagnostic.cancel(); + return None; + } + }; + if reparsed_trees.len() != 1 { + return None; + } + let reparsed_tree = reparsed_trees.pop().unwrap(); + + // Compare against the original tree. + if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None } } pub(super) fn display_macro_source( @@ -512,21 +561,21 @@ pub(super) fn display_macro_source( let matchers = tts.chunks(4).map(|arm| &arm[0]); if def.macro_rules { - format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(matchers, ";")) + format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx, matchers, ";")) } else { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", vis.to_src_with_space(cx.tcx, def_id), name, - matchers.map(render_macro_matcher).collect::(), + matchers.map(|matcher| render_macro_matcher(cx, matcher)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", vis.to_src_with_space(cx.tcx, def_id), name, - render_macro_arms(matchers, ","), + render_macro_arms(cx, matchers, ","), ) } } diff --git a/src/test/rustdoc/decl_macro.rs b/src/test/rustdoc/decl_macro.rs index fe19dadbe0243..94ade31b5e5f4 100644 --- a/src/test/rustdoc/decl_macro.rs +++ b/src/test/rustdoc/decl_macro.rs @@ -9,7 +9,7 @@ pub macro my_macro() { } -// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok : tt) *) {' +// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok:tt)*) {' // @has - //pre '...' // @has - //pre '}' pub macro my_macro_2($($tok:tt)*) { @@ -18,8 +18,8 @@ pub macro my_macro_2($($tok:tt)*) { // @has decl_macro/macro.my_macro_multi.html //pre 'pub macro my_macro_multi {' // @has - //pre '(_) => { ... },' -// @has - //pre '($foo : ident.$bar : expr) => { ... },' -// @has - //pre '($($foo : literal), +) => { ... },' +// @has - //pre '($foo:ident . $bar:expr) => { ... },' +// @has - //pre '($($foo:literal),+) => { ... },' // @has - //pre '}' pub macro my_macro_multi { (_) => { @@ -33,7 +33,7 @@ pub macro my_macro_multi { } } -// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo : expr) {' +// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo:expr) {' // @has - //pre '...' // @has - //pre '}' pub macro by_example_single { @@ -42,12 +42,12 @@ pub macro by_example_single { mod a { mod b { - // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo : expr) {' + // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {' pub(in super) macro by_example_vis { ($foo:expr) => {} } mod c { - // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo : expr) {' + // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {' pub(in a) macro by_example_vis_named { ($foo:expr) => {} } diff --git a/src/test/rustdoc/macros.rs b/src/test/rustdoc/macros.rs index 1cd454720e7d1..ae0cf7a14789d 100644 --- a/src/test/rustdoc/macros.rs +++ b/src/test/rustdoc/macros.rs @@ -1,7 +1,7 @@ // @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {' // @has - //pre '() => { ... };' -// @has - //pre '($a : tt) => { ... };' -// @has - //pre '($e : expr) => { ... };' +// @has - //pre '($a:tt) => { ... };' +// @has - //pre '($e:expr) => { ... };' #[macro_export] macro_rules! my_macro { () => []; @@ -12,8 +12,8 @@ macro_rules! my_macro { // Check that exported macro defined in a module are shown at crate root. // @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {' // @has - //pre '() => { ... };' -// @has - //pre '($a : tt) => { ... };' -// @has - //pre '($e : expr) => { ... };' +// @has - //pre '($a:tt) => { ... };' +// @has - //pre '($e:expr) => { ... };' mod sub { #[macro_export] macro_rules! my_sub_macro { diff --git a/src/test/rustdoc/reexports-priv.rs b/src/test/rustdoc/reexports-priv.rs index 95f741807494c..aea9b9f2b395d 100644 --- a/src/test/rustdoc/reexports-priv.rs +++ b/src/test/rustdoc/reexports-priv.rs @@ -5,7 +5,7 @@ extern crate reexports; -// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' +// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; // @!has 'foo/macro.addr_of_crate.html' pub(crate) use reexports::addr_of_crate; @@ -61,11 +61,11 @@ use reexports::UnionLocal; pub mod outer { pub mod inner { - // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; - // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {' pub(crate) use reexports::addr_of_crate; - // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {' pub(super) use reexports::addr_of_super; // @!has 'foo/outer/inner/macro.addr_of_self.html' pub(self) use reexports::addr_of_self; diff --git a/src/test/rustdoc/reexports.rs b/src/test/rustdoc/reexports.rs index 3b31530847035..7abcbfb618122 100644 --- a/src/test/rustdoc/reexports.rs +++ b/src/test/rustdoc/reexports.rs @@ -4,7 +4,7 @@ extern crate reexports; -// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' +// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; // @!has 'foo/macro.addr_of_crate.html' pub(crate) use reexports::addr_of_crate; @@ -60,7 +60,7 @@ use reexports::UnionLocal; pub mod outer { pub mod inner { - // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; // @!has 'foo/outer/inner/macro.addr_of_crate.html' pub(crate) use reexports::addr_of_crate; From 544a6bb7e72c907f05881ae7f461005cc5f92759 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 28 Dec 2021 13:43:08 -0800 Subject: [PATCH 15/21] Replace &DocCtxt -> TyCtxt in macro matcher rendering --- src/librustdoc/clean/utils.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 5fe7dd6c2bc83..2c3fd39baf69f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -486,13 +486,13 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL"); /// Render a sequence of macro arms in a format suitable for displaying to the user /// as part of an item declaration. pub(super) fn render_macro_arms<'a>( - cx: &DocContext<'_>, + tcx: TyCtxt<'_>, matchers: impl Iterator, arm_delim: &str, ) -> String { let mut out = String::new(); for matcher in matchers { - writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(cx, matcher), arm_delim) + writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim) .unwrap(); } out @@ -500,8 +500,8 @@ pub(super) fn render_macro_arms<'a>( /// Render a macro matcher in a format suitable for displaying to the user /// as part of an item declaration. -pub(super) fn render_macro_matcher(cx: &DocContext<'_>, matcher: &TokenTree) -> String { - if let Some(snippet) = snippet_equal_to_token(cx, matcher) { +pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String { + if let Some(snippet) = snippet_equal_to_token(tcx, matcher) { snippet } else { rustc_ast_pretty::pprust::tt_to_string(matcher) @@ -510,11 +510,11 @@ pub(super) fn render_macro_matcher(cx: &DocContext<'_>, matcher: &TokenTree) -> /// Find the source snippet for this token's Span, reparse it, and return the /// snippet if the reparsed TokenTree matches the argument TokenTree. -fn snippet_equal_to_token(cx: &DocContext<'_>, matcher: &TokenTree) -> Option { +fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option { // Find what rustc thinks is the source snippet. // This may not actually be anything meaningful if this matcher was itself // generated by a macro. - let source_map = cx.sess().source_map(); + let source_map = tcx.sess.source_map(); let span = matcher.span(); let snippet = source_map.span_to_snippet(span).ok()?; @@ -561,21 +561,21 @@ pub(super) fn display_macro_source( let matchers = tts.chunks(4).map(|arm| &arm[0]); if def.macro_rules { - format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx, matchers, ";")) + format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";")) } else { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", vis.to_src_with_space(cx.tcx, def_id), name, - matchers.map(|matcher| render_macro_matcher(cx, matcher)).collect::(), + matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", vis.to_src_with_space(cx.tcx, def_id), name, - render_macro_arms(cx, matchers, ","), + render_macro_arms(cx.tcx, matchers, ","), ) } } From 0f8415b8e1d93de7b6673298c9f10c709742d9ab Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 28 Dec 2021 13:52:33 -0800 Subject: [PATCH 16/21] Add a test of rustdoc on macro-generated macro --- src/test/rustdoc/macro-generated-macro.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/rustdoc/macro-generated-macro.rs diff --git a/src/test/rustdoc/macro-generated-macro.rs b/src/test/rustdoc/macro-generated-macro.rs new file mode 100644 index 0000000000000..25d8bc3ec6281 --- /dev/null +++ b/src/test/rustdoc/macro-generated-macro.rs @@ -0,0 +1,14 @@ +macro_rules! outer { + ($($matcher:tt)*) => { + #[macro_export] + macro_rules! inner { + (<= $($matcher)* =>) => {}; + } + } +} + +// @has macro_generated_macro/macro.inner.html //pre 'macro_rules! inner {' +// @has - //pre '(<= type $($i : ident) :: * + $e : expr =>) => { ... };' +outer!(type $($i:ident)::* + $e:expr); + +inner!(<= type foo::bar + x.sort() =>); From 72cb1bd06dfdcec7c707e46fff44b3351a6c5ea9 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 7 Jan 2022 10:10:30 -0800 Subject: [PATCH 17/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); From c4471b0b9c9b3762c8030c44835b614f90deaf75 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 | 196 +++++++++---------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e39ea46c0c0ca..493c815ff0115 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> { @@ -414,9 +414,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))) }) } } @@ -442,15 +442,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) @@ -706,7 +706,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 @@ -721,7 +721,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)), @@ -737,15 +737,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 {}", @@ -756,7 +756,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 {}", @@ -767,7 +767,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 @@ -776,7 +776,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 = @@ -807,7 +807,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)); @@ -837,7 +837,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_variant( - &self, + self, kind: &EntryKind, index: DefIndex, parent_did: DefId, @@ -886,7 +886,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); @@ -914,7 +914,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_explicit_predicates( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { @@ -922,7 +922,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_inferred_outlives( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { @@ -935,7 +935,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_super_predicates( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { @@ -943,7 +943,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_explicit_item_bounds( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { @@ -955,11 +955,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 @@ -968,63 +968,63 @@ 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_trait_item_def_id(&self, id: DefIndex) -> Option { + fn get_trait_item_def_id(self, id: DefIndex) -> Option { self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self)) } - 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> { @@ -1032,14 +1032,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. &[] @@ -1054,7 +1054,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() @@ -1079,7 +1079,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { /// Module here is understood in name resolution sense - it can be a `mod` item, /// or a crate root, or an enum, or a trait. fn for_each_module_child( - &self, + self, id: DefIndex, mut callback: impl FnMut(ModChild), sess: &Session, @@ -1177,15 +1177,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) @@ -1194,7 +1194,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 @@ -1205,7 +1205,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 @@ -1217,7 +1217,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_thir_abstract_const( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> Result]>, ErrorReported> { @@ -1228,7 +1228,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 @@ -1237,7 +1237,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 @@ -1248,7 +1248,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, _) @@ -1263,14 +1263,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_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] { + fn get_associated_item_def_ids(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] { if let Some(children) = self.root.tables.children.get(self, id) { tcx.arena.alloc_from_iter( children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)), @@ -1280,7 +1280,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - 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); @@ -1307,11 +1307,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); @@ -1322,7 +1322,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_item_attrs( - &'a self, + self, id: DefIndex, sess: &'a Session, ) -> impl Iterator + 'a { @@ -1346,7 +1346,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 @@ -1357,7 +1357,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 @@ -1369,7 +1369,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_inherent_implementations_for_type( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> &'tcx [DefId] { @@ -1384,20 +1384,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)] { @@ -1424,7 +1424,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(..) => (), @@ -1437,7 +1437,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![] @@ -1446,7 +1446,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 @@ -1455,7 +1455,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()) @@ -1467,7 +1467,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_dylib_dependency_formats( - &self, + self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(CrateNum, LinkagePreference)] { tcx.arena.alloc_from_iter( @@ -1478,7 +1478,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. &[] @@ -1487,7 +1487,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, @@ -1497,7 +1497,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() { @@ -1509,7 +1509,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) @@ -1518,7 +1518,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!(), @@ -1527,7 +1527,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, @@ -1538,7 +1538,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, @@ -1547,7 +1547,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 @@ -1556,7 +1556,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), @@ -1564,19 +1564,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() @@ -1585,13 +1585,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 { @@ -1601,17 +1601,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)); @@ -1669,7 +1669,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 8fd8db5c2955dd715cf7ee59205a733abcdd34fc Mon Sep 17 00:00:00 2001 From: Dmitrii - Demenev Date: Sun, 9 Jan 2022 19:17:15 -0500 Subject: [PATCH 19/21] Extended the note on the use of `no_run` attribute --- src/doc/rustdoc/src/documentation-tests.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index aea55d4f4b69c..534fd19b52eb2 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -335,7 +335,8 @@ panic during execution. If the code doesn't panic, the test will fail. The `no_run` attribute will compile your code but not run it. This is important for examples such as "Here's how to retrieve a web page," which you would want to ensure compiles, but might be run in a test -environment that has no network access. +environment that has no network access. This attribute can also be +used to demonstrate code snippets that can cause Undefined Behavior. ```rust /// ```no_run From 680ebeaa792a6446b0096492b286a748f79dd933 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 9 Jan 2022 13:47:50 -0800 Subject: [PATCH 20/21] RELEASES.md: Add 1.58 release note for `File::options` stabilization --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index d6f5909a2ebc0..6356ddb2da727 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -42,6 +42,7 @@ Stabilized APIs - [`{integer}::saturating_div`] - [`Option::unwrap_unchecked`] - [`NonZero{unsigned}::is_power_of_two`] +- [`File::options`] These APIs are now usable in const contexts: @@ -137,6 +138,7 @@ and related tools. [`{integer}::saturating_div`]: https://doc.rust-lang.org/stable/std/primitive.i8.html#method.saturating_div [`Option::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_unchecked [`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two +[`File::options`]: https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.options [`unix::process::ExitStatusExt::core_dumped`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.core_dumped [`unix::process::ExitStatusExt::stopped_signal`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.stopped_signal [`unix::process::ExitStatusExt::continued`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.continued From 2ae616af302d6022fbc3234122bc3bb71915c073 Mon Sep 17 00:00:00 2001 From: Yaroslav Dynnikov Date: Mon, 10 Jan 2022 14:22:45 +0300 Subject: [PATCH 21/21] Fix doc formatting for time.rs The doc states that instants are not steady, but the word "not" wasn't highlighted in bold. --- library/std/src/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 86cc93c445376..b6867e68df745 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -54,7 +54,7 @@ pub use core::time::FromSecsError; /// instant when created, and are often useful for tasks such as measuring /// benchmarks or timing how long an operation takes. /// -/// Note, however, that instants are not guaranteed to be **steady**. In other +/// Note, however, that instants are **not** guaranteed to be **steady**. In other /// words, each tick of the underlying clock might not be the same length (e.g. /// some seconds may be longer than others). An instant may jump forwards or /// experience time dilation (slow down or speed up), but it will never go