1 #![doc = include_str!("../../core/src/error.md")] 2 #![stable(feature = "rust1", since = "1.0.0")] 3 4 #[cfg(test)] 5 mod tests; 6 7 use crate::backtrace::Backtrace; 8 use crate::fmt::{self, Write}; 9 10 #[stable(feature = "rust1", since = "1.0.0")] 11 pub use core::error::Error; 12 13 mod private { 14 // This is a hack to prevent `type_id` from being overridden by `Error` 15 // implementations, since that can enable unsound downcasting. 16 #[unstable(feature = "error_type_id", issue = "60784")] 17 #[derive(Debug)] 18 pub struct Internal; 19 } 20 21 /// An error reporter that prints an error and its sources. 22 /// 23 /// Report also exposes configuration options for formatting the error sources, either entirely on a 24 /// single line, or in multi-line format with each source on a new line. 25 /// 26 /// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the 27 /// wrapped error be `Send`, `Sync`, or `'static`. 28 /// 29 /// # Examples 30 /// 31 /// ```rust 32 /// #![feature(error_reporter)] 33 /// use std::error::{Error, Report}; 34 /// use std::fmt; 35 /// 36 /// #[derive(Debug)] 37 /// struct SuperError { 38 /// source: SuperErrorSideKick, 39 /// } 40 /// 41 /// impl fmt::Display for SuperError { 42 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 43 /// write!(f, "SuperError is here!") 44 /// } 45 /// } 46 /// 47 /// impl Error for SuperError { 48 /// fn source(&self) -> Option<&(dyn Error + 'static)> { 49 /// Some(&self.source) 50 /// } 51 /// } 52 /// 53 /// #[derive(Debug)] 54 /// struct SuperErrorSideKick; 55 /// 56 /// impl fmt::Display for SuperErrorSideKick { 57 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 58 /// write!(f, "SuperErrorSideKick is here!") 59 /// } 60 /// } 61 /// 62 /// impl Error for SuperErrorSideKick {} 63 /// 64 /// fn get_super_error() -> Result<(), SuperError> { 65 /// Err(SuperError { source: SuperErrorSideKick }) 66 /// } 67 /// 68 /// fn main() { 69 /// match get_super_error() { 70 /// Err(e) => println!("Error: {}", Report::new(e)), 71 /// _ => println!("No error"), 72 /// } 73 /// } 74 /// ``` 75 /// 76 /// This example produces the following output: 77 /// 78 /// ```console 79 /// Error: SuperError is here!: SuperErrorSideKick is here! 80 /// ``` 81 /// 82 /// ## Output consistency 83 /// 84 /// Report prints the same output via `Display` and `Debug`, so it works well with 85 /// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: 86 /// 87 /// ```should_panic 88 /// #![feature(error_reporter)] 89 /// use std::error::Report; 90 /// # use std::error::Error; 91 /// # use std::fmt; 92 /// # #[derive(Debug)] 93 /// # struct SuperError { 94 /// # source: SuperErrorSideKick, 95 /// # } 96 /// # impl fmt::Display for SuperError { 97 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 98 /// # write!(f, "SuperError is here!") 99 /// # } 100 /// # } 101 /// # impl Error for SuperError { 102 /// # fn source(&self) -> Option<&(dyn Error + 'static)> { 103 /// # Some(&self.source) 104 /// # } 105 /// # } 106 /// # #[derive(Debug)] 107 /// # struct SuperErrorSideKick; 108 /// # impl fmt::Display for SuperErrorSideKick { 109 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 110 /// # write!(f, "SuperErrorSideKick is here!") 111 /// # } 112 /// # } 113 /// # impl Error for SuperErrorSideKick {} 114 /// # fn get_super_error() -> Result<(), SuperError> { 115 /// # Err(SuperError { source: SuperErrorSideKick }) 116 /// # } 117 /// 118 /// get_super_error().map_err(Report::new).unwrap(); 119 /// ``` 120 /// 121 /// This example produces the following output: 122 /// 123 /// ```console 124 /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 125 /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 126 /// ``` 127 /// 128 /// ## Return from `main` 129 /// 130 /// `Report` also implements `From` for all types that implement [`Error`]; this when combined with 131 /// the `Debug` output means `Report` is an ideal starting place for formatting errors returned 132 /// from `main`. 133 /// 134 /// ```should_panic 135 /// #![feature(error_reporter)] 136 /// use std::error::Report; 137 /// # use std::error::Error; 138 /// # use std::fmt; 139 /// # #[derive(Debug)] 140 /// # struct SuperError { 141 /// # source: SuperErrorSideKick, 142 /// # } 143 /// # impl fmt::Display for SuperError { 144 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 145 /// # write!(f, "SuperError is here!") 146 /// # } 147 /// # } 148 /// # impl Error for SuperError { 149 /// # fn source(&self) -> Option<&(dyn Error + 'static)> { 150 /// # Some(&self.source) 151 /// # } 152 /// # } 153 /// # #[derive(Debug)] 154 /// # struct SuperErrorSideKick; 155 /// # impl fmt::Display for SuperErrorSideKick { 156 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 157 /// # write!(f, "SuperErrorSideKick is here!") 158 /// # } 159 /// # } 160 /// # impl Error for SuperErrorSideKick {} 161 /// # fn get_super_error() -> Result<(), SuperError> { 162 /// # Err(SuperError { source: SuperErrorSideKick }) 163 /// # } 164 /// 165 /// fn main() -> Result<(), Report<SuperError>> { 166 /// get_super_error()?; 167 /// Ok(()) 168 /// } 169 /// ``` 170 /// 171 /// This example produces the following output: 172 /// 173 /// ```console 174 /// Error: SuperError is here!: SuperErrorSideKick is here! 175 /// ``` 176 /// 177 /// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line 178 /// output format. If you want to make sure your `Report`s are pretty printed and include backtrace 179 /// you will need to manually convert and enable those flags. 180 /// 181 /// ```should_panic 182 /// #![feature(error_reporter)] 183 /// use std::error::Report; 184 /// # use std::error::Error; 185 /// # use std::fmt; 186 /// # #[derive(Debug)] 187 /// # struct SuperError { 188 /// # source: SuperErrorSideKick, 189 /// # } 190 /// # impl fmt::Display for SuperError { 191 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 192 /// # write!(f, "SuperError is here!") 193 /// # } 194 /// # } 195 /// # impl Error for SuperError { 196 /// # fn source(&self) -> Option<&(dyn Error + 'static)> { 197 /// # Some(&self.source) 198 /// # } 199 /// # } 200 /// # #[derive(Debug)] 201 /// # struct SuperErrorSideKick; 202 /// # impl fmt::Display for SuperErrorSideKick { 203 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 204 /// # write!(f, "SuperErrorSideKick is here!") 205 /// # } 206 /// # } 207 /// # impl Error for SuperErrorSideKick {} 208 /// # fn get_super_error() -> Result<(), SuperError> { 209 /// # Err(SuperError { source: SuperErrorSideKick }) 210 /// # } 211 /// 212 /// fn main() -> Result<(), Report<SuperError>> { 213 /// get_super_error() 214 /// .map_err(Report::from) 215 /// .map_err(|r| r.pretty(true).show_backtrace(true))?; 216 /// Ok(()) 217 /// } 218 /// ``` 219 /// 220 /// This example produces the following output: 221 /// 222 /// ```console 223 /// Error: SuperError is here! 224 /// 225 /// Caused by: 226 /// SuperErrorSideKick is here! 227 /// ``` 228 #[unstable(feature = "error_reporter", issue = "90172")] 229 pub struct Report<E = Box<dyn Error>> { 230 /// The error being reported. 231 error: E, 232 /// Whether a backtrace should be included as part of the report. 233 show_backtrace: bool, 234 /// Whether the report should be pretty-printed. 235 pretty: bool, 236 } 237 238 impl<E> Report<E> 239 where 240 Report<E>: From<E>, 241 { 242 /// Create a new `Report` from an input error. 243 #[unstable(feature = "error_reporter", issue = "90172")] new(error: E) -> Report<E>244 pub fn new(error: E) -> Report<E> { 245 Self::from(error) 246 } 247 } 248 249 impl<E> Report<E> { 250 /// Enable pretty-printing the report across multiple lines. 251 /// 252 /// # Examples 253 /// 254 /// ```rust 255 /// #![feature(error_reporter)] 256 /// use std::error::Report; 257 /// # use std::error::Error; 258 /// # use std::fmt; 259 /// # #[derive(Debug)] 260 /// # struct SuperError { 261 /// # source: SuperErrorSideKick, 262 /// # } 263 /// # impl fmt::Display for SuperError { 264 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 265 /// # write!(f, "SuperError is here!") 266 /// # } 267 /// # } 268 /// # impl Error for SuperError { 269 /// # fn source(&self) -> Option<&(dyn Error + 'static)> { 270 /// # Some(&self.source) 271 /// # } 272 /// # } 273 /// # #[derive(Debug)] 274 /// # struct SuperErrorSideKick; 275 /// # impl fmt::Display for SuperErrorSideKick { 276 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 277 /// # write!(f, "SuperErrorSideKick is here!") 278 /// # } 279 /// # } 280 /// # impl Error for SuperErrorSideKick {} 281 /// 282 /// let error = SuperError { source: SuperErrorSideKick }; 283 /// let report = Report::new(error).pretty(true); 284 /// eprintln!("Error: {report:?}"); 285 /// ``` 286 /// 287 /// This example produces the following output: 288 /// 289 /// ```console 290 /// Error: SuperError is here! 291 /// 292 /// Caused by: 293 /// SuperErrorSideKick is here! 294 /// ``` 295 /// 296 /// When there are multiple source errors the causes will be numbered in order of iteration 297 /// starting from the outermost error. 298 /// 299 /// ```rust 300 /// #![feature(error_reporter)] 301 /// use std::error::Report; 302 /// # use std::error::Error; 303 /// # use std::fmt; 304 /// # #[derive(Debug)] 305 /// # struct SuperError { 306 /// # source: SuperErrorSideKick, 307 /// # } 308 /// # impl fmt::Display for SuperError { 309 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 310 /// # write!(f, "SuperError is here!") 311 /// # } 312 /// # } 313 /// # impl Error for SuperError { 314 /// # fn source(&self) -> Option<&(dyn Error + 'static)> { 315 /// # Some(&self.source) 316 /// # } 317 /// # } 318 /// # #[derive(Debug)] 319 /// # struct SuperErrorSideKick { 320 /// # source: SuperErrorSideKickSideKick, 321 /// # } 322 /// # impl fmt::Display for SuperErrorSideKick { 323 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 324 /// # write!(f, "SuperErrorSideKick is here!") 325 /// # } 326 /// # } 327 /// # impl Error for SuperErrorSideKick { 328 /// # fn source(&self) -> Option<&(dyn Error + 'static)> { 329 /// # Some(&self.source) 330 /// # } 331 /// # } 332 /// # #[derive(Debug)] 333 /// # struct SuperErrorSideKickSideKick; 334 /// # impl fmt::Display for SuperErrorSideKickSideKick { 335 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 336 /// # write!(f, "SuperErrorSideKickSideKick is here!") 337 /// # } 338 /// # } 339 /// # impl Error for SuperErrorSideKickSideKick { } 340 /// 341 /// let source = SuperErrorSideKickSideKick; 342 /// let source = SuperErrorSideKick { source }; 343 /// let error = SuperError { source }; 344 /// let report = Report::new(error).pretty(true); 345 /// eprintln!("Error: {report:?}"); 346 /// ``` 347 /// 348 /// This example produces the following output: 349 /// 350 /// ```console 351 /// Error: SuperError is here! 352 /// 353 /// Caused by: 354 /// 0: SuperErrorSideKick is here! 355 /// 1: SuperErrorSideKickSideKick is here! 356 /// ``` 357 #[unstable(feature = "error_reporter", issue = "90172")] pretty(mut self, pretty: bool) -> Self358 pub fn pretty(mut self, pretty: bool) -> Self { 359 self.pretty = pretty; 360 self 361 } 362 363 /// Display backtrace if available when using pretty output format. 364 /// 365 /// # Examples 366 /// 367 /// **Note**: Report will search for the first `Backtrace` it can find starting from the 368 /// outermost error. In this example it will display the backtrace from the second error in the 369 /// sources, `SuperErrorSideKick`. 370 /// 371 /// ```rust 372 /// #![feature(error_reporter)] 373 /// #![feature(provide_any)] 374 /// #![feature(error_generic_member_access)] 375 /// # use std::error::Error; 376 /// # use std::fmt; 377 /// use std::any::Demand; 378 /// use std::error::Report; 379 /// use std::backtrace::Backtrace; 380 /// 381 /// # #[derive(Debug)] 382 /// # struct SuperError { 383 /// # source: SuperErrorSideKick, 384 /// # } 385 /// # impl fmt::Display for SuperError { 386 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 387 /// # write!(f, "SuperError is here!") 388 /// # } 389 /// # } 390 /// # impl Error for SuperError { 391 /// # fn source(&self) -> Option<&(dyn Error + 'static)> { 392 /// # Some(&self.source) 393 /// # } 394 /// # } 395 /// #[derive(Debug)] 396 /// struct SuperErrorSideKick { 397 /// backtrace: Backtrace, 398 /// } 399 /// 400 /// impl SuperErrorSideKick { 401 /// fn new() -> SuperErrorSideKick { 402 /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } 403 /// } 404 /// } 405 /// 406 /// impl Error for SuperErrorSideKick { 407 /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { 408 /// demand.provide_ref::<Backtrace>(&self.backtrace); 409 /// } 410 /// } 411 /// 412 /// // The rest of the example is unchanged ... 413 /// # impl fmt::Display for SuperErrorSideKick { 414 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 415 /// # write!(f, "SuperErrorSideKick is here!") 416 /// # } 417 /// # } 418 /// 419 /// let source = SuperErrorSideKick::new(); 420 /// let error = SuperError { source }; 421 /// let report = Report::new(error).pretty(true).show_backtrace(true); 422 /// eprintln!("Error: {report:?}"); 423 /// ``` 424 /// 425 /// This example produces something similar to the following output: 426 /// 427 /// ```console 428 /// Error: SuperError is here! 429 /// 430 /// Caused by: 431 /// SuperErrorSideKick is here! 432 /// 433 /// Stack backtrace: 434 /// 0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new 435 /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0 436 /// 2: rust_out::main 437 /// 3: core::ops::function::FnOnce::call_once 438 /// 4: std::sys_common::backtrace::__rust_begin_short_backtrace 439 /// 5: std::rt::lang_start::{{closure}} 440 /// 6: std::panicking::try 441 /// 7: std::rt::lang_start_internal 442 /// 8: std::rt::lang_start 443 /// 9: main 444 /// 10: __libc_start_main 445 /// 11: _start 446 /// ``` 447 #[unstable(feature = "error_reporter", issue = "90172")] show_backtrace(mut self, show_backtrace: bool) -> Self448 pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { 449 self.show_backtrace = show_backtrace; 450 self 451 } 452 } 453 454 impl<E> Report<E> 455 where 456 E: Error, 457 { backtrace(&self) -> Option<&Backtrace>458 fn backtrace(&self) -> Option<&Backtrace> { 459 // have to grab the backtrace on the first error directly since that error may not be 460 // 'static 461 let backtrace = (&self.error as &dyn Error).request_ref(); 462 let backtrace = backtrace.or_else(|| { 463 self.error 464 .source() 465 .map(|source| source.sources().find_map(|source| source.request_ref())) 466 .flatten() 467 }); 468 backtrace 469 } 470 471 /// Format the report as a single line. 472 #[unstable(feature = "error_reporter", issue = "90172")] fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result473 fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 474 write!(f, "{}", self.error)?; 475 476 let sources = self.error.source().into_iter().flat_map(<dyn Error>::sources); 477 478 for cause in sources { 479 write!(f, ": {cause}")?; 480 } 481 482 Ok(()) 483 } 484 485 /// Format the report as multiple lines, with each error cause on its own line. 486 #[unstable(feature = "error_reporter", issue = "90172")] fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result487 fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 488 let error = &self.error; 489 490 write!(f, "{error}")?; 491 492 if let Some(cause) = error.source() { 493 write!(f, "\n\nCaused by:")?; 494 495 let multiple = cause.source().is_some(); 496 497 for (ind, error) in cause.sources().enumerate() { 498 writeln!(f)?; 499 let mut indented = Indented { inner: f }; 500 if multiple { 501 write!(indented, "{ind: >4}: {error}")?; 502 } else { 503 write!(indented, " {error}")?; 504 } 505 } 506 } 507 508 if self.show_backtrace { 509 let backtrace = self.backtrace(); 510 511 if let Some(backtrace) = backtrace { 512 let backtrace = backtrace.to_string(); 513 514 f.write_str("\n\nStack backtrace:\n")?; 515 f.write_str(backtrace.trim_end())?; 516 } 517 } 518 519 Ok(()) 520 } 521 } 522 523 #[unstable(feature = "error_reporter", issue = "90172")] 524 impl<E> From<E> for Report<E> 525 where 526 E: Error, 527 { from(error: E) -> Self528 fn from(error: E) -> Self { 529 Report { error, show_backtrace: false, pretty: false } 530 } 531 } 532 533 #[unstable(feature = "error_reporter", issue = "90172")] 534 impl<E> fmt::Display for Report<E> 535 where 536 E: Error, 537 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 539 if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } 540 } 541 } 542 543 // This type intentionally outputs the same format for `Display` and `Debug`for 544 // situations where you unwrap a `Report` or return it from main. 545 #[unstable(feature = "error_reporter", issue = "90172")] 546 impl<E> fmt::Debug for Report<E> 547 where 548 Report<E>: fmt::Display, 549 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result550 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 551 fmt::Display::fmt(self, f) 552 } 553 } 554 555 /// Wrapper type for indenting the inner source. 556 struct Indented<'a, D> { 557 inner: &'a mut D, 558 } 559 560 impl<T> Write for Indented<'_, T> 561 where 562 T: Write, 563 { write_str(&mut self, s: &str) -> fmt::Result564 fn write_str(&mut self, s: &str) -> fmt::Result { 565 for (i, line) in s.split('\n').enumerate() { 566 if i > 0 { 567 self.inner.write_char('\n')?; 568 self.inner.write_str(" ")?; 569 } 570 571 self.inner.write_str(line)?; 572 } 573 574 Ok(()) 575 } 576 } 577