Skip to content

Commit 5b3902f

Browse files
committed
attempt to make Report usable with Box dyn Error and fn main
1 parent 9be1cc9 commit 5b3902f

File tree

1 file changed

+201
-103
lines changed

1 file changed

+201
-103
lines changed

library/std/src/error.rs

+201-103
Original file line numberDiff line numberDiff line change
@@ -914,106 +914,109 @@ impl dyn Error + Send + Sync {
914914
/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
915915
/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
916916
/// ```
917-
// /// TODO: Report doesn't yet support return from `main` gracefully, fix in followup (yaahc)
918-
// /// ## Return from `main`
919-
// ///
920-
// /// `Report` also implements `From` for all types that implement [`Error`], this when combined with
921-
// /// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
922-
// /// from `main`.
923-
// ///
924-
// /// ```
925-
// /// #![feature(error_reporter)]
926-
// /// use std::error::Report;
927-
// /// # use std::error::Error;
928-
// /// # use std::fmt;
929-
// /// # #[derive(Debug)]
930-
// /// # struct SuperError {
931-
// /// # source: SuperErrorSideKick,
932-
// /// # }
933-
// /// # impl fmt::Display for SuperError {
934-
// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
935-
// /// # write!(f, "SuperError is here!")
936-
// /// # }
937-
// /// # }
938-
// /// # impl Error for SuperError {
939-
// /// # fn source(&self) -> Option<&(dyn Error + 'static)> {
940-
// /// # Some(&self.source)
941-
// /// # }
942-
// /// # }
943-
// /// # #[derive(Debug)]
944-
// /// # struct SuperErrorSideKick;
945-
// /// # impl fmt::Display for SuperErrorSideKick {
946-
// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
947-
// /// # write!(f, "SuperErrorSideKick is here!")
948-
// /// # }
949-
// /// # }
950-
// /// # impl Error for SuperErrorSideKick {}
951-
// /// # fn get_super_error() -> Result<(), SuperError> {
952-
// /// # Err(SuperError { source: SuperErrorSideKick })
953-
// /// # }
954-
// ///
955-
// /// fn main() -> Result<(), Report> {
956-
// /// get_super_error()?;
957-
// /// }
958-
// /// ```
959-
// ///
960-
// /// This example produces the following output:
961-
// ///
962-
// /// ```console
963-
// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
964-
// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
965-
// /// ```
966-
// ///
967-
// /// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
968-
// /// output format, if you want to make sure your `Report`s are pretty printed and include backtrace
969-
// /// you will need to manually convert and enable those flags.
970-
// ///
971-
// /// ```
972-
// /// #![feature(error_reporter)]
973-
// /// use std::error::Report;
974-
// /// # use std::error::Error;
975-
// /// # use std::fmt;
976-
// /// # #[derive(Debug)]
977-
// /// # struct SuperError {
978-
// /// # source: SuperErrorSideKick,
979-
// /// # }
980-
// /// # impl fmt::Display for SuperError {
981-
// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
982-
// /// # write!(f, "SuperError is here!")
983-
// /// # }
984-
// /// # }
985-
// /// # impl Error for SuperError {
986-
// /// # fn source(&self) -> Option<&(dyn Error + 'static)> {
987-
// /// # Some(&self.source)
988-
// /// # }
989-
// /// # }
990-
// /// # #[derive(Debug)]
991-
// /// # struct SuperErrorSideKick;
992-
// /// # impl fmt::Display for SuperErrorSideKick {
993-
// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994-
// /// # write!(f, "SuperErrorSideKick is here!")
995-
// /// # }
996-
// /// # }
997-
// /// # impl Error for SuperErrorSideKick {}
998-
// /// # fn get_super_error() -> Result<(), SuperError> {
999-
// /// # Err(SuperError { source: SuperErrorSideKick })
1000-
// /// # }
1001-
// ///
1002-
// /// fn main() -> Result<(), Report> {
1003-
// /// get_super_error()
1004-
// /// .map_err(Report::new)
1005-
// /// .map_err(|r| r.pretty(true).show_backtrace(true))?;
1006-
// /// }
1007-
// /// ```
1008-
// ///
1009-
// /// This example produces the following output:
1010-
// ///
1011-
// /// ```console
1012-
// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
1013-
// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
1014-
// /// ```
917+
///
918+
/// ## Return from `main`
919+
///
920+
/// `Report` also implements `From` for all types that implement [`Error`], this when combined with
921+
/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
922+
/// from `main`.
923+
///
924+
/// ```should_panic
925+
/// #![feature(error_reporter)]
926+
/// use std::error::Report;
927+
/// # use std::error::Error;
928+
/// # use std::fmt;
929+
/// # #[derive(Debug)]
930+
/// # struct SuperError {
931+
/// # source: SuperErrorSideKick,
932+
/// # }
933+
/// # impl fmt::Display for SuperError {
934+
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
935+
/// # write!(f, "SuperError is here!")
936+
/// # }
937+
/// # }
938+
/// # impl Error for SuperError {
939+
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
940+
/// # Some(&self.source)
941+
/// # }
942+
/// # }
943+
/// # #[derive(Debug)]
944+
/// # struct SuperErrorSideKick;
945+
/// # impl fmt::Display for SuperErrorSideKick {
946+
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
947+
/// # write!(f, "SuperErrorSideKick is here!")
948+
/// # }
949+
/// # }
950+
/// # impl Error for SuperErrorSideKick {}
951+
/// # fn get_super_error() -> Result<(), SuperError> {
952+
/// # Err(SuperError { source: SuperErrorSideKick })
953+
/// # }
954+
///
955+
/// fn main() -> Result<(), Report> {
956+
/// get_super_error()?;
957+
/// Ok(())
958+
/// }
959+
/// ```
960+
///
961+
/// This example produces the following output:
962+
///
963+
/// ```console
964+
/// Error: SuperError is here!: SuperErrorSideKick is here!
965+
/// ```
966+
///
967+
/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
968+
/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace
969+
/// you will need to manually convert and enable those flags.
970+
///
971+
/// ```should_panic
972+
/// #![feature(error_reporter)]
973+
/// use std::error::Report;
974+
/// # use std::error::Error;
975+
/// # use std::fmt;
976+
/// # #[derive(Debug)]
977+
/// # struct SuperError {
978+
/// # source: SuperErrorSideKick,
979+
/// # }
980+
/// # impl fmt::Display for SuperError {
981+
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
982+
/// # write!(f, "SuperError is here!")
983+
/// # }
984+
/// # }
985+
/// # impl Error for SuperError {
986+
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
987+
/// # Some(&self.source)
988+
/// # }
989+
/// # }
990+
/// # #[derive(Debug)]
991+
/// # struct SuperErrorSideKick;
992+
/// # impl fmt::Display for SuperErrorSideKick {
993+
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994+
/// # write!(f, "SuperErrorSideKick is here!")
995+
/// # }
996+
/// # }
997+
/// # impl Error for SuperErrorSideKick {}
998+
/// # fn get_super_error() -> Result<(), SuperError> {
999+
/// # Err(SuperError { source: SuperErrorSideKick })
1000+
/// # }
1001+
///
1002+
/// fn main() -> Result<(), Report> {
1003+
/// get_super_error()
1004+
/// .map_err(Report::from)
1005+
/// .map_err(|r| r.pretty(true).show_backtrace(true))?;
1006+
/// Ok(())
1007+
/// }
1008+
/// ```
1009+
///
1010+
/// This example produces the following output:
1011+
///
1012+
/// ```console
1013+
/// Error: SuperError is here!
1014+
///
1015+
/// Caused by:
1016+
/// SuperErrorSideKick is here!
1017+
/// ```
10151018
#[unstable(feature = "error_reporter", issue = "90172")]
1016-
pub struct Report<E> {
1019+
pub struct Report<E = Box<dyn Error>> {
10171020
/// The error being reported.
10181021
error: E,
10191022
/// Whether a backtrace should be included as part of the report.
@@ -1024,14 +1027,16 @@ pub struct Report<E> {
10241027

10251028
impl<E> Report<E>
10261029
where
1027-
E: Error,
1030+
Report<E>: From<E>,
10281031
{
10291032
/// Create a new `Report` from an input error.
10301033
#[unstable(feature = "error_reporter", issue = "90172")]
10311034
pub fn new(error: E) -> Report<E> {
1032-
Report { error, show_backtrace: false, pretty: false }
1035+
Self::from(error)
10331036
}
1037+
}
10341038

1039+
impl<E> Report<E> {
10351040
/// Enable pretty-printing the report across multiple lines.
10361041
///
10371042
/// # Examples
@@ -1232,7 +1237,81 @@ where
12321237
self.show_backtrace = show_backtrace;
12331238
self
12341239
}
1240+
}
1241+
1242+
impl<E> Report<E>
1243+
where
1244+
E: Error,
1245+
{
1246+
fn backtrace(&self) -> Option<&Backtrace> {
1247+
// have to grab the backtrace on the first error directly since that error may not be
1248+
// 'static
1249+
let backtrace = self.error.backtrace();
1250+
let backtrace = backtrace.or_else(|| {
1251+
self.error
1252+
.source()
1253+
.map(|source| source.chain().find_map(|source| source.backtrace()))
1254+
.flatten()
1255+
});
1256+
backtrace
1257+
}
1258+
1259+
/// Format the report as a single line.
1260+
#[unstable(feature = "error_reporter", issue = "90172")]
1261+
fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1262+
write!(f, "{}", self.error)?;
1263+
1264+
let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
1265+
1266+
for cause in sources {
1267+
write!(f, ": {}", cause)?;
1268+
}
1269+
1270+
Ok(())
1271+
}
1272+
1273+
/// Format the report as multiple lines, with each error cause on its own line.
1274+
#[unstable(feature = "error_reporter", issue = "90172")]
1275+
fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1276+
let error = &self.error;
1277+
1278+
write!(f, "{}", error)?;
1279+
1280+
if let Some(cause) = error.source() {
1281+
write!(f, "\n\nCaused by:")?;
1282+
1283+
let multiple = cause.source().is_some();
1284+
1285+
for (ind, error) in cause.chain().enumerate() {
1286+
writeln!(f)?;
1287+
let mut indented = Indented {
1288+
inner: f,
1289+
};
1290+
if multiple {
1291+
write!(indented, "{: >4}: {}", ind, error)?;
1292+
} else {
1293+
write!(indented, " {}", error)?;
1294+
}
1295+
}
1296+
}
1297+
1298+
if self.show_backtrace {
1299+
let backtrace = self.backtrace();
1300+
1301+
if let Some(backtrace) = backtrace {
1302+
let backtrace = backtrace.to_string();
1303+
1304+
f.write_str("\n\nStack backtrace:\n")?;
1305+
f.write_str(backtrace.trim_end())?;
1306+
}
1307+
}
1308+
1309+
Ok(())
1310+
}
1311+
}
12351312

1313+
impl Report<Box<dyn Error>>
1314+
{
12361315
fn backtrace(&self) -> Option<&Backtrace> {
12371316
// have to grab the backtrace on the first error directly since that error may not be
12381317
// 'static
@@ -1306,7 +1385,18 @@ where
13061385
E: Error,
13071386
{
13081387
fn from(error: E) -> Self {
1309-
Report::new(error)
1388+
Report { error, show_backtrace: false, pretty: false }
1389+
}
1390+
}
1391+
1392+
#[unstable(feature = "error_reporter", issue = "90172")]
1393+
impl<'a, E> From<E> for Report<Box<dyn Error + 'a>>
1394+
where
1395+
E: Error + 'a,
1396+
{
1397+
fn from(error: E) -> Self {
1398+
let error = box error;
1399+
Report { error, show_backtrace: false, pretty: false }
13101400
}
13111401
}
13121402

@@ -1320,12 +1410,20 @@ where
13201410
}
13211411
}
13221412

1413+
#[unstable(feature = "error_reporter", issue = "90172")]
1414+
impl fmt::Display for Report<Box<dyn Error>>
1415+
{
1416+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1417+
if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
1418+
}
1419+
}
1420+
13231421
// This type intentionally outputs the same format for `Display` and `Debug`for
13241422
// situations where you unwrap a `Report` or return it from main.
13251423
#[unstable(feature = "error_reporter", issue = "90172")]
13261424
impl<E> fmt::Debug for Report<E>
13271425
where
1328-
E: Error,
1426+
Report<E>: fmt::Display,
13291427
{
13301428
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13311429
fmt::Display::fmt(self, f)

0 commit comments

Comments
 (0)