From 0afce620385d6d4fba3c8affa31787f6133bac24 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Fri, 29 Jul 2022 18:54:47 +0000 Subject: [PATCH 01/24] Move error trait into core --- library/alloc/src/boxed.rs | 282 +++++++- library/alloc/src/lib.rs | 2 + library/core/src/error.rs | 565 +++++++++++++++ library/core/src/lib.rs | 3 + library/core/src/str/mod.rs | 4 + library/std/src/error.rs | 1321 ++++++++++++++++++----------------- library/std/src/lib.rs | 2 + 7 files changed, 1533 insertions(+), 646 deletions(-) create mode 100644 library/core/src/error.rs diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index c1ceeb0deb837..5e3c822585e42 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -151,6 +151,8 @@ use core::async_iter::AsyncIterator; use core::borrow; use core::cmp::Ordering; use core::convert::{From, TryFrom}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; @@ -169,11 +171,13 @@ use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw}; use crate::alloc::{AllocError, Allocator, Global, Layout}; -#[cfg(not(no_global_oom_handling))] +#[cfg(any(not(no_global_oom_handling), not(bootstrap)))] use crate::borrow::Cow; use crate::raw_vec::RawVec; #[cfg(not(no_global_oom_handling))] use crate::str::from_boxed_utf8_unchecked; +#[cfg(not(bootstrap))] +use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; @@ -188,6 +192,7 @@ mod thin; #[lang = "owned_box"] #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] +// #[rustc_strict_coherence] // The declaration of the `Box` struct must be kept in sync with the // `alloc::alloc::box_free` function or ICEs will happen. See the comment // on `box_free` for more details. @@ -2085,3 +2090,278 @@ impl AsyncIterator for Box { (**self).size_hint() } } + +#[cfg(not(bootstrap))] +impl dyn Error { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + if self.is::() { + unsafe { + let raw: *mut dyn Error = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +#[cfg(not(bootstrap))] +impl dyn Error + Send { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // Reapply the `Send` marker. + mem::transmute::, Box>(s) + }) + } +} + +#[cfg(not(bootstrap))] +impl dyn Error + Send + Sync { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // Reapply the `Send + Sync` marker. + mem::transmute::, Box>(s) + }) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From for Box { + /// Converts a type of [`Error`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + Sync + 'a> From for Box { + /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of + /// dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// unsafe impl Send for AnError {} + /// + /// unsafe impl Sync for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Box { + /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: String) -> Box { + struct StringError(String); + + impl Error for StringError { + #[allow(deprecated)] + fn description(&self) -> &str { + &self.0 + } + } + + impl fmt::Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + // Purposefully skip printing "StringError(..)" + impl fmt::Debug for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + Box::new(StringError(err)) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl From for Box { + /// Converts a [`String`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(str_err: String) -> Box { + let err1: Box = From::from(str_err); + let err2: Box = err1; + err2 + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: &str) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl From<&str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: &str) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a, 'b> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'b, str>) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'a, str>) -> Box { + From::from(String::from(err)) + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 8b6f4054851dd..2f9695962b49f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -111,6 +111,7 @@ #![feature(const_pin)] #![feature(cstr_from_bytes_until_nul)] #![feature(dispatch_from_dyn)] +#![cfg_attr(not(bootstrap), feature(error_in_core))] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(fmt_internals)] @@ -178,6 +179,7 @@ #![feature(unboxed_closures)] #![feature(unsized_fn_params)] #![feature(c_unwind)] +#![feature(with_negative_coherence)] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/core/src/error.rs b/library/core/src/error.rs new file mode 100644 index 0000000000000..4430e855e741f --- /dev/null +++ b/library/core/src/error.rs @@ -0,0 +1,565 @@ +//! Interfaces for working with Errors. +//! +//! # Error Handling In Rust +//! +//! The Rust language provides two complementary systems for constructing / +//! representing, reporting, propagating, reacting to, and discarding errors. +//! These responsibilities are collectively known as "error handling." The +//! components of the first system, the panic runtime and interfaces, are most +//! commonly used to represent bugs that have been detected in your program. The +//! components of the second system, `Result`, the error traits, and user +//! defined types, are used to represent anticipated runtime failure modes of +//! your program. +//! +//! ## The Panic Interfaces +//! +//! The following are the primary interfaces of the panic system and the +//! responsibilities they cover: +//! +//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) +//! * [`PanicInfo`] (Reporting) +//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) +//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) +//! +//! The following are the primary interfaces of the error system and the +//! responsibilities they cover: +//! +//! * [`Result`] (Propagating, Reacting) +//! * The [`Error`] trait (Reporting) +//! * User defined types (Constructing / Representing) +//! * [`match`] and [`downcast`] (Reacting) +//! * The question mark operator ([`?`]) (Propagating) +//! * The partially stable [`Try`] traits (Propagating, Constructing) +//! * [`Termination`] (Reporting) +//! +//! ## Converting Errors into Panics +//! +//! The panic and error systems are not entirely distinct. Often times errors +//! that are anticipated runtime failures in an API might instead represent bugs +//! to a caller. For these situations the standard library provides APIs for +//! constructing panics with an `Error` as it's source. +//! +//! * [`Result::unwrap`] +//! * [`Result::expect`] +//! +//! These functions are equivalent, they either return the inner value if the +//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error +//! as the source. The only difference between them is that with `expect` you +//! provide a panic error message to be printed alongside the source, whereas +//! `unwrap` has a default message indicating only that you unwraped an `Err`. +//! +//! Of the two, `expect` is generally preferred since its `msg` field allows you +//! to convey your intent and assumptions which makes tracking down the source +//! of a panic easier. `unwrap` on the other hand can still be a good fit in +//! situations where you can trivially show that a piece of code will never +//! panic, such as `"127.0.0.1".parse::().unwrap()` or early +//! prototyping. +//! +//! # Common Message Styles +//! +//! There are two common styles for how people word `expect` messages. Using +//! the message to present information to users encountering a panic +//! ("expect as error message") or using the message to present information +//! to developers debugging the panic ("expect as precondition"). +//! +//! In the former case the expect message is used to describe the error that +//! has occurred which is considered a bug. Consider the following example: +//! +//! ```should_panic +//! // Read environment variable, panic if it is not present +//! let path = std::env::var("IMPORTANT_PATH").unwrap(); +//! ``` +//! +//! In the "expect as error message" style we would use expect to describe +//! that the environment variable was not set when it should have been: +//! +//! ```should_panic +//! let path = std::env::var("IMPORTANT_PATH") +//! .expect("env variable `IMPORTANT_PATH` is not set"); +//! ``` +//! +//! In the "expect as precondition" style, we would instead describe the +//! reason we _expect_ the `Result` should be `Ok`. With this style we would +//! prefer to write: +//! +//! ```should_panic +//! let path = std::env::var("IMPORTANT_PATH") +//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); +//! ``` +//! +//! The "expect as error message" style does not work as well with the +//! default output of the std panic hooks, and often ends up repeating +//! information that is already communicated by the source error being +//! unwrapped: +//! +//! ```text +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 +//! ``` +//! +//! In this example we end up mentioning that an env variable is not set, +//! followed by our source message that says the env is not present, the +//! only additional information we're communicating is the name of the +//! environment variable being checked. +//! +//! The "expect as precondition" style instead focuses on source code +//! readability, making it easier to understand what must have gone wrong in +//! situations where panics are being used to represent bugs exclusively. +//! Also, by framing our expect in terms of what "SHOULD" have happened to +//! prevent the source error, we end up introducing new information that is +//! independent from our source error. +//! +//! ```text +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 +//! ``` +//! +//! In this example we are communicating not only the name of the +//! environment variable that should have been set, but also an explanation +//! for why it should have been set, and we let the source error display as +//! a clear contradiction to our expectation. +//! +//! **Hint**: If you're having trouble remembering how to phrase +//! expect-as-precondition style error messages remember to focus on the word +//! "should" as in "env variable should be set by blah" or "the given binary +//! should be available and executable by the current user". +//! +//! [`panic_any`]: crate::panic::panic_any +//! [`PanicInfo`]: crate::panic::PanicInfo +//! [`catch_unwind`]: crate::panic::catch_unwind +//! [`resume_unwind`]: crate::panic::resume_unwind +//! [`downcast`]: crate::error::Error +//! [`Termination`]: crate::process::Termination +//! [`Try`]: crate::ops::Try +//! [panic hook]: crate::panic::set_hook +//! [`set_hook`]: crate::panic::set_hook +//! [`take_hook`]: crate::panic::take_hook +//! [panic-handler]: +//! [`match`]: ../../std/keyword.match.html +//! [`?`]: ../../std/result/index.html#the-question-mark-operator- + +// A note about crates and the facade: +// +// Originally, the `Error` trait was defined in libcore, and the impls +// were scattered about. However, coherence objected to this +// arrangement, because to create the blanket impls for `Box` required +// knowing that `&str: !Error`, and we have no means to deal with that +// sort of conflict just now. Therefore, for the time being, we have +// moved the `Error` trait into libstd. As we evolve a sol'n to the +// coherence challenge (e.g., specialization, neg impls, etc) we can +// reconsider what crate these items belong in. + +#[cfg(test)] +mod tests; + +use crate::any::{Demand, Provider, TypeId}; +use crate::fmt::{Debug, Display}; + +/// `Error` is a trait representing the basic expectations for error values, +/// i.e., values of type `E` in [`Result`]. +/// +/// Errors must describe themselves through the [`Display`] and [`Debug`] +/// traits. Error messages are typically concise lowercase sentences without +/// trailing punctuation: +/// +/// ``` +/// let err = "NaN".parse::().unwrap_err(); +/// assert_eq!(err.to_string(), "invalid digit found in string"); +/// ``` +/// +/// Errors may provide cause chain information. [`Error::source()`] is generally +/// used when errors cross "abstraction boundaries". If one module must report +/// an error that is caused by an error from a lower-level module, it can allow +/// accessing that error via [`Error::source()`]. This makes it possible for the +/// high-level module to provide its own errors while also revealing some of the +/// implementation for debugging via `source` chains. +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[rustc_has_incoherent_inherent_impls] +pub trait Error: Debug + Display { + /// The lower-level source of this error, if any. + /// + /// # Examples + /// + /// ``` + /// 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() { + /// match get_super_error() { + /// Err(e) => { + /// println!("Error: {e}"); + /// println!("Caused by: {}", e.source().unwrap()); + /// } + /// _ => println!("No error"), + /// } + /// } + /// ``` + #[stable(feature = "error_source", since = "1.30.0")] + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } + + /// Gets the `TypeId` of `self`. + #[doc(hidden)] + #[unstable( + feature = "error_type_id", + reason = "this is memory-unsafe to override in user code", + issue = "60784" + )] + fn type_id(&self, _: private::Internal) -> TypeId + where + Self: 'static, + { + TypeId::of::() + } + + /// ``` + /// if let Err(e) = "xc".parse::() { + /// // Print `e` itself, no need for description(). + /// eprintln!("Error: {e}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")] + fn description(&self) -> &str { + "description() is deprecated; use Display" + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated( + since = "1.33.0", + note = "replaced by Error::source, which can support downcasting" + )] + #[allow(missing_docs)] + fn cause(&self) -> Option<&dyn Error> { + self.source() + } + + /// Provides type based access to context intended for error reports. + /// + /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract + /// references to member variables from `dyn Error` trait objects. + /// + /// # Example + /// + /// ```rust + /// #![feature(provide_any)] + /// #![feature(error_generic_member_access)] + /// use core::fmt; + /// use core::any::Demand; + /// + /// #[derive(Debug)] + /// struct MyBacktrace { + /// // ... + /// } + /// + /// impl MyBacktrace { + /// fn new() -> MyBacktrace { + /// // ... + /// # MyBacktrace {} + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SourceError { + /// // ... + /// } + /// + /// impl fmt::Display for SourceError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Source Error") + /// } + /// } + /// + /// impl std::error::Error for SourceError {} + /// + /// #[derive(Debug)] + /// struct Error { + /// source: SourceError, + /// backtrace: MyBacktrace, + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Error") + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { + /// req + /// .provide_ref::(&self.backtrace) + /// .provide_ref::(&self.source); + /// } + /// } + /// + /// fn main() { + /// let backtrace = MyBacktrace::new(); + /// let source = SourceError {}; + /// let error = Error { source, backtrace }; + /// let dyn_error = &error as &dyn std::error::Error; + /// let backtrace_ref = dyn_error.request_ref::().unwrap(); + /// + /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(unused_variables)] + fn provide<'a>(&'a self, req: &mut Demand<'a>) {} +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<'b> Provider for dyn Error + 'b { + fn provide<'a>(&'a self, req: &mut Demand<'a>) { + self.provide(req) + } +} + +mod private { + // This is a hack to prevent `type_id` from being overridden by `Error` + // implementations, since that can enable unsound downcasting. + #[unstable(feature = "error_type_id", issue = "60784")] + #[derive(Debug)] + pub struct Internal; +} + +#[unstable(feature = "never_type", issue = "35121")] +impl Error for ! {} + +impl<'a> dyn Error + 'a { + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&'a self) -> Option<&'a T> { + core::any::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&'a self) -> Option { + core::any::request_value(self) + } +} + +// Copied from `any.rs`. +impl dyn Error + 'static { + /// Returns `true` if the inner type is the same as `T`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + // Get `TypeId` of the type this function is instantiated with. + let t = TypeId::of::(); + + // Get `TypeId` of the type in the trait object (`self`). + let concrete = self.type_id(private::Internal); + + // Compare both `TypeId`s on equality. + t == concrete + } + + /// Returns some reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&*(self as *const dyn Error as *const T)) } + } else { + None + } + } + + /// Returns some mutable reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.is::() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) } + } else { + None + } + } +} + +impl dyn Error + 'static + Send { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + ::is::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + ::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + ::downcast_mut::(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } +} + +impl dyn Error + 'static + Send + Sync { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + ::is::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + ::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + ::downcast_mut::(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } +} + +impl dyn Error { + /// Returns an iterator starting with the current error and continuing with + /// recursively calling [`Error::source`]. + /// + /// If you want to omit the current error and only use its sources, + /// use `skip(1)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_iter)] + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct A; + /// + /// #[derive(Debug)] + /// struct B(Option>); + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "A") + /// } + /// } + /// + /// impl fmt::Display for B { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "B") + /// } + /// } + /// + /// impl Error for A {} + /// + /// impl Error for B { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// self.0.as_ref().map(|e| e.as_ref()) + /// } + /// } + /// + /// let b = B(Some(Box::new(A))); + /// + /// // let err : Box = b.into(); // or + /// let err = &b as &(dyn Error); + /// + /// let mut iter = err.chain(); + /// + /// assert_eq!("B".to_string(), iter.next().unwrap().to_string()); + /// assert_eq!("A".to_string(), iter.next().unwrap().to_string()); + /// assert!(iter.next().is_none()); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "error_iter", issue = "58520")] + #[inline] + pub fn chain(&self) -> Chain<'_> { + Chain { current: Some(self) } + } +} + +/// An iterator over an [`Error`] and its sources. +/// +/// If you want to omit the initial error and only process +/// its sources, use `skip(1)`. +#[unstable(feature = "error_iter", issue = "58520")] +#[derive(Clone, Debug)] +pub struct Chain<'a> { + current: Option<&'a (dyn Error + 'static)>, +} + +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> Iterator for Chain<'a> { + type Item = &'a (dyn Error + 'static); + + fn next(&mut self) -> Option { + let current = self.current; + self.current = self.current.and_then(Error::source); + current + } +} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24742bb49b9a5..d2770092abb72 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -302,6 +302,9 @@ pub mod clone; pub mod cmp; pub mod convert; pub mod default; +#[cfg(not(bootstrap))] +#[unstable(feature = "error_in_core", issue = "none")] +pub mod error; pub mod marker; pub mod ops; diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index c4f2e283eb3bc..e9f542673d158 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2638,3 +2638,7 @@ impl_fn_for_zst! { unsafe { from_utf8_unchecked(bytes) } }; } + +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +impl !crate::error::Error for &str {} diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 722df119d2294..fa02977bd8f35 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -156,13 +156,20 @@ use core::array; use core::convert::Infallible; use crate::alloc::{AllocError, LayoutError}; -use crate::any::{Demand, Provider, TypeId}; -use crate::backtrace::Backtrace; +use crate::any::Demand; +#[cfg(bootstrap)] +use crate::any::{Provider, TypeId}; +// use crate::backtrace::Backtrace; +#[cfg(bootstrap)] use crate::borrow::Cow; use crate::cell; use crate::char; -use crate::fmt::{self, Debug, Display, Write}; +#[cfg(bootstrap)] +use crate::fmt::Display; +use crate::fmt::{self, Debug}; +//, Write}; use crate::io; +#[cfg(bootstrap)] use crate::mem::transmute; use crate::num; use crate::str; @@ -170,6 +177,10 @@ use crate::string; use crate::sync::Arc; use crate::time; +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::error::Error; + /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result`]. /// @@ -190,6 +201,7 @@ use crate::time; /// implementation for debugging via `source` chains. #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[cfg(bootstrap)] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// @@ -355,6 +367,7 @@ pub trait Error: Debug + Display { fn provide<'a>(&'a self, req: &mut Demand<'a>) {} } +#[cfg(bootstrap)] #[unstable(feature = "error_generic_member_access", issue = "99301")] impl<'b> Provider for dyn Error + 'b { fn provide<'a>(&'a self, req: &mut Demand<'a>) { @@ -370,6 +383,7 @@ mod private { pub struct Internal; } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. @@ -402,6 +416,7 @@ impl<'a, E: Error + 'a> From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + Send + Sync + 'a> From for Box { /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of @@ -440,6 +455,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -483,6 +499,7 @@ impl From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "string_box_error", since = "1.6.0")] impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. @@ -504,6 +521,7 @@ impl From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -527,6 +545,7 @@ impl<'a> From<&str> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "string_box_error", since = "1.6.0")] impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. @@ -548,6 +567,7 @@ impl From<&str> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -569,6 +589,7 @@ impl<'a, 'b> From> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. @@ -589,6 +610,7 @@ impl<'a> From> for Box { } } +#[cfg(bootstrap)] #[unstable(feature = "never_type", issue = "35121")] impl Error for ! {} @@ -857,6 +879,7 @@ impl Error for alloc::ffi::IntoStringError { } } +#[cfg(bootstrap)] impl<'a> dyn Error + 'a { /// Request a reference of type `T` as context about this error. #[unstable(feature = "error_generic_member_access", issue = "99301")] @@ -872,6 +895,7 @@ impl<'a> dyn Error + 'a { } // Copied from `any.rs`. +#[cfg(bootstrap)] impl dyn Error + 'static { /// Returns `true` if the inner type is the same as `T`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -912,6 +936,7 @@ impl dyn Error + 'static { } } +#[cfg(bootstrap)] impl dyn Error + 'static + Send { /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -947,6 +972,7 @@ impl dyn Error + 'static + Send { } } +#[cfg(bootstrap)] impl dyn Error + 'static + Send + Sync { /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -982,6 +1008,7 @@ impl dyn Error + 'static + Send + Sync { } } +#[cfg(bootstrap)] impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1061,10 +1088,12 @@ impl dyn Error { /// its sources, use `skip(1)`. #[unstable(feature = "error_iter", issue = "58520")] #[derive(Clone, Debug)] +#[cfg(bootstrap)] pub struct Chain<'a> { current: Option<&'a (dyn Error + 'static)>, } +#[cfg(bootstrap)] #[unstable(feature = "error_iter", issue = "58520")] impl<'a> Iterator for Chain<'a> { type Item = &'a (dyn Error + 'static); @@ -1076,6 +1105,7 @@ impl<'a> Iterator for Chain<'a> { } } +#[cfg(bootstrap)] impl dyn Error + Send { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1089,6 +1119,7 @@ impl dyn Error + Send { } } +#[cfg(bootstrap)] impl dyn Error + Send + Sync { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1102,645 +1133,645 @@ impl dyn Error + Send + Sync { } } -/// An error reporter that prints 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 implement `Error`. It doesn't require that the -/// wrapped error be `Send`, `Sync`, or `'static`. -/// -/// # Examples -/// -/// ```rust -/// #![feature(error_reporter)] -/// use std::error::{Error, Report}; -/// 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() { -/// match get_super_error() { -/// Err(e) => println!("Error: {}", Report::new(e)), -/// _ => println!("No error"), -/// } -/// } -/// ``` -/// -/// This example produces the following output: -/// -/// ```console -/// Error: SuperError is here!: SuperErrorSideKick is here! -/// ``` -/// -/// ## Output consistency -/// -/// Report prints the same output via `Display` and `Debug`, so it works well with -/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: -/// -/// ```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 -/// ``` -/// -/// ## 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> { - /// 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, -} - -impl Report -where - Report: From, -{ - /// Create a new `Report` from an input error. - #[unstable(feature = "error_reporter", issue = "90172")] - pub fn new(error: E) -> Report { - Self::from(error) - } -} - -impl 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! - /// ``` - /// - /// 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; - self - } - - /// Display backtrace if available when using pretty output format. - /// - /// # 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)] - /// #![feature(provide_any)] - /// #![feature(error_generic_member_access)] - /// # use std::error::Error; - /// # use std::fmt; - /// use std::any::Demand; - /// use std::error::Report; - /// use std::backtrace::Backtrace; - /// - /// # #[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 SuperErrorSideKick { - /// fn new() -> SuperErrorSideKick { - /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } - /// } - /// } - /// - /// impl Error for SuperErrorSideKick { - /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { - /// req - /// .provide_ref::(&self.backtrace); - /// } - /// } - /// - /// // 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:?}"); - /// ``` - /// - /// 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_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 { - 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 as &dyn Error).request_ref(); - let backtrace = backtrace.or_else(|| { - self.error - .source() - .map(|source| source.chain().find_map(|source| source.request_ref())) - .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, "{ind: >4}: {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 - let backtrace = self.error.request_ref(); - let backtrace = backtrace.or_else(|| { - self.error - .source() - .map(|source| source.chain().find_map(|source| source.request_ref())) - .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, "{ind: >4}: {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(()) - } -} - -#[unstable(feature = "error_reporter", issue = "90172")] -impl From for Report -where - E: Error, -{ - fn from(error: E) -> Self { - 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 } - } -} - -#[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) } - } -} - -#[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 - Report: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -/// Wrapper type for indenting the inner source. -struct Indented<'a, D> { - inner: &'a mut D, -} - -impl Write for Indented<'_, T> -where - T: Write, -{ - fn write_str(&mut self, s: &str) -> fmt::Result { - for (i, line) in s.split('\n').enumerate() { - if i > 0 { - self.inner.write_char('\n')?; - self.inner.write_str(" ")?; - } - - self.inner.write_str(line)?; - } - - Ok(()) - } -} +// /// An error reporter that prints 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 implement `Error`. It doesn't require that the +// /// wrapped error be `Send`, `Sync`, or `'static`. +// /// +// /// # Examples +// /// +// /// ```rust +// /// #![feature(error_reporter)] +// /// use std::error::{Error, Report}; +// /// 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() { +// /// match get_super_error() { +// /// Err(e) => println!("Error: {}", Report::new(e)), +// /// _ => println!("No error"), +// /// } +// /// } +// /// ``` +// /// +// /// This example produces the following output: +// /// +// /// ```console +// /// Error: SuperError is here!: SuperErrorSideKick is here! +// /// ``` +// /// +// /// ## Output consistency +// /// +// /// Report prints the same output via `Display` and `Debug`, so it works well with +// /// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: +// /// +// /// ```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 +// /// ``` +// /// +// /// ## 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> { +// /// 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, +// } + +// impl Report +// where +// Report: From, +// { +// /// Create a new `Report` from an input error. +// #[unstable(feature = "error_reporter", issue = "90172")] +// pub fn new(error: E) -> Report { +// Self::from(error) +// } +// } + +// impl 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! +// /// ``` +// /// +// /// 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; +// self +// } + +// /// Display backtrace if available when using pretty output format. +// /// +// /// # 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)] +// /// #![feature(provide_any)] +// /// #![feature(error_generic_member_access)] +// /// # use std::error::Error; +// /// # use std::fmt; +// /// use std::any::Demand; +// /// use std::error::Report; +// /// use std::backtrace::Backtrace; +// /// +// /// # #[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 SuperErrorSideKick { +// /// fn new() -> SuperErrorSideKick { +// /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } +// /// } +// /// } +// /// +// /// impl Error for SuperErrorSideKick { +// /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { +// /// req +// /// .provide_ref::(&self.backtrace); +// /// } +// /// } +// /// +// /// // 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:?}"); +// /// ``` +// /// +// /// 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_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 { +// 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 as &dyn Error).request_ref(); +// let backtrace = backtrace.or_else(|| { +// self.error +// .source() +// .map(|source| source.chain().find_map(|source| source.request_ref())) +// .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, "{ind: >4}: {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 +// let backtrace = self.error.request_ref(); +// let backtrace = backtrace.or_else(|| { +// self.error +// .source() +// .map(|source| source.chain().find_map(|source| source.request_ref())) +// .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, "{ind: >4}: {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(()) +// } +// } + +// #[unstable(feature = "error_reporter", issue = "90172")] +// impl From for Report +// where +// E: Error, +// { +// fn from(error: E) -> Self { +// 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 } +// } +// } + +// #[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) } +// } +// } + +// #[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 +// Report: fmt::Display, +// { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// fmt::Display::fmt(self, f) +// } +// } + +// /// Wrapper type for indenting the inner source. +// struct Indented<'a, D> { +// inner: &'a mut D, +// } + +// impl Write for Indented<'_, T> +// where +// T: Write, +// { +// fn write_str(&mut self, s: &str) -> fmt::Result { +// for (i, line) in s.split('\n').enumerate() { +// if i > 0 { +// self.inner.write_char('\n')?; +// self.inner.write_str(" ")?; +// } + +// self.inner.write_str(line)?; +// } + +// Ok(()) +// } +// } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6b0c0ad7c2166..b2833dca685f5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -269,6 +269,8 @@ #![feature(cstr_internals)] #![feature(duration_checked_float)] #![feature(duration_constants)] +#![cfg_attr(not(bootstrap), feature(error_generic_member_access))] +#![cfg_attr(not(bootstrap), feature(error_in_core))] #![feature(exact_size_is_empty)] #![feature(exclusive_wrapper)] #![feature(extend_one)] From b42d648108009275a659f42c55dc02eb024a56ec Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Tue, 2 Aug 2022 23:49:52 +0000 Subject: [PATCH 02/24] checkpoint --- library/alloc/src/boxed.rs | 18 + library/alloc/src/boxed/thin.rs | 10 + .../alloc/src/collections/btree/map/entry.rs | 11 + library/alloc/src/lib.rs | 54 + library/alloc/src/string.rs | 20 + library/core/src/alloc/layout.rs | 6 + library/core/src/alloc/mod.rs | 10 + library/core/src/array/mod.rs | 11 + library/core/src/char/decode.rs | 11 + library/core/src/char/mod.rs | 6 + library/core/src/convert/mod.rs | 10 + library/core/src/error.rs | 213 ++-- library/core/src/lib.rs | 1 - library/core/src/num/error.rs | 20 + library/core/src/num/mod.rs | 11 + library/core/src/str/error.rs | 20 + library/std/src/collections/hash/map.rs | 11 + library/std/src/error.rs | 1126 +++++++++-------- library/std/src/io/error.rs | 9 + library/std/src/lib.rs | 1 + 20 files changed, 902 insertions(+), 677 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 5e3c822585e42..66795120ad98f 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2365,3 +2365,21 @@ impl<'a> From> for Box { From::from(String::from(err)) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "box_error", since = "1.8.0")] +impl core::error::Error for Box { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + core::error::Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn core::error::Error> { + core::error::Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + core::error::Error::source(&**self) + } +} diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 649ccfcaa9ed8..0a20c74b00fdc 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -2,6 +2,8 @@ // https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs // by matthieu-m use crate::alloc::{self, Layout, LayoutError}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] @@ -271,3 +273,11 @@ impl WithHeader { Layout::new::().extend(value_layout) } } + +#[cfg(not(bootstrap))] +#[unstable(feature = "thin_box", issue = "92791")] +impl Error for ThinBox { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.deref().source() + } +} diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index b6eecf9b0e952..cd7cdc1920719 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -133,6 +133,17 @@ impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display } } +#[cfg(not(bootstrap))] +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error + for crate::collections::btree_map::OccupiedError<'a, K, V> +{ + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 2f9695962b49f..20b1f2f287f93 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -111,6 +111,7 @@ #![feature(const_pin)] #![feature(cstr_from_bytes_until_nul)] #![feature(dispatch_from_dyn)] +#![cfg_attr(not(bootstrap), feature(error_generic_member_access))] #![cfg_attr(not(bootstrap), feature(error_in_core))] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -128,6 +129,7 @@ #![feature(nonnull_slice_from_raw_parts)] #![feature(pattern)] #![feature(pointer_byte_offsets)] +#![cfg_attr(not(bootstrap), feature(provide_any))] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] @@ -240,3 +242,55 @@ pub mod vec; pub mod __export { pub use core::format_args; } + +#[cfg(not(bootstrap))] +#[stable(feature = "arc_error", since = "1.52.0")] +impl core::error::Error for crate::sync::Arc { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + core::error::Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn core::error::Error> { + core::error::Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + core::error::Error::source(&**self) + } + + fn provide<'a>(&'a self, req: &mut core::any::Demand<'a>) { + core::error::Error::provide(&**self, req); + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "try_reserve", since = "1.57.0")] +impl core::error::Error for crate::collections::TryReserveError {} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl core::error::Error for crate::ffi::NulError { + #[allow(deprecated)] + fn description(&self) -> &str { + "nul byte found in data" + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] +impl core::error::Error for crate::ffi::FromVecWithNulError {} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_into", since = "1.7.0")] +impl core::error::Error for crate::ffi::IntoStringError { + #[allow(deprecated)] + fn description(&self) -> &str { + "C string contained non-utf8 bytes" + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + Some(self.__source()) + } +} diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index a5118e5333b82..2c72dcdf1570d 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -44,6 +44,8 @@ #[cfg(not(no_global_oom_handling))] use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt; use core::hash; use core::iter::FusedIterator; @@ -1938,6 +1940,24 @@ impl fmt::Display for FromUtf16Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for FromUtf8Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-8" + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for FromUtf16Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-16" + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for String { diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 59ebe5fbe0227..d33877a86a34e 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -5,6 +5,8 @@ // Your performance intuition is useless. Run perf. use crate::cmp; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::mem::{self, ValidAlign}; use crate::ptr::NonNull; @@ -436,6 +438,10 @@ pub type LayoutErr = LayoutError; #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutError; +#[cfg(not(bootstrap))] +#[stable(feature = "alloc_layout", since = "1.28.0")] +impl Error for LayoutError {} + // (we need this for downstream impl of trait Error) #[stable(feature = "alloc_layout", since = "1.28.0")] impl fmt::Display for LayoutError { diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 6cc6e359e65b6..94efa76664f6a 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -21,6 +21,8 @@ pub use self::layout::LayoutErr; #[stable(feature = "alloc_layout_error", since = "1.50.0")] pub use self::layout::LayoutError; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::ptr::{self, NonNull}; @@ -32,6 +34,14 @@ use crate::ptr::{self, NonNull}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; +#[cfg(not(bootstrap))] +#[unstable( + feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838" +)] +impl Error for AllocError {} + // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocError { diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index c9823a136bc42..7cbd47175123f 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -7,6 +7,8 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::TrustedLen; @@ -119,6 +121,15 @@ impl fmt::Display for TryFromSliceError { } } +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromSliceError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + impl TryFromSliceError { #[unstable( feature = "array_error_internals", diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 71297acd17145..dc8ea66cc6d0e 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -1,5 +1,7 @@ //! UTF-8 and UTF-16 decoding iterators +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use super::from_u32_unchecked; @@ -121,3 +123,12 @@ impl fmt::Display for DecodeUtf16Error { write!(f, "unpaired surrogate found: {:x}", self.code) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl Error for DecodeUtf16Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "unpaired surrogate found" + } +} diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 0df23e7bbe695..d3a9feeaec79b 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -36,6 +36,8 @@ pub use self::methods::encode_utf16_raw; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf8_raw; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt::{self, Write}; use crate::iter::FusedIterator; @@ -582,3 +584,7 @@ impl fmt::Display for TryFromCharError { "unicode code point out of range".fmt(fmt) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "u8_from_char", since = "1.59.0")] +impl Error for TryFromCharError {} diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index b30c8a4aeabdd..5bddfd1a413e7 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -34,6 +34,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{Hash, Hasher}; @@ -715,6 +717,14 @@ impl fmt::Display for Infallible { } } +#[cfg(not(bootstrap))] +#[stable(feature = "str_parse_error2", since = "1.8.0")] +impl Error for Infallible { + fn description(&self) -> &str { + match *self {} + } +} + #[stable(feature = "convert_infallible", since = "1.34.0")] impl PartialEq for Infallible { fn eq(&self, _: &Infallible) -> bool { diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 4430e855e741f..2259415ec8a39 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1,140 +1,6 @@ //! Interfaces for working with Errors. -//! -//! # Error Handling In Rust -//! -//! The Rust language provides two complementary systems for constructing / -//! representing, reporting, propagating, reacting to, and discarding errors. -//! These responsibilities are collectively known as "error handling." The -//! components of the first system, the panic runtime and interfaces, are most -//! commonly used to represent bugs that have been detected in your program. The -//! components of the second system, `Result`, the error traits, and user -//! defined types, are used to represent anticipated runtime failure modes of -//! your program. -//! -//! ## The Panic Interfaces -//! -//! The following are the primary interfaces of the panic system and the -//! responsibilities they cover: -//! -//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) -//! * [`PanicInfo`] (Reporting) -//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) -//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) -//! -//! The following are the primary interfaces of the error system and the -//! responsibilities they cover: -//! -//! * [`Result`] (Propagating, Reacting) -//! * The [`Error`] trait (Reporting) -//! * User defined types (Constructing / Representing) -//! * [`match`] and [`downcast`] (Reacting) -//! * The question mark operator ([`?`]) (Propagating) -//! * The partially stable [`Try`] traits (Propagating, Constructing) -//! * [`Termination`] (Reporting) -//! -//! ## Converting Errors into Panics -//! -//! The panic and error systems are not entirely distinct. Often times errors -//! that are anticipated runtime failures in an API might instead represent bugs -//! to a caller. For these situations the standard library provides APIs for -//! constructing panics with an `Error` as it's source. -//! -//! * [`Result::unwrap`] -//! * [`Result::expect`] -//! -//! These functions are equivalent, they either return the inner value if the -//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error -//! as the source. The only difference between them is that with `expect` you -//! provide a panic error message to be printed alongside the source, whereas -//! `unwrap` has a default message indicating only that you unwraped an `Err`. -//! -//! Of the two, `expect` is generally preferred since its `msg` field allows you -//! to convey your intent and assumptions which makes tracking down the source -//! of a panic easier. `unwrap` on the other hand can still be a good fit in -//! situations where you can trivially show that a piece of code will never -//! panic, such as `"127.0.0.1".parse::().unwrap()` or early -//! prototyping. -//! -//! # Common Message Styles -//! -//! There are two common styles for how people word `expect` messages. Using -//! the message to present information to users encountering a panic -//! ("expect as error message") or using the message to present information -//! to developers debugging the panic ("expect as precondition"). -//! -//! In the former case the expect message is used to describe the error that -//! has occurred which is considered a bug. Consider the following example: -//! -//! ```should_panic -//! // Read environment variable, panic if it is not present -//! let path = std::env::var("IMPORTANT_PATH").unwrap(); -//! ``` -//! -//! In the "expect as error message" style we would use expect to describe -//! that the environment variable was not set when it should have been: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` is not set"); -//! ``` -//! -//! In the "expect as precondition" style, we would instead describe the -//! reason we _expect_ the `Result` should be `Ok`. With this style we would -//! prefer to write: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); -//! ``` -//! -//! The "expect as error message" style does not work as well with the -//! default output of the std panic hooks, and often ends up repeating -//! information that is already communicated by the source error being -//! unwrapped: -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we end up mentioning that an env variable is not set, -//! followed by our source message that says the env is not present, the -//! only additional information we're communicating is the name of the -//! environment variable being checked. -//! -//! The "expect as precondition" style instead focuses on source code -//! readability, making it easier to understand what must have gone wrong in -//! situations where panics are being used to represent bugs exclusively. -//! Also, by framing our expect in terms of what "SHOULD" have happened to -//! prevent the source error, we end up introducing new information that is -//! independent from our source error. -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we are communicating not only the name of the -//! environment variable that should have been set, but also an explanation -//! for why it should have been set, and we let the source error display as -//! a clear contradiction to our expectation. -//! -//! **Hint**: If you're having trouble remembering how to phrase -//! expect-as-precondition style error messages remember to focus on the word -//! "should" as in "env variable should be set by blah" or "the given binary -//! should be available and executable by the current user". -//! -//! [`panic_any`]: crate::panic::panic_any -//! [`PanicInfo`]: crate::panic::PanicInfo -//! [`catch_unwind`]: crate::panic::catch_unwind -//! [`resume_unwind`]: crate::panic::resume_unwind -//! [`downcast`]: crate::error::Error -//! [`Termination`]: crate::process::Termination -//! [`Try`]: crate::ops::Try -//! [panic hook]: crate::panic::set_hook -//! [`set_hook`]: crate::panic::set_hook -//! [`take_hook`]: crate::panic::take_hook -//! [panic-handler]: -//! [`match`]: ../../std/keyword.match.html -//! [`?`]: ../../std/result/index.html#the-question-mark-operator- +// FIXME(yaahc): link to std docs or common docs and try to figure out intradoc issue +#![unstable(feature = "error_in_core", issue = "none")] // A note about crates and the facade: // @@ -563,3 +429,78 @@ impl<'a> Iterator for Chain<'a> { current } } + +#[stable(feature = "error_by_ref", since = "1.51.0")] +impl<'a, T: Error + ?Sized> Error for &'a T { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn Error> { + Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } + + fn provide<'b>(&'b self, req: &mut Demand<'b>) { + Error::provide(&**self, req); + } +} + +#[stable(feature = "fmt_error", since = "1.11.0")] +impl Error for crate::fmt::Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "an error occurred when formatting an argument" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already mutably borrowed" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowMutError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already borrowed" + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for crate::char::CharTryFromError { + #[allow(deprecated)] + fn description(&self) -> &str { + "converted integer out of range for `char`" + } +} + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl Error for crate::char::ParseCharError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "duration_checked_float", issue = "83400")] +impl Error for crate::time::FromFloatSecsError {} + +#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] +impl Error for crate::ffi::FromBytesWithNulError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] +impl Error for crate::ffi::FromBytesUntilNulError {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d2770092abb72..8d04a213f503d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -303,7 +303,6 @@ pub mod cmp; pub mod convert; pub mod default; #[cfg(not(bootstrap))] -#[unstable(feature = "error_in_core", issue = "none")] pub mod error; pub mod marker; pub mod ops; diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 1a223016dae0f..1f6b40e5df554 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -1,6 +1,8 @@ //! Error types for conversion to integral types. use crate::convert::Infallible; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// The error type returned when a checked integral type conversion fails. @@ -144,3 +146,21 @@ impl fmt::Display for ParseIntError { self.__description().fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f481399fdcf92..ed322ade6ebb2 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,6 +3,8 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -57,6 +59,15 @@ pub use wrapping::Wrapping; #[cfg(not(no_fp_fmt_parse))] pub use dec2flt::ParseFloatError; +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseFloatError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + #[stable(feature = "rust1", since = "1.0.0")] pub use error::ParseIntError; diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index 4e569fcc866b6..343889b6999fa 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -1,5 +1,7 @@ //! Defines utf8 error type. +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// Errors which can occur when attempting to interpret a sequence of [`u8`] @@ -122,6 +124,15 @@ impl fmt::Display for Utf8Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for Utf8Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-8: corrupt contents" + } +} + /// An error returned when parsing a `bool` using [`from_str`] fails /// /// [`from_str`]: super::FromStr::from_str @@ -136,3 +147,12 @@ impl fmt::Display for ParseBoolError { "provided string was not `true` or `false`".fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseBoolError { + #[allow(deprecated)] + fn description(&self) -> &str { + "failed to parse bool" + } +} diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index db811343fa322..9845d1faf9aa1 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -9,6 +9,8 @@ use crate::borrow::Borrow; use crate::cell::Cell; use crate::collections::TryReserveError; use crate::collections::TryReserveErrorKind; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt::{self, Debug}; #[allow(deprecated)] use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; @@ -2158,6 +2160,15 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { } } +#[cfg(not(bootstrap))] +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: fmt::Debug, V: fmt::Debug> Error for OccupiedError<'a, K, V> { + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); diff --git a/library/std/src/error.rs b/library/std/src/error.rs index fa02977bd8f35..8ab727377c2da 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -152,29 +152,42 @@ #[cfg(test)] mod tests; +#[cfg(bootstrap)] use core::array; +#[cfg(bootstrap)] use core::convert::Infallible; +#[cfg(bootstrap)] use crate::alloc::{AllocError, LayoutError}; +#[cfg(bootstrap)] use crate::any::Demand; #[cfg(bootstrap)] use crate::any::{Provider, TypeId}; -// use crate::backtrace::Backtrace; +use crate::backtrace::Backtrace; #[cfg(bootstrap)] use crate::borrow::Cow; +#[cfg(bootstrap)] use crate::cell; +#[cfg(bootstrap)] use crate::char; #[cfg(bootstrap)] +use crate::fmt::Debug; +#[cfg(bootstrap)] use crate::fmt::Display; -use crate::fmt::{self, Debug}; -//, Write}; +use crate::fmt::{self, Write}; +#[cfg(bootstrap)] use crate::io; #[cfg(bootstrap)] use crate::mem::transmute; +#[cfg(bootstrap)] use crate::num; +#[cfg(bootstrap)] use crate::str; +#[cfg(bootstrap)] use crate::string; +#[cfg(bootstrap)] use crate::sync::Arc; +#[cfg(bootstrap)] use crate::time; #[cfg(not(bootstrap))] @@ -614,6 +627,7 @@ impl<'a> From> for Box { #[unstable(feature = "never_type", issue = "35121")] impl Error for ! {} +#[cfg(bootstrap)] #[unstable( feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", @@ -621,9 +635,11 @@ impl Error for ! {} )] impl Error for AllocError {} +#[cfg(bootstrap)] #[stable(feature = "alloc_layout", since = "1.28.0")] impl Error for LayoutError {} +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::ParseBoolError { #[allow(deprecated)] @@ -632,6 +648,7 @@ impl Error for str::ParseBoolError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::Utf8Error { #[allow(deprecated)] @@ -640,6 +657,7 @@ impl Error for str::Utf8Error { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseIntError { #[allow(deprecated)] @@ -648,6 +666,7 @@ impl Error for num::ParseIntError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for num::TryFromIntError { #[allow(deprecated)] @@ -656,6 +675,7 @@ impl Error for num::TryFromIntError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for array::TryFromSliceError { #[allow(deprecated)] @@ -664,6 +684,7 @@ impl Error for array::TryFromSliceError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseFloatError { #[allow(deprecated)] @@ -672,6 +693,7 @@ impl Error for num::ParseFloatError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for string::FromUtf8Error { #[allow(deprecated)] @@ -680,6 +702,7 @@ impl Error for string::FromUtf8Error { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for string::FromUtf16Error { #[allow(deprecated)] @@ -688,6 +711,7 @@ impl Error for string::FromUtf16Error { } } +#[cfg(bootstrap)] #[stable(feature = "str_parse_error2", since = "1.8.0")] impl Error for Infallible { fn description(&self) -> &str { @@ -695,6 +719,7 @@ impl Error for Infallible { } } +#[cfg(bootstrap)] #[stable(feature = "decode_utf16", since = "1.9.0")] impl Error for char::DecodeUtf16Error { #[allow(deprecated)] @@ -703,9 +728,11 @@ impl Error for char::DecodeUtf16Error { } } +#[cfg(bootstrap)] #[stable(feature = "u8_from_char", since = "1.59.0")] impl Error for char::TryFromCharError {} +#[cfg(bootstrap)] #[unstable(feature = "map_try_insert", issue = "82766")] impl<'a, K: Debug + Ord, V: Debug> Error for crate::collections::btree_map::OccupiedError<'a, K, V> @@ -716,6 +743,7 @@ impl<'a, K: Debug + Ord, V: Debug> Error } } +#[cfg(bootstrap)] #[unstable(feature = "map_try_insert", issue = "82766")] impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> { #[allow(deprecated)] @@ -724,6 +752,7 @@ impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedErr } } +#[cfg(bootstrap)] #[stable(feature = "box_error", since = "1.8.0")] impl Error for Box { #[allow(deprecated, deprecated_in_future)] @@ -741,6 +770,7 @@ impl Error for Box { } } +#[cfg(bootstrap)] #[unstable(feature = "thin_box", issue = "92791")] impl crate::error::Error for crate::boxed::ThinBox { fn source(&self) -> Option<&(dyn crate::error::Error + 'static)> { @@ -749,6 +779,7 @@ impl crate::error::Error for crate::boxed::Thin } } +#[cfg(bootstrap)] #[stable(feature = "error_by_ref", since = "1.51.0")] impl<'a, T: Error + ?Sized> Error for &'a T { #[allow(deprecated, deprecated_in_future)] @@ -770,6 +801,7 @@ impl<'a, T: Error + ?Sized> Error for &'a T { } } +#[cfg(bootstrap)] #[stable(feature = "arc_error", since = "1.52.0")] impl Error for Arc { #[allow(deprecated, deprecated_in_future)] @@ -791,6 +823,7 @@ impl Error for Arc { } } +#[cfg(bootstrap)] #[stable(feature = "fmt_error", since = "1.11.0")] impl Error for fmt::Error { #[allow(deprecated)] @@ -799,6 +832,7 @@ impl Error for fmt::Error { } } +#[cfg(bootstrap)] #[stable(feature = "try_borrow", since = "1.13.0")] impl Error for cell::BorrowError { #[allow(deprecated)] @@ -807,6 +841,7 @@ impl Error for cell::BorrowError { } } +#[cfg(bootstrap)] #[stable(feature = "try_borrow", since = "1.13.0")] impl Error for cell::BorrowMutError { #[allow(deprecated)] @@ -815,6 +850,7 @@ impl Error for cell::BorrowMutError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for char::CharTryFromError { #[allow(deprecated)] @@ -823,6 +859,7 @@ impl Error for char::CharTryFromError { } } +#[cfg(bootstrap)] #[stable(feature = "char_from_str", since = "1.20.0")] impl Error for char::ParseCharError { #[allow(deprecated)] @@ -831,12 +868,15 @@ impl Error for char::ParseCharError { } } +#[cfg(bootstrap)] #[stable(feature = "try_reserve", since = "1.57.0")] impl Error for alloc::collections::TryReserveError {} +#[cfg(bootstrap)] #[unstable(feature = "duration_checked_float", issue = "83400")] impl Error for time::FromFloatSecsError {} +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for alloc::ffi::NulError { #[allow(deprecated)] @@ -845,6 +885,7 @@ impl Error for alloc::ffi::NulError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl From for io::Error { /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`]. @@ -853,6 +894,7 @@ impl From for io::Error { } } +#[cfg(bootstrap)] #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl Error for core::ffi::FromBytesWithNulError { #[allow(deprecated)] @@ -861,12 +903,15 @@ impl Error for core::ffi::FromBytesWithNulError { } } +#[cfg(bootstrap)] #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] impl Error for core::ffi::FromBytesUntilNulError {} +#[cfg(bootstrap)] #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl Error for alloc::ffi::FromVecWithNulError {} +#[cfg(bootstrap)] #[stable(feature = "cstring_into", since = "1.7.0")] impl Error for alloc::ffi::IntoStringError { #[allow(deprecated)] @@ -1133,509 +1178,509 @@ impl dyn Error + Send + Sync { } } -// /// An error reporter that prints 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 implement `Error`. It doesn't require that the -// /// wrapped error be `Send`, `Sync`, or `'static`. -// /// -// /// # Examples -// /// -// /// ```rust -// /// #![feature(error_reporter)] -// /// use std::error::{Error, Report}; -// /// 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() { -// /// match get_super_error() { -// /// Err(e) => println!("Error: {}", Report::new(e)), -// /// _ => println!("No error"), -// /// } -// /// } -// /// ``` -// /// -// /// This example produces the following output: -// /// -// /// ```console -// /// Error: SuperError is here!: SuperErrorSideKick is here! -// /// ``` -// /// -// /// ## Output consistency -// /// -// /// Report prints the same output via `Display` and `Debug`, so it works well with -// /// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: -// /// -// /// ```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 -// /// ``` -// /// -// /// ## 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> { -// /// 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, -// } - -// impl Report -// where -// Report: From, -// { -// /// Create a new `Report` from an input error. -// #[unstable(feature = "error_reporter", issue = "90172")] -// pub fn new(error: E) -> Report { -// Self::from(error) -// } -// } - -// impl 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! -// /// ``` -// /// -// /// 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; -// self -// } - -// /// Display backtrace if available when using pretty output format. -// /// -// /// # 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)] -// /// #![feature(provide_any)] -// /// #![feature(error_generic_member_access)] -// /// # use std::error::Error; -// /// # use std::fmt; -// /// use std::any::Demand; -// /// use std::error::Report; -// /// use std::backtrace::Backtrace; -// /// -// /// # #[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 SuperErrorSideKick { -// /// fn new() -> SuperErrorSideKick { -// /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } -// /// } -// /// } -// /// -// /// impl Error for SuperErrorSideKick { -// /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { -// /// req -// /// .provide_ref::(&self.backtrace); -// /// } -// /// } -// /// -// /// // 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:?}"); -// /// ``` -// /// -// /// 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_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 { -// self.show_backtrace = show_backtrace; -// self -// } -// } +/// An error reporter that prints 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 implement `Error`. It doesn't require that the +/// wrapped error be `Send`, `Sync`, or `'static`. +/// +/// # Examples +/// +/// ```rust +/// #![feature(error_reporter)] +/// use std::error::{Error, Report}; +/// 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() { +/// match get_super_error() { +/// Err(e) => println!("Error: {}", Report::new(e)), +/// _ => println!("No error"), +/// } +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here!: SuperErrorSideKick is here! +/// ``` +/// +/// ## Output consistency +/// +/// Report prints the same output via `Display` and `Debug`, so it works well with +/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: +/// +/// ```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 +/// ``` +/// +/// ## 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> { + /// 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, +} -// 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 as &dyn Error).request_ref(); -// let backtrace = backtrace.or_else(|| { -// self.error -// .source() -// .map(|source| source.chain().find_map(|source| source.request_ref())) -// .flatten() -// }); -// backtrace -// } +impl Report +where + Report: From, +{ + /// Create a new `Report` from an input error. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn new(error: E) -> Report { + Self::from(error) + } +} -// /// 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)?; +impl 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! + /// ``` + /// + /// 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; + self + } -// let sources = self.error.source().into_iter().flat_map(::chain); + /// Display backtrace if available when using pretty output format. + /// + /// # 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)] + /// #![feature(provide_any)] + /// #![feature(error_generic_member_access)] + /// # use std::error::Error; + /// # use std::fmt; + /// use std::any::Demand; + /// use std::error::Report; + /// use std::backtrace::Backtrace; + /// + /// # #[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 SuperErrorSideKick { + /// fn new() -> SuperErrorSideKick { + /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } + /// } + /// } + /// + /// impl Error for SuperErrorSideKick { + /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { + /// req + /// .provide_ref::(&self.backtrace); + /// } + /// } + /// + /// // 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:?}"); + /// ``` + /// + /// 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_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 { + self.show_backtrace = show_backtrace; + self + } +} -// for cause in sources { -// write!(f, ": {cause}")?; -// } +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 as &dyn Error).request_ref(); + let backtrace = backtrace.or_else(|| { + self.error + .source() + .map(|source| source.chain().find_map(|source| source.request_ref())) + .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(()) -// } + 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; + /// 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}")?; + write!(f, "{error}")?; -// if let Some(cause) = error.source() { -// write!(f, "\n\nCaused by:")?; + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; -// let multiple = cause.source().is_some(); + 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, "{ind: >4}: {error}")?; -// } else { -// write!(indented, " {error}")?; -// } -// } -// } + for (ind, error) in cause.chain().enumerate() { + writeln!(f)?; + let mut indented = Indented { inner: f }; + if multiple { + write!(indented, "{ind: >4}: {error}")?; + } else { + write!(indented, " {error}")?; + } + } + } -// if self.show_backtrace { -// let backtrace = self.backtrace(); + if self.show_backtrace { + let backtrace = self.backtrace(); -// if let Some(backtrace) = backtrace { -// let backtrace = backtrace.to_string(); + if let Some(backtrace) = backtrace { + let backtrace = backtrace.to_string(); -// f.write_str("\n\nStack backtrace:\n")?; -// f.write_str(backtrace.trim_end())?; -// } -// } + f.write_str("\n\nStack backtrace:\n")?; + f.write_str(backtrace.trim_end())?; + } + } -// Ok(()) -// } -// } + Ok(()) + } +} // impl Report> { // fn backtrace(&self) -> Option<&Backtrace> { @@ -1703,16 +1748,17 @@ impl dyn Error + Send + Sync { // } // } -// #[unstable(feature = "error_reporter", issue = "90172")] -// impl From for Report -// where -// E: Error, -// { -// fn from(error: E) -> Self { -// Report { error, show_backtrace: false, pretty: false } -// } -// } +#[unstable(feature = "error_reporter", issue = "90172")] +impl From for Report +where + E: Error, +{ + fn from(error: E) -> Self { + Report { error, show_backtrace: false, pretty: false } + } +} +// FIXME(yaahc): replace Box with a newtype // #[unstable(feature = "error_reporter", issue = "90172")] // impl<'a, E> From for Report> // where @@ -1724,15 +1770,15 @@ impl dyn Error + Send + Sync { // } // } -// #[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) } -// } -// } +#[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) } + } +} // #[unstable(feature = "error_reporter", issue = "90172")] // impl fmt::Display for Report> { @@ -1741,37 +1787,37 @@ impl dyn Error + Send + Sync { // } // } -// // 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 -// Report: fmt::Display, -// { -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// fmt::Display::fmt(self, 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 + Report: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} -// /// Wrapper type for indenting the inner source. -// struct Indented<'a, D> { -// inner: &'a mut D, -// } +/// Wrapper type for indenting the inner source. +struct Indented<'a, D> { + inner: &'a mut D, +} -// impl Write for Indented<'_, T> -// where -// T: Write, -// { -// fn write_str(&mut self, s: &str) -> fmt::Result { -// for (i, line) in s.split('\n').enumerate() { -// if i > 0 { -// self.inner.write_char('\n')?; -// self.inner.write_str(" ")?; -// } +impl Write for Indented<'_, T> +where + T: Write, +{ + fn write_str(&mut self, s: &str) -> fmt::Result { + for (i, line) in s.split('\n').enumerate() { + if i > 0 { + self.inner.write_char('\n')?; + self.inner.write_str(" ")?; + } -// self.inner.write_str(line)?; -// } + self.inner.write_str(line)?; + } -// Ok(()) -// } -// } + Ok(()) + } +} diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index ff7fdcae16f53..518a94a3c2883 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -76,6 +76,15 @@ impl fmt::Debug for Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Error { + /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`]. + fn from(_: alloc::ffi::NulError) -> Error { + const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") + } +} + // Only derive debug in tests, to make sure it // doesn't accidentally get printed. #[cfg_attr(test, derive(Debug))] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b2833dca685f5..5a970c7dbd3a3 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -271,6 +271,7 @@ #![feature(duration_constants)] #![cfg_attr(not(bootstrap), feature(error_generic_member_access))] #![cfg_attr(not(bootstrap), feature(error_in_core))] +#![cfg_attr(not(bootstrap), feature(error_iter))] #![feature(exact_size_is_empty)] #![feature(exclusive_wrapper)] #![feature(extend_one)] From 863488dfd55c47ace05cc16ef9453831ca4335d5 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 7 Aug 2022 17:17:27 +0800 Subject: [PATCH 03/24] parser will not give wrong help message for 'public' --- compiler/rustc_ast/src/token.rs | 20 +++++++++++++++++++ .../rustc_parse/src/parser/diagnostics.rs | 18 ++++++++--------- compiler/rustc_span/src/symbol.rs | 1 + .../ui/parser/public-instead-of-pub-1.fixed | 11 ++++++++++ src/test/ui/parser/public-instead-of-pub-1.rs | 11 ++++++++++ .../ui/parser/public-instead-of-pub-1.stderr | 13 ++++++++++++ src/test/ui/parser/public-instead-of-pub-2.rs | 7 +++++++ .../ui/parser/public-instead-of-pub-2.stderr | 8 ++++++++ 8 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/parser/public-instead-of-pub-1.fixed create mode 100644 src/test/ui/parser/public-instead-of-pub-1.rs create mode 100644 src/test/ui/parser/public-instead-of-pub-1.stderr create mode 100644 src/test/ui/parser/public-instead-of-pub-2.rs create mode 100644 src/test/ui/parser/public-instead-of-pub-2.stderr diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 85d9687c600dc..bd4ad2873c07c 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -436,6 +436,26 @@ impl Token { || self == &OpenDelim(Delimiter::Parenthesis) } + /// Returns `true` if the token can appear at the start of a item + pub fn can_begin_item(&self) -> bool { + self.is_keyword(kw::Use) + || self.is_keyword(kw::Fn) + || self.is_keyword(kw::Extern) + || self.is_keyword(kw::Crate) + || self.is_keyword(kw::Mod) + || self.is_keyword(kw::Const) + || self.is_keyword(kw::Static) + || self.is_keyword(kw::Trait) + || self.is_keyword(kw::Impl) + || self.is_keyword(kw::Mod) + || self.is_keyword(kw::Type) + || self.is_keyword(kw::Enum) + || self.is_keyword(kw::Struct) + || self.is_keyword(kw::Union) + || self.is_keyword(kw::Macro) + || self == &OpenDelim(Delimiter::Parenthesis) + } + /// Returns `true` if the token is any literal. pub fn is_lit(&self) -> bool { matches!(self.kind, Literal(..)) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a2155ac1d1ad4..1a3db94c93857 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -22,7 +22,7 @@ use rustc_errors::{ use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; use std::ops::{Deref, DerefMut}; @@ -602,15 +602,13 @@ impl<'a> Parser<'a> { self.last_unexpected_token_span = Some(self.token.span); let mut err = self.struct_span_err(self.token.span, &msg_exp); - if let TokenKind::Ident(symbol, _) = &self.prev_token.kind { - if symbol.as_str() == "public" { - err.span_suggestion_short( - self.prev_token.span, - "write `pub` instead of `public` to make the item public", - "pub", - appl, - ); - } + if self.prev_token.is_ident_named(sym::public) && self.token.can_begin_item() { + err.span_suggestion_short( + self.prev_token.span, + "write `pub` instead of `public` to make the item public", + "pub", + appl, + ); } // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 791160ff6944e..16d3766d88e67 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1118,6 +1118,7 @@ symbols! { ptr_offset_from_unsigned, pub_macro_rules, pub_restricted, + public, pure, pushpop_unsafe, qreg, diff --git a/src/test/ui/parser/public-instead-of-pub-1.fixed b/src/test/ui/parser/public-instead-of-pub-1.fixed new file mode 100644 index 0000000000000..a4fa68ba5cc2f --- /dev/null +++ b/src/test/ui/parser/public-instead-of-pub-1.fixed @@ -0,0 +1,11 @@ +// Checks what happens when `public` is used instead of the correct, `pub` +// run-rustfix + +pub enum Test { + //~^ ERROR expected one of `!` or `::`, found keyword `enum` + //~^^ HELP write `pub` instead of `public` to make the item public + A, + B, +} + +fn main() { } diff --git a/src/test/ui/parser/public-instead-of-pub-1.rs b/src/test/ui/parser/public-instead-of-pub-1.rs new file mode 100644 index 0000000000000..43565c9b1d25f --- /dev/null +++ b/src/test/ui/parser/public-instead-of-pub-1.rs @@ -0,0 +1,11 @@ +// Checks what happens when `public` is used instead of the correct, `pub` +// run-rustfix + +public enum Test { + //~^ ERROR expected one of `!` or `::`, found keyword `enum` + //~^^ HELP write `pub` instead of `public` to make the item public + A, + B, +} + +fn main() { } diff --git a/src/test/ui/parser/public-instead-of-pub-1.stderr b/src/test/ui/parser/public-instead-of-pub-1.stderr new file mode 100644 index 0000000000000..795a5bcf5dfa6 --- /dev/null +++ b/src/test/ui/parser/public-instead-of-pub-1.stderr @@ -0,0 +1,13 @@ +error: expected one of `!` or `::`, found keyword `enum` + --> $DIR/public-instead-of-pub-1.rs:4:8 + | +LL | public enum Test { + | ^^^^ expected one of `!` or `::` + | +help: write `pub` instead of `public` to make the item public + | +LL | pub enum Test { + | ~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/parser/public-instead-of-pub-2.rs b/src/test/ui/parser/public-instead-of-pub-2.rs new file mode 100644 index 0000000000000..8a43c361e0510 --- /dev/null +++ b/src/test/ui/parser/public-instead-of-pub-2.rs @@ -0,0 +1,7 @@ +// Checks what happens when `public` is used instead of the correct, `pub` +// Won't give help message for this case + +public let x = 1; +//~^ ERROR expected one of `!` or `::`, found keyword `let` + +fn main() { } diff --git a/src/test/ui/parser/public-instead-of-pub-2.stderr b/src/test/ui/parser/public-instead-of-pub-2.stderr new file mode 100644 index 0000000000000..efe225656fd7f --- /dev/null +++ b/src/test/ui/parser/public-instead-of-pub-2.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `let` + --> $DIR/public-instead-of-pub-2.rs:4:8 + | +LL | public let x = 1; + | ^^^ expected one of `!` or `::` + +error: aborting due to previous error + From 2b4ffa78befae244c955ec62580f9c43d982c04e Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Wed, 10 Aug 2022 19:45:46 +0000 Subject: [PATCH 04/24] fix broken link --- library/std/src/io/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 518a94a3c2883..885e44f5e18bd 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -79,7 +79,7 @@ impl fmt::Debug for Error { #[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] impl From for Error { - /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`]. + /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. fn from(_: alloc::ffi::NulError) -> Error { const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") } From 7f2af2aa74ac98079f914eb8a40f4c5304003884 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Wed, 10 Aug 2022 20:15:28 +0000 Subject: [PATCH 05/24] cleanup to prep for review --- library/alloc/src/boxed.rs | 1 - library/alloc/src/collections/mod.rs | 4 +++ library/alloc/src/ffi/c_str.rs | 26 ++++++++++++++ library/alloc/src/lib.rs | 52 ---------------------------- library/alloc/src/sync.rs | 22 ++++++++++++ 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 66795120ad98f..d8776055e9d3d 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -192,7 +192,6 @@ mod thin; #[lang = "owned_box"] #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] -// #[rustc_strict_coherence] // The declaration of the `Box` struct must be kept in sync with the // `alloc::alloc::box_free` function or ICEs will happen. See the comment // on `box_free` for more details. diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 628a5b155673c..21d0def0866ed 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -152,3 +152,7 @@ trait SpecExtend { /// Extends `self` with the contents of the given iterator. fn spec_extend(&mut self, iter: I); } + +#[cfg(not(bootstrap))] +#[stable(feature = "try_reserve", since = "1.57.0")] +impl core::error::Error for TryReserveError {} diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index ae61b1f1e8ed5..b3c3941be5afb 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1121,3 +1121,29 @@ impl CStr { CString::from(self) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl core::error::Error for NulError { + #[allow(deprecated)] + fn description(&self) -> &str { + "nul byte found in data" + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] +impl core::error::Error for FromVecWithNulError {} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_into", since = "1.7.0")] +impl core::error::Error for IntoStringError { + #[allow(deprecated)] + fn description(&self) -> &str { + "C string contained non-utf8 bytes" + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + Some(self.__source()) + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 20b1f2f287f93..93f40d902ef24 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -242,55 +242,3 @@ pub mod vec; pub mod __export { pub use core::format_args; } - -#[cfg(not(bootstrap))] -#[stable(feature = "arc_error", since = "1.52.0")] -impl core::error::Error for crate::sync::Arc { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - core::error::Error::description(&**self) - } - - #[allow(deprecated)] - fn cause(&self) -> Option<&dyn core::error::Error> { - core::error::Error::cause(&**self) - } - - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - core::error::Error::source(&**self) - } - - fn provide<'a>(&'a self, req: &mut core::any::Demand<'a>) { - core::error::Error::provide(&**self, req); - } -} - -#[cfg(not(bootstrap))] -#[stable(feature = "try_reserve", since = "1.57.0")] -impl core::error::Error for crate::collections::TryReserveError {} - -#[cfg(not(bootstrap))] -#[stable(feature = "rust1", since = "1.0.0")] -impl core::error::Error for crate::ffi::NulError { - #[allow(deprecated)] - fn description(&self) -> &str { - "nul byte found in data" - } -} - -#[cfg(not(bootstrap))] -#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] -impl core::error::Error for crate::ffi::FromVecWithNulError {} - -#[cfg(not(bootstrap))] -#[stable(feature = "cstring_into", since = "1.7.0")] -impl core::error::Error for crate::ffi::IntoStringError { - #[allow(deprecated)] - fn description(&self) -> &str { - "C string contained non-utf8 bytes" - } - - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - Some(self.__source()) - } -} diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4c03cc3ed158a..4377edeee8710 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2763,3 +2763,25 @@ fn data_offset_align(align: usize) -> usize { let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } + +#[cfg(not(bootstrap))] +#[stable(feature = "arc_error", since = "1.52.0")] +impl core::error::Error for Arc { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + core::error::Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn core::error::Error> { + core::error::Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + core::error::Error::source(&**self) + } + + fn provide<'a>(&'a self, req: &mut core::any::Demand<'a>) { + core::error::Error::provide(&**self, req); + } +} From 813b5de16f2773519ab4c5dcbfc70a62b83350ca Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Wed, 10 Aug 2022 20:17:09 +0000 Subject: [PATCH 06/24] remove temporarily invalid code to be added back in a diff PR --- library/std/src/error.rs | 85 ---------------------------------------- 1 file changed, 85 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 8ab727377c2da..f424c512136b7 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1682,72 +1682,6 @@ where } } -// impl Report> { -// 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.request_ref(); -// let backtrace = backtrace.or_else(|| { -// self.error -// .source() -// .map(|source| source.chain().find_map(|source| source.request_ref())) -// .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, "{ind: >4}: {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(()) -// } -// } - #[unstable(feature = "error_reporter", issue = "90172")] impl From for Report where @@ -1758,18 +1692,6 @@ where } } -// FIXME(yaahc): replace Box with a newtype -// #[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 } -// } -// } - #[unstable(feature = "error_reporter", issue = "90172")] impl fmt::Display for Report where @@ -1780,13 +1702,6 @@ 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")] From 637508898ec5ad78c269024ecd9094231b51eaad Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Wed, 10 Aug 2022 20:19:11 +0000 Subject: [PATCH 07/24] make provider impl into a blanket impl --- library/core/src/error.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 2259415ec8a39..8b2e538e87f1d 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -206,7 +206,10 @@ pub trait Error: Debug + Display { } #[unstable(feature = "error_generic_member_access", issue = "99301")] -impl<'b> Provider for dyn Error + 'b { +impl Provider for E +where + E: Error, +{ fn provide<'a>(&'a self, req: &mut Demand<'a>) { self.provide(req) } From 01bc13c4943669a6790ca8f76fc73472ecb55fe6 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Wed, 10 Aug 2022 21:36:25 +0000 Subject: [PATCH 08/24] include unsized --- library/core/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 8b2e538e87f1d..1dc213237aa78 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -208,7 +208,7 @@ pub trait Error: Debug + Display { #[unstable(feature = "error_generic_member_access", issue = "99301")] impl Provider for E where - E: Error, + E: Error + ?Sized, { fn provide<'a>(&'a self, req: &mut Demand<'a>) { self.provide(req) From ada65c2aad095ca13ac4b353100083c324356512 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Thu, 11 Aug 2022 18:37:08 +0000 Subject: [PATCH 09/24] fix broken tests --- library/alloc/src/boxed.rs | 11 ++++++++++- library/core/src/num/mod.rs | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index d8776055e9d3d..346df21383650 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -171,12 +171,13 @@ use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw}; use crate::alloc::{AllocError, Allocator, Global, Layout}; -#[cfg(any(not(no_global_oom_handling), not(bootstrap)))] +#[cfg(not(no_global_oom_handling))] use crate::borrow::Cow; use crate::raw_vec::RawVec; #[cfg(not(no_global_oom_handling))] use crate::str::from_boxed_utf8_unchecked; #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; @@ -2139,6 +2140,7 @@ impl dyn Error + Send + Sync { } #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. @@ -2172,6 +2174,7 @@ impl<'a, E: Error + 'a> From for Box { } #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + Send + Sync + 'a> From for Box { /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of @@ -2211,6 +2214,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -2255,6 +2259,7 @@ impl From for Box { } #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] #[stable(feature = "string_box_error", since = "1.6.0")] impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. @@ -2277,6 +2282,7 @@ impl From for Box { } #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -2301,6 +2307,7 @@ impl<'a> From<&str> for Box { } #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] #[stable(feature = "string_box_error", since = "1.6.0")] impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. @@ -2323,6 +2330,7 @@ impl From<&str> for Box { } #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -2345,6 +2353,7 @@ impl<'a, 'b> From> for Box { } #[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index ed322ade6ebb2..8f5e39dc29522 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -60,6 +60,7 @@ pub use wrapping::Wrapping; pub use dec2flt::ParseFloatError; #[cfg(not(bootstrap))] +#[cfg(not(no_fp_fmt_parse))] #[stable(feature = "rust1", since = "1.0.0")] impl Error for ParseFloatError { #[allow(deprecated)] From 780bb0861b348c63aeb7319138118fd7208a3d8c Mon Sep 17 00:00:00 2001 From: Jean CASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Tue, 16 Aug 2022 22:28:51 +0200 Subject: [PATCH 10/24] Migrate ast_lowering::path to SessionDiagnostic --- Cargo.lock | 1 + compiler/rustc_ast_lowering/Cargo.toml | 1 + compiler/rustc_ast_lowering/src/errors.rs | 29 +++++++++++++++++++ compiler/rustc_ast_lowering/src/lib.rs | 1 + compiler/rustc_ast_lowering/src/path.rs | 23 +++++---------- .../locales/en-US/ast_lowering.ftl | 5 ++++ compiler/rustc_error_messages/src/lib.rs | 1 + 7 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 compiler/rustc_ast_lowering/src/errors.rs create mode 100644 compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl diff --git a/Cargo.lock b/Cargo.lock index 395f5a127bd3d..f3054c1d6598e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3575,6 +3575,7 @@ dependencies = [ "rustc_errors", "rustc_hir", "rustc_index", + "rustc_macros", "rustc_middle", "rustc_query_system", "rustc_session", diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 39ba62ef2ffc5..474aff2e2aac0 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -15,6 +15,7 @@ rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } +rustc_macros = { path = "../rustc_macros" } rustc_query_system = { path = "../rustc_query_system" } rustc_span = { path = "../rustc_span" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs new file mode 100644 index 0000000000000..8701491c9eb3d --- /dev/null +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -0,0 +1,29 @@ +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::generic_type_with_parentheses, code = "E0214")] +pub struct GenericTypeWithParentheses { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sub: Option, +} + +#[derive(Clone, Copy)] +pub struct UseAngleBrackets { + pub open_param: Span, + pub close_param: Span, +} + +impl AddSubdiagnostic for UseAngleBrackets { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + diag.multipart_suggestion( + fluent::ast_lowering::use_angle_brackets, + vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))], + Applicability::MaybeIncorrect, + ); + } +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5f5667ce9055f..958885ea4c532 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -75,6 +75,7 @@ macro_rules! arena_vec { mod asm; mod block; +mod errors; mod expr; mod index; mod item; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 393be3b454c37..5874d08a94fe0 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,11 +1,11 @@ use crate::ImplTraitPosition; +use super::errors::{GenericTypeWithParentheses, UseAngleBrackets}; use super::ResolverAstLoweringExt; use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::{self as ast, *}; -use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::GenericArg; @@ -185,7 +185,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,); let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { - let msg = "parenthesized type parameters may only be used with a `Fn` trait"; match **generic_args { GenericArgs::AngleBracketed(ref data) => { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) @@ -193,10 +192,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), ParenthesizedGenericArgs::Err => { - let mut err = struct_span_err!(self.tcx.sess, data.span, E0214, "{}", msg); - err.span_label(data.span, "only `Fn` traits may use parentheses"); // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait` - if !data.inputs.is_empty() { + let sub = if !data.inputs.is_empty() { // Start of the span to the 1st character of 1st argument let open_param = data.inputs_span.shrink_to_lo().to(data .inputs @@ -212,16 +209,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .span .shrink_to_hi() .to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - &format!("use angle brackets instead",), - vec![ - (open_param, String::from("<")), - (close_param, String::from(">")), - ], - Applicability::MaybeIncorrect, - ); - } - err.emit(); + + Some(UseAngleBrackets { open_param, close_param }) + } else { + None + }; + self.tcx.sess.emit_err(GenericTypeWithParentheses { span: data.span, sub }); ( self.lower_angle_bracketed_parameter_data( &data.as_angle_bracketed_args(), diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl new file mode 100644 index 0000000000000..ac7fc37e37dd5 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -0,0 +1,5 @@ +ast_lowering_generic_type_with_parentheses = + parenthesized type parameters may only be used with a `Fn` trait + .label = only `Fn` traits may use parentheses + +ast_lowering_use_angle_brackets = use angle brackets instead diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 9e73a39980927..03e0069ebccbe 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -30,6 +30,7 @@ pub use unic_langid::{langid, LanguageIdentifier}; // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. fluent_messages! { + ast_lowering => "../locales/en-US/ast_lowering.ftl", borrowck => "../locales/en-US/borrowck.ftl", builtin_macros => "../locales/en-US/builtin_macros.ftl", const_eval => "../locales/en-US/const_eval.ftl", From e9e46c95ce60469f596b8188c439dc278dff6bc4 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Wed, 17 Aug 2022 06:07:33 -0500 Subject: [PATCH 11/24] Don't treat stashed warnings as errors --- compiler/rustc_errors/src/lib.rs | 74 ++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 395bf5aad01b6..fe2afdf5a20b8 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -625,19 +625,13 @@ impl Handler { /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { let mut inner = self.inner.borrow_mut(); - // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic - // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. - // See the PR for a discussion. - inner.stashed_diagnostics.insert((span, key), diag); + inner.stash((span, key), diag); } /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key. pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option> { - self.inner - .borrow_mut() - .stashed_diagnostics - .remove(&(span, key)) - .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) + let mut inner = self.inner.borrow_mut(); + inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) } /// Emit all stashed diagnostics. @@ -1105,13 +1099,31 @@ impl HandlerInner { /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option { + let has_errors = self.has_errors(); let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::>(); let mut reported = None; for mut diag in diags { + // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { - reported = Some(ErrorGuaranteed(())); + if matches!(diag.level, Level::Error { lint: true }) { + self.lint_err_count -= 1; + } else { + self.err_count -= 1; + } + } else { + if diag.is_force_warn() { + self.warn_count -= 1; + } else { + // Unless they're forced, don't flush stashed warnings when + // there are errors, to avoid causing warning overload. The + // stash would've been stolen already if it were important. + if has_errors { + continue; + } + } } - self.emit_diagnostic(&mut diag); + let reported_this = self.emit_diagnostic(&mut diag); + reported = reported.or(reported_this); } reported } @@ -1301,9 +1313,47 @@ impl HandlerInner { } } + fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) { + // Track the diagnostic for counts, but don't panic-if-treat-err-as-bug + // yet; that happens when we actually emit the diagnostic. + if diagnostic.is_error() { + if matches!(diagnostic.level, Level::Error { lint: true }) { + self.lint_err_count += 1; + } else { + self.err_count += 1; + } + } else { + // Warnings are only automatically flushed if they're forced. + if diagnostic.is_force_warn() { + self.warn_count += 1; + } + } + + // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic + // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. + // See the PR for a discussion. + self.stashed_diagnostics.insert(key, diagnostic); + } + + fn steal(&mut self, key: (Span, StashKey)) -> Option { + let diagnostic = self.stashed_diagnostics.remove(&key)?; + if diagnostic.is_error() { + if matches!(diagnostic.level, Level::Error { lint: true }) { + self.lint_err_count -= 1; + } else { + self.err_count -= 1; + } + } else { + if diagnostic.is_force_warn() { + self.warn_count -= 1; + } + } + Some(diagnostic) + } + #[inline] fn err_count(&self) -> usize { - self.err_count + self.stashed_diagnostics.len() + self.err_count } fn has_errors(&self) -> bool { From 767239f7403a3808e534da02ca388632eac2bc18 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Wed, 17 Aug 2022 06:52:47 -0500 Subject: [PATCH 12/24] Reenable early feature-gates as future-compat warnings --- compiler/rustc_ast_passes/src/feature_gate.rs | 58 +++++++++++-------- compiler/rustc_errors/src/lib.rs | 1 + compiler/rustc_lint_defs/src/builtin.rs | 51 ++++++++++++++++ compiler/rustc_session/src/parse.rs | 55 +++++++++++++++++- src/test/ui/macros/stringify.rs | 7 +++ .../or-patterns/or-patterns-syntactic-pass.rs | 16 ++--- .../or-patterns-syntactic-pass.stderr | 13 +++++ ...ints-before-generic-args-syntactic-pass.rs | 4 ++ ...-before-generic-args-syntactic-pass.stderr | 24 ++++++++ src/test/ui/pattern/rest-pat-syntactic.rs | 5 +- src/test/ui/pattern/rest-pat-syntactic.stderr | 24 ++++++++ 11 files changed, 224 insertions(+), 34 deletions(-) create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr create mode 100644 src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr create mode 100644 src/test/ui/pattern/rest-pat-syntactic.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 97eee56f94807..68fca08101891 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -2,10 +2,10 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd, VariantData}; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_feature::Features; use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; -use rustc_feature::{Features, GateIssue}; -use rustc_session::parse::{feature_err, feature_err_issue}; +use rustc_session::parse::{feature_err, feature_warn}; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -20,9 +20,7 @@ macro_rules! gate_feature_fn { let has_feature: bool = has_feature(visitor.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); if !has_feature && !span.allows_unstable($name) { - feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain) - .help(help) - .emit(); + feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit(); } }}; ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ @@ -31,8 +29,19 @@ macro_rules! gate_feature_fn { let has_feature: bool = has_feature(visitor.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); if !has_feature && !span.allows_unstable($name) { - feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain) - .emit(); + feature_err(&visitor.sess.parse_sess, name, span, explain).emit(); + } + }}; + (future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ + let (visitor, has_feature, span, name, explain) = + (&*$visitor, $has_feature, $span, $name, $explain); + let has_feature: bool = has_feature(visitor.features); + debug!( + "gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)", + name, span, has_feature + ); + if !has_feature && !span.allows_unstable($name) { + feature_warn(&visitor.sess.parse_sess, name, span, explain); } }}; } @@ -44,6 +53,9 @@ macro_rules! gate_feature_post { ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => { gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) }; + (future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => { + gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain) + }; } pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) { @@ -588,11 +600,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { { // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type // ascription error, but the likely intention was to write a `let` statement. (#78907). - feature_err_issue( + feature_err( &self.sess.parse_sess, sym::type_ascription, lhs.span, - GateIssue::Language, "type ascription is experimental", ).span_suggestion_verbose( lhs.span.shrink_to_lo(), @@ -615,15 +626,22 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } ast::ExprKind::Type(..) => { - // To avoid noise about type ascription in common syntax errors, only emit if it - // is the *only* error. if self.sess.parse_sess.span_diagnostic.err_count() == 0 { + // To avoid noise about type ascription in common syntax errors, + // only emit if it is the *only* error. gate_feature_post!( &self, type_ascription, e.span, "type ascription is experimental" ); + } else { + // And if it isn't, cancel the early-pass warning. + self.sess + .parse_sess + .span_diagnostic + .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning) + .map(|err| err.cancel()); } } ast::ExprKind::TryBlock(_) => { @@ -789,14 +807,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). + // We emit an early future-incompatible warning for these. + // New syntax gates should go above here to get a hard error gate. macro_rules! gate_all { ($gate:ident, $msg:literal) => { - // FIXME(eddyb) do something more useful than always - // disabling these uses of early feature-gatings. - if false { - for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_feature_post!(&visitor, $gate, *span, $msg); - } + for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { + gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg); } }; } @@ -809,11 +825,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(try_blocks, "`try` blocks are unstable"); gate_all!(label_break_value, "labels on blocks are unstable"); gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); - // To avoid noise about type ascription in common syntax errors, - // only emit if it is the *only* error. (Also check it last.) - if sess.parse_sess.span_diagnostic.err_count() == 0 { - gate_all!(type_ascription, "type ascription is experimental"); - } + gate_all!(type_ascription, "type ascription is experimental"); visit::walk_crate(&mut visitor, krate); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index fe2afdf5a20b8..43b8288d8b627 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -458,6 +458,7 @@ struct HandlerInner { pub enum StashKey { ItemNoType, UnderscoreForArrayLengths, + EarlySyntaxWarning, } fn default_track_diagnostic(_: &Diagnostic) {} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f00165cd3b370..95e34da734d6a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3212,6 +3212,56 @@ declare_lint! { }; } +declare_lint! { + /// The `unstable_syntax_pre_expansion` lint detects the use of unstable + /// syntax that is discarded during attribute expansion. + /// + /// ### Example + /// + /// ```rust + /// #[cfg(FALSE)] + /// macro foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The input to active attributes such as `#[cfg]` or procedural macro + /// attributes is required to be valid syntax. Previously, the compiler only + /// gated the use of unstable syntax features after resolving `#[cfg]` gates + /// and expanding procedural macros. + /// + /// To avoid relying on unstable syntax, move the use of unstable syntax + /// into a position where the compiler does not parse the syntax, such as a + /// functionlike macro. + /// + /// ```rust + /// # #![deny(unstable_syntax_pre_expansion)] + /// + /// macro_rules! identity { + /// ( $($tokens:tt)* ) => { $($tokens)* } + /// } + /// + /// #[cfg(FALSE)] + /// identity! { + /// macro foo() {} + /// } + /// ``` + /// + /// This is a [future-incompatible] lint to transition this + /// to a hard error in the future. See [issue #65860] for more details. + /// + /// [issue #65860]: https://github.com/rust-lang/rust/issues/65860 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub UNSTABLE_SYNTAX_PRE_EXPANSION, + Warn, + "unstable syntax can change at any point in the future, causing a hard error!", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #65860 ", + }; +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3280,6 +3330,7 @@ declare_lint_pass! { POINTER_STRUCTURAL_MATCH, NONTRIVIAL_STRUCTURAL_MATCH, SOFT_UNSTABLE, + UNSTABLE_SYNTAX_PRE_EXPANSION, INLINE_NO_SANITIZE, BAD_ASM_STYLE, ASM_SUB_REGISTER, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index f31d52147b47b..9f0886cb2089c 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -2,15 +2,17 @@ //! It also serves as an input to the parser itself. use crate::config::CheckCfg; -use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; +use crate::lint::{ + builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId, +}; use crate::SessionDiagnostic; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ - error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, - DiagnosticMessage, ErrorGuaranteed, MultiSpan, + error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, + DiagnosticMessage, ErrorGuaranteed, MultiSpan, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -101,11 +103,58 @@ pub fn feature_err_issue<'a>( issue: GateIssue, explain: &str, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() { + sess.span_diagnostic + .steal_diagnostic(span, StashKey::EarlySyntaxWarning) + .map(|err| err.cancel()); + } + let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658)); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); err } +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +pub fn feature_warn<'a>(sess: &'a ParseSess, feature: Symbol, span: Span, explain: &str) { + feature_warn_issue(sess, feature, span, GateIssue::Language, explain); +} + +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. +pub fn feature_warn_issue<'a>( + sess: &'a ParseSess, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &str, +) { + let mut err = sess.span_diagnostic.struct_span_warn(span, explain); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); + + // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level + let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; + let future_incompatible = lint.future_incompatible.as_ref().unwrap(); + err.code(DiagnosticId::Lint { + name: lint.name_lower(), + has_future_breakage: false, + is_force_warn: false, + }); + err.warn(lint.desc); + err.note(format!("for more information, see {}", future_incompatible.reference)); + + // A later feature_err call can steal and cancel this warning. + err.stash(span, StashKey::EarlySyntaxWarning); +} + /// Adds the diagnostics for a feature to an existing error. pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) { add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language); diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index 8e71ed7c1120f..082c1abb8f2f4 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -3,11 +3,18 @@ // compile-flags: --test #![feature(async_closure)] +#![feature(box_patterns)] +#![feature(box_syntax)] #![feature(const_trait_impl)] +#![feature(decl_macro)] #![feature(generators)] #![feature(half_open_range_patterns)] +#![feature(label_break_value)] #![feature(more_qualified_paths)] #![feature(raw_ref_op)] +#![feature(trait_alias)] +#![feature(try_blocks)] +#![feature(type_ascription)] #![deny(unused_macros)] macro_rules! stringify_block { diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs index 6f9a631b092a7..dda5c0bb59d23 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -7,7 +7,7 @@ fn main() {} // Test the `pat` macro fragment parser: macro_rules! accept_pat { - ($p:pat) => {} + ($p:pat) => {}; } accept_pat!((p | q)); @@ -21,28 +21,28 @@ accept_pat!([p | q]); #[cfg(FALSE)] fn or_patterns() { // Top level of `let`: - let (| A | B); + let (A | B); let (A | B); let (A | B): u8; let (A | B) = 0; let (A | B): u8 = 0; // Top level of `for`: - for | A | B in 0 {} + for A | B in 0 {} for A | B in 0 {} // Top level of `while`: - while let | A | B = 0 {} + while let A | B = 0 {} while let A | B = 0 {} // Top level of `if`: - if let | A | B = 0 {} + if let A | B = 0 {} if let A | B = 0 {} // Top level of `match` arms: match 0 { - | A | B => {}, - A | B => {}, + A | B => {} + A | B => {} } // Functions: @@ -68,6 +68,8 @@ fn or_patterns() { // These bind as `(prefix p) | q` as opposed to `prefix (p | q)`: let (box 0 | 1); // Unstable; we *can* change the precedence if we want. + //~^ WARN box pattern syntax is experimental + //~| WARN unstable syntax let (&0 | 1); let (&mut 0 | 1); let (x @ 0 | 1); diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr new file mode 100644 index 0000000000000..c43fe192a73b8 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr @@ -0,0 +1,13 @@ +warning: box pattern syntax is experimental + --> $DIR/or-patterns-syntactic-pass.rs:70:10 + | +LL | let (box 0 | 1); // Unstable; we *can* change the precedence if we want. + | ^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 1 warning emitted + diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs index afbd13e6fd9a8..d8346653c25aa 100644 --- a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs +++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs @@ -3,7 +3,11 @@ #[cfg(FALSE)] fn syntax() { foo::(); + //~^ WARN associated type bounds are unstable + //~| WARN unstable syntax foo::(); + //~^ WARN associated type bounds are unstable + //~| WARN unstable syntax } fn main() {} diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr new file mode 100644 index 0000000000000..7e843c7f4d006 --- /dev/null +++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr @@ -0,0 +1,24 @@ +warning: associated type bounds are unstable + --> $DIR/constraints-before-generic-args-syntactic-pass.rs:5:19 + | +LL | foo::(); + | ^^^^^^ + | + = note: see issue #52662 for more information + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: associated type bounds are unstable + --> $DIR/constraints-before-generic-args-syntactic-pass.rs:8:23 + | +LL | foo::(); + | ^^^^^^ + | + = note: see issue #52662 for more information + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 2 warnings emitted + diff --git a/src/test/ui/pattern/rest-pat-syntactic.rs b/src/test/ui/pattern/rest-pat-syntactic.rs index 9656a0b5de9ce..4da5a2db76743 100644 --- a/src/test/ui/pattern/rest-pat-syntactic.rs +++ b/src/test/ui/pattern/rest-pat-syntactic.rs @@ -19,6 +19,8 @@ fn rest_patterns() { // Box patterns: let box ..; + //~^ WARN box pattern syntax is experimental + //~| WARN unstable syntax // In or-patterns: match x { @@ -57,7 +59,7 @@ fn rest_patterns() { .. | [ ( - box .., + box .., //~ WARN box pattern syntax is experimental &(..), &mut .., x @ .. @@ -67,4 +69,5 @@ fn rest_patterns() { ref mut x @ .. => {} } + //~| WARN unstable syntax } diff --git a/src/test/ui/pattern/rest-pat-syntactic.stderr b/src/test/ui/pattern/rest-pat-syntactic.stderr new file mode 100644 index 0000000000000..37019b7d5ba7a --- /dev/null +++ b/src/test/ui/pattern/rest-pat-syntactic.stderr @@ -0,0 +1,24 @@ +warning: box pattern syntax is experimental + --> $DIR/rest-pat-syntactic.rs:21:9 + | +LL | let box ..; + | ^^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: box pattern syntax is experimental + --> $DIR/rest-pat-syntactic.rs:62:17 + | +LL | box .., + | ^^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 2 warnings emitted + From 944c6b6d760d392552fc60ec4e3ba3ad84598350 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Wed, 17 Aug 2022 06:59:46 -0500 Subject: [PATCH 13/24] New ui tests for new soft feature gates --- .../soft-syntax-gates-with-errors.rs | 30 +++++++++++++++++++ .../soft-syntax-gates-with-errors.stderr | 21 +++++++++++++ .../soft-syntax-gates-without-errors.rs | 26 ++++++++++++++++ .../soft-syntax-gates-without-errors.stderr | 24 +++++++++++++++ .../ui/suggestions/many-type-ascription.rs | 4 +++ .../suggestions/many-type-ascription.stderr | 12 ++++++++ .../type-ascription-and-other-error.rs | 6 ++++ .../type-ascription-and-other-error.stderr | 8 +++++ 8 files changed, 131 insertions(+) create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr create mode 100644 src/test/ui/suggestions/many-type-ascription.rs create mode 100644 src/test/ui/suggestions/many-type-ascription.stderr create mode 100644 src/test/ui/suggestions/type-ascription-and-other-error.rs create mode 100644 src/test/ui/suggestions/type-ascription-and-other-error.stderr diff --git a/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs new file mode 100644 index 0000000000000..49f1cba7151ef --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs @@ -0,0 +1,30 @@ +// check-fail +// This file is used to test the behavior of the early-pass syntax warnings. +// If macro syntax is stabilized, replace with a different unstable syntax. + +macro a() {} +//~^ ERROR: `macro` is experimental + +#[cfg(FALSE)] +macro b() {} + +macro_rules! identity { + ($($x:tt)*) => ($($x)*); +} + +identity! { + macro c() {} + //~^ ERROR: `macro` is experimental +} + +#[cfg(FALSE)] +identity! { + macro d() {} // No error +} + +identity! { + #[cfg(FALSE)] + macro e() {} +} + +fn main() {} diff --git a/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr new file mode 100644 index 0000000000000..49550d811ba52 --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr @@ -0,0 +1,21 @@ +error[E0658]: `macro` is experimental + --> $DIR/soft-syntax-gates-with-errors.rs:5:1 + | +LL | macro a() {} + | ^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + +error[E0658]: `macro` is experimental + --> $DIR/soft-syntax-gates-with-errors.rs:16:5 + | +LL | macro c() {} + | ^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs new file mode 100644 index 0000000000000..ca4ad2320f657 --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs @@ -0,0 +1,26 @@ +// check-pass +// This file is used to test the behavior of the early-pass syntax warnings. +// If macro syntax is stabilized, replace with a different unstable syntax. + +#[cfg(FALSE)] +macro b() {} +//~^ WARN: `macro` is experimental +//~| WARN: unstable syntax + +macro_rules! identity { + ($($x:tt)*) => ($($x)*); +} + +#[cfg(FALSE)] +identity! { + macro d() {} // No error +} + +identity! { + #[cfg(FALSE)] + macro e() {} + //~^ WARN: `macro` is experimental + //~| WARN: unstable syntax +} + +fn main() {} diff --git a/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr new file mode 100644 index 0000000000000..3d9c22e548710 --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr @@ -0,0 +1,24 @@ +warning: `macro` is experimental + --> $DIR/soft-syntax-gates-without-errors.rs:6:1 + | +LL | macro b() {} + | ^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: `macro` is experimental + --> $DIR/soft-syntax-gates-without-errors.rs:21:5 + | +LL | macro e() {} + | ^^^^^^^^^^^^ + | + = note: see issue #39412 for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + +warning: 2 warnings emitted + diff --git a/src/test/ui/suggestions/many-type-ascription.rs b/src/test/ui/suggestions/many-type-ascription.rs new file mode 100644 index 0000000000000..31ac556b9447c --- /dev/null +++ b/src/test/ui/suggestions/many-type-ascription.rs @@ -0,0 +1,4 @@ +fn main() { + let _ = 0: i32; //~ ERROR: type ascription is experimental + let _ = 0: i32; // (error only emitted once) +} diff --git a/src/test/ui/suggestions/many-type-ascription.stderr b/src/test/ui/suggestions/many-type-ascription.stderr new file mode 100644 index 0000000000000..3706bbae9df9f --- /dev/null +++ b/src/test/ui/suggestions/many-type-ascription.stderr @@ -0,0 +1,12 @@ +error[E0658]: type ascription is experimental + --> $DIR/many-type-ascription.rs:2:13 + | +LL | let _ = 0: i32; + | ^^^^^^ + | + = note: see issue #23416 for more information + = help: add `#![feature(type_ascription)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/suggestions/type-ascription-and-other-error.rs b/src/test/ui/suggestions/type-ascription-and-other-error.rs new file mode 100644 index 0000000000000..99ab2f3c858b9 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-and-other-error.rs @@ -0,0 +1,6 @@ +fn main() { + not rust; //~ ERROR + let _ = 0: i32; // (error hidden by existing error) + #[cfg(FALSE)] + let _ = 0: i32; // (warning hidden by existing error) +} diff --git a/src/test/ui/suggestions/type-ascription-and-other-error.stderr b/src/test/ui/suggestions/type-ascription-and-other-error.stderr new file mode 100644 index 0000000000000..eadf634bb14fd --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-and-other-error.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `rust` + --> $DIR/type-ascription-and-other-error.rs:2:9 + | +LL | not rust; + | ^^^^ expected one of 8 possible tokens + +error: aborting due to previous error + From 0d4f665cc27b70b65952b9168556f7d12ce7e06f Mon Sep 17 00:00:00 2001 From: Jean CASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:58:57 +0200 Subject: [PATCH 14/24] Migrate ast_lowering::lib and ast_lowering::item to SessionDiagnostic --- compiler/rustc_ast_lowering/src/errors.rs | 53 ++++++++++++++++++- compiler/rustc_ast_lowering/src/item.rs | 11 ++-- compiler/rustc_ast_lowering/src/lib.rs | 38 +++++-------- .../locales/en-US/ast_lowering.ftl | 13 +++++ 4 files changed, 83 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 8701491c9eb3d..c6337ce161d6f 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; use rustc_macros::SessionDiagnostic; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; #[derive(SessionDiagnostic, Clone, Copy)] #[error(ast_lowering::generic_type_with_parentheses, code = "E0214")] @@ -27,3 +27,54 @@ impl AddSubdiagnostic for UseAngleBrackets { ); } } + +#[derive(SessionDiagnostic)] +#[help] +#[error(ast_lowering::invalid_abi, code = "E0703")] +pub struct InvalidAbi { + #[primary_span] + #[label] + pub span: Span, + pub abi: Symbol, + pub valid_abis: String, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::assoc_ty_parentheses)] +pub struct AssocTyParentheses { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: AssocTyParenthesesSub, +} + +#[derive(Clone, Copy)] +pub enum AssocTyParenthesesSub { + Empty { parentheses_span: Span }, + NotEmpty { open_param: Span, close_param: Span }, +} + +impl AddSubdiagnostic for AssocTyParenthesesSub { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + match self { + Self::Empty { parentheses_span } => diag.multipart_suggestion( + fluent::ast_lowering::remove_parentheses, + vec![(parentheses_span, String::new())], + Applicability::MaybeIncorrect, + ), + Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion( + fluent::ast_lowering::use_angle_brackets, + vec![(open_param, String::from("<")), (close_param, String::from(">"))], + Applicability::MaybeIncorrect, + ), + }; + } +} + +#[derive(SessionDiagnostic)] +#[error(ast_lowering::misplaced_impl_trait, code = "E0562")] +pub struct MisplacedImplTrait { + #[primary_span] + pub span: Span, + pub position: String, +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ee4c0036f7698..9e3b05801f316 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,3 +1,4 @@ +use super::errors::InvalidAbi; use super::ResolverAstLoweringExt; use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; @@ -7,7 +8,6 @@ use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -1260,10 +1260,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn error_on_invalid_abi(&self, abi: StrLit) { - struct_span_err!(self.tcx.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol) - .span_label(abi.span, "invalid ABI") - .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) - .emit(); + self.tcx.sess.emit_err(InvalidAbi { + span: abi.span, + abi: abi.symbol, + valid_abis: abi::all_names().join(", "), + }); } fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 958885ea4c532..6e2f38b7e7156 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -39,6 +39,8 @@ #[macro_use] extern crate tracing; +use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; + use rustc_ast::ptr::P; use rustc_ast::visit; use rustc_ast::{self as ast, *}; @@ -49,7 +51,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability, Handler, StashKey}; +use rustc_errors::{Handler, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -1071,19 +1073,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) { - let mut err = self.tcx.sess.struct_span_err( - data.span, - "parenthesized generic arguments cannot be used in associated type constraints", - ); // Suggest removing empty parentheses: "Trait()" -> "Trait" - if data.inputs.is_empty() { + let sub = if data.inputs.is_empty() { let parentheses_span = data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - "remove these parentheses", - vec![(parentheses_span, String::new())], - Applicability::MaybeIncorrect, - ); + AssocTyParenthesesSub::Empty { parentheses_span } } // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait` else { @@ -1097,13 +1091,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // End of last argument to end of parameters let close_param = data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi()); - err.multipart_suggestion( - &format!("use angle brackets instead",), - vec![(open_param, String::from("<")), (close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ); - } - err.emit(); + AssocTyParenthesesSub::NotEmpty { open_param, close_param } + }; + self.tcx.sess.emit_err(AssocTyParentheses { span: data.span, sub }); } #[instrument(level = "debug", skip(self))] @@ -1342,14 +1332,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path } ImplTraitContext::Disallowed(position) => { - let mut err = struct_span_err!( - self.tcx.sess, - t.span, - E0562, - "`impl Trait` only allowed in function and inherent method return types, not in {}", - position - ); - err.emit(); + self.tcx.sess.emit_err(MisplacedImplTrait { + span: t.span, + position: position.to_string(), + }); hir::TyKind::Err } } diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl index ac7fc37e37dd5..3856dd1050bec 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -3,3 +3,16 @@ ast_lowering_generic_type_with_parentheses = .label = only `Fn` traits may use parentheses ast_lowering_use_angle_brackets = use angle brackets instead + +ast_lowering_invalid_abi = + invalid ABI: found `{$abi}` + .label = invalid ABI + .help = valid ABIs: {$valid_abis} + +ast_lowering_assoc_ty_parentheses = + parenthesized generic arguments cannot be used in associated type constraints + +ast_lowering_remove_parentheses = remove these parentheses + +ast_lowering_misplaced_impl_trait = + `impl Trait` only allowed in function and inherent method return types, not in {$position} From 41effad4ae510c6b874eae050f7b484360a38959 Mon Sep 17 00:00:00 2001 From: Jean CASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Wed, 17 Aug 2022 19:48:25 +0200 Subject: [PATCH 15/24] Migrate ast_lowering::expr to SessionDiagnostic --- compiler/rustc_ast_lowering/src/errors.rs | 70 ++++++++++++++ compiler/rustc_ast_lowering/src/expr.rs | 94 ++++--------------- .../locales/en-US/ast_lowering.ftl | 33 +++++++ 3 files changed, 121 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index c6337ce161d6f..3eeef0add94e6 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -78,3 +78,73 @@ pub struct MisplacedImplTrait { pub span: Span, pub position: String, } + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::rustc_box_attribute_error)] +pub struct RustcBoxAttributeError { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::underscore_expr_lhs_assign)] +pub struct UnderscoreExprLhsAssign { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::base_expression_double_dot)] +pub struct BaseExpressionDoubleDot { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")] +pub struct AwaitOnlyInAsyncFnAndBlocks { + #[primary_span] + #[label] + pub dot_await_span: Span, + #[label(ast_lowering::this_not_async)] + pub item_span: Option, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::generator_too_many_parameters, code = "E0628")] +pub struct GeneratorTooManyParameters { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::closure_cannot_be_static, code = "E0697")] +pub struct ClosureCannotBeStatic { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[help] +#[error(ast_lowering::async_non_move_closure_not_supported, code = "E0708")] +pub struct AsyncNonMoveClosureNotSupported { + #[primary_span] + pub fn_decl_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::functional_record_update_destructuring_assignment)] +pub struct FunctionalRecordUpdateDestructuringAssignemnt { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::async_generators_not_supported, code = "E0727")] +pub struct AsyncGeneratorsNotSupported { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 32dbd2ff47d6b..011b8fc973ecb 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,3 +1,8 @@ +use super::errors::{ + AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, + BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, + GeneratorTooManyParameters, RustcBoxAttributeError, UnderscoreExprLhsAssign, +}; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use crate::{FnDeclKind, ImplTraitPosition}; @@ -7,7 +12,6 @@ use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::definitions::DefPathData; @@ -46,13 +50,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(e.id); return hir::Expr { hir_id, kind, span: self.lower_span(e.span) }; } else { - self.tcx.sess - .struct_span_err( - e.span, - "#[rustc_box] requires precisely one argument \ - and no other attributes are allowed", - ) - .emit(); + self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span }); hir::ExprKind::Err } } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { @@ -212,13 +210,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) } ExprKind::Underscore => { - self.tcx - .sess.struct_span_err( - e.span, - "in expressions, `_` can only be used on the left-hand side of an assignment", - ) - .span_label(e.span, "`_` not allowed here") - .emit(); + self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span }); hir::ExprKind::Err } ExprKind::Path(ref qself, ref path) => { @@ -250,11 +242,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let rest = match &se.rest { StructRest::Base(e) => Some(self.lower_expr(e)), StructRest::Rest(sp) => { - self.tcx - .sess - .struct_span_err(*sp, "base expression required after `..`") - .span_label(*sp, "add a base expression here") - .emit(); + self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp }); Some(&*self.arena.alloc(self.expr_err(*sp))) } StructRest::None => None, @@ -663,17 +651,10 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.generator_kind { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { - let mut err = struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { dot_await_span, - E0728, - "`await` is only allowed inside `async` functions and blocks" - ); - err.span_label(dot_await_span, "only allowed inside `async` functions and blocks"); - if let Some(item_sp) = self.current_item { - err.span_label(item_sp, "this is not `async`"); - } - err.emit(); + item_span: self.current_item, + }); } } let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None); @@ -893,13 +874,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match generator_kind { Some(hir::GeneratorKind::Gen) => { if decl.inputs.len() > 1 { - struct_span_err!( - self.tcx.sess, - fn_decl_span, - E0628, - "too many parameters for a generator (expected 0 or 1 parameters)" - ) - .emit(); + self.tcx.sess.emit_err(GeneratorTooManyParameters { fn_decl_span }); } Some(movability) } @@ -908,13 +883,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } None => { if movability == Movability::Static { - struct_span_err!( - self.tcx.sess, - fn_decl_span, - E0697, - "closures cannot be static" - ) - .emit(); + self.tcx.sess.emit_err(ClosureCannotBeStatic { fn_decl_span }); } None } @@ -961,17 +930,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let body = self.with_new_scopes(|this| { // FIXME(cramertj): allow `async` non-`move` closures with arguments. if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { - struct_span_err!( - this.tcx.sess, - fn_decl_span, - E0708, - "`async` non-`move` closures with parameters are not currently supported", - ) - .help( - "consider using `let` statements to manually capture \ - variables by reference before entering an `async move` closure", - ) - .emit(); + this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span }); } // Transform `async |x: u8| -> X { ... }` into @@ -1211,20 +1170,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let fields_omitted = match &se.rest { StructRest::Base(e) => { - self.tcx - .sess - .struct_span_err( - e.span, - "functional record updates are not allowed in destructuring \ - assignments", - ) - .span_suggestion( - e.span, - "consider removing the trailing pattern", - "", - rustc_errors::Applicability::MachineApplicable, - ) - .emit(); + self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignemnt { + span: e.span, + }); true } StructRest::Rest(_) => true, @@ -1421,13 +1369,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.generator_kind { Some(hir::GeneratorKind::Gen) => {} Some(hir::GeneratorKind::Async(_)) => { - struct_span_err!( - self.tcx.sess, - span, - E0727, - "`async` generators are not yet supported" - ) - .emit(); + self.tcx.sess.emit_err(AsyncGeneratorsNotSupported { span }); } None => self.generator_kind = Some(hir::GeneratorKind::Gen), } diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl index 3856dd1050bec..47f2305b9136e 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -16,3 +16,36 @@ ast_lowering_remove_parentheses = remove these parentheses ast_lowering_misplaced_impl_trait = `impl Trait` only allowed in function and inherent method return types, not in {$position} + +ast_lowering_rustc_box_attribute_error = + #[rustc_box] requires precisely one argument and no other attributes are allowed + +ast_lowering_underscore_expr_lhs_assign = + in expressions, `_` can only be used on the left-hand side of an assignment + .label = `_` not allowed here + +ast_lowering_base_expression_double_dot = + base expression required after `..` + .label = add a base expression here + +ast_lowering_await_only_in_async_fn_and_blocks = + `await` is only allowed inside `async` functions and blocks + .label = only allowed inside `async` functions and blocks + +ast_lowering_this_not_async = this is not `async` + +ast_lowering_generator_too_many_parameters = + too many parameters for a generator (expected 0 or 1 parameters) + +ast_lowering_closure_cannot_be_static = closures cannot be static + +ast_lowering_async_non_move_closure_not_supported = + `async` non-`move` closures with parameters are not currently supported + .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure + +ast_lowering_functional_record_update_destructuring_assignment = + functional record updates are not allowed in destructuring assignments + .suggestion = consider removing the trailing pattern + +ast_lowering_async_generators_not_supported = + `async` generators are not yet supported From 64bd8c1dc427c8bcd69bed7c240b1f1f38bedbd3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 17 Aug 2022 19:02:55 +0000 Subject: [PATCH 16/24] Make same_type_modulo_infer a proper TypeRelation --- .../src/infer/error_reporting/mod.rs | 132 +++++++++++------- compiler/rustc_middle/src/ty/sty.rs | 4 + src/test/ui/implied-bounds/issue-100690.rs | 45 ++++++ .../ui/implied-bounds/issue-100690.stderr | 22 +++ 4 files changed, 150 insertions(+), 53 deletions(-) create mode 100644 src/test/ui/implied-bounds/issue-100690.rs create mode 100644 src/test/ui/implied-bounds/issue-100690.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 3c7dac2bfd816..d55708acc9a9b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -66,6 +66,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::Node; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::{ self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, @@ -2660,67 +2661,92 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Float types, respectively). When comparing two ADTs, these rules apply recursively. pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); - match (a.kind(), b.kind()) { - (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => { - if def_a != def_b { - return false; - } + SameTypeModuloInfer(self).relate(a, b).is_ok() + } +} - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => { - if did_a != did_b { - return false; - } +struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>); - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_))) +impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.0.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + // Unused, only for consts which we treat as always equal + ty::ParamEnv::empty() + } + + fn tag(&self) -> &'static str { + "SameTypeModuloInfer" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + _variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> relate::RelateResult<'tcx, T> { + self.relate(a, b) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + match (a.kind(), b.kind()) { + (ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_))) | ( - &ty::Infer(ty::InferTy::IntVar(_)), - &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)), + ty::Infer(ty::InferTy::IntVar(_)), + ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)), ) - | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) + | (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_))) | ( - &ty::Infer(ty::InferTy::FloatVar(_)), - &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), + ty::Infer(ty::InferTy::FloatVar(_)), + ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)), ) - | (&ty::Infer(ty::InferTy::TyVar(_)), _) - | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, - (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { - mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b) - } - (&ty::RawPtr(a), &ty::RawPtr(b)) => { - a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty) - } - (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b), - (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => { - self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct - } - (&ty::Tuple(a), &ty::Tuple(b)) => { - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnPtr(a), &ty::FnPtr(b)) => { - let a = a.skip_binder().inputs_and_output; - let b = b.skip_binder().inputs_and_output; - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - // FIXME(compiler-errors): This needs to be generalized more - _ => a == b, + | (ty::Infer(ty::InferTy::TyVar(_)), _) + | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), + (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), + _ => relate::super_relate_tys(self, a, b), } } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + if (a.is_var() && b.is_free_or_static()) || (b.is_var() && a.is_free_or_static()) || a == b + { + Ok(a) + } else { + Err(TypeError::Mismatch) + } + } + + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: relate::Relate<'tcx>, + { + Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) + } + + fn consts( + &mut self, + a: ty::Const<'tcx>, + _b: ty::Const<'tcx>, + ) -> relate::RelateResult<'tcx, ty::Const<'tcx>> { + // FIXME(compiler-errors): This could at least do some first-order + // relation + Ok(a) + } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 52c3a38861e65..0070575f2136a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1617,6 +1617,10 @@ impl<'tcx> Region<'tcx> { _ => self.is_free(), } } + + pub fn is_var(self) -> bool { + matches!(self.kind(), ty::ReVar(_)) + } } /// Type utilities diff --git a/src/test/ui/implied-bounds/issue-100690.rs b/src/test/ui/implied-bounds/issue-100690.rs new file mode 100644 index 0000000000000..5599cd410baad --- /dev/null +++ b/src/test/ui/implied-bounds/issue-100690.rs @@ -0,0 +1,45 @@ +// This code (probably) _should_ compile, but it currently does not because we +// are not smart enough about implied bounds. + +use std::io; + +fn real_dispatch(f: F) -> Result<(), io::Error> +//~^ NOTE required by a bound in this +where + F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, + //~^ NOTE required by this bound in `real_dispatch` + //~| NOTE required by a bound in `real_dispatch` +{ + todo!() +} + +#[derive(Debug)] +struct UIView<'a, T: 'a> { + _phantom: std::marker::PhantomData<&'a mut T>, +} + +trait Handle<'a, T: 'a, V, R> { + fn dispatch(&self, f: F) -> Result<(), io::Error> + where + F: FnOnce(&mut V) -> R + Send + 'static; +} + +#[derive(Debug, Clone)] +struct TUIHandle { + _phantom: std::marker::PhantomData, +} + +impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle { + fn dispatch(&self, f: F) -> Result<(), io::Error> + where + F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static, + { + real_dispatch(f) + //~^ ERROR expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` + //~| NOTE expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` + //~| NOTE expected a closure with arguments + //~| NOTE required by a bound introduced by this call + } +} + +fn main() {} diff --git a/src/test/ui/implied-bounds/issue-100690.stderr b/src/test/ui/implied-bounds/issue-100690.stderr new file mode 100644 index 0000000000000..3f6af70d8ed93 --- /dev/null +++ b/src/test/ui/implied-bounds/issue-100690.stderr @@ -0,0 +1,22 @@ +error[E0277]: expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` + --> $DIR/issue-100690.rs:37:23 + | +LL | real_dispatch(f) + | ------------- ^ expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` + | | + | required by a bound introduced by this call + | + = note: expected a closure with arguments `(&mut UIView<'a, T>,)` + found a closure with arguments `(&mut UIView<'_, T>,)` +note: required by a bound in `real_dispatch` + --> $DIR/issue-100690.rs:9:8 + | +LL | fn real_dispatch(f: F) -> Result<(), io::Error> + | ------------- required by a bound in this +... +LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 11d9f34343a3da36504ffa00f7f26e3e884fca19 Mon Sep 17 00:00:00 2001 From: Jean CASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Wed, 17 Aug 2022 23:00:33 +0200 Subject: [PATCH 17/24] Migrate ast_lowering::ast to SessionDiagnostic --- compiler/rustc_ast_lowering/src/asm.rs | 161 +++++++----------- compiler/rustc_ast_lowering/src/errors.rs | 124 +++++++++++++- .../locales/en-US/ast_lowering.ftl | 54 ++++++ 3 files changed, 239 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 4166b4fc2e5bc..d246510e0c1ed 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,11 +1,17 @@ use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt}; +use super::errors::{ + AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported, + InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, + InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub, + InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber, + RegisterConflict, +}; use super::LoweringContext; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::definitions::DefPathData; @@ -26,13 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let asm_arch = if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch }; if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc { - struct_span_err!( - self.tcx.sess, - sp, - E0472, - "inline assembly is unsupported on this target" - ) - .emit(); + self.tcx.sess.emit_err(InlineAsmUnsupportedTarget { span: sp }); } if let Some(asm_arch) = asm_arch { // Inline assembly is currently only stable for these architectures. @@ -59,10 +59,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)) && !self.tcx.sess.opts.actually_rustdoc { - self.tcx - .sess - .struct_span_err(sp, "the `att_syntax` option is only supported on x86") - .emit(); + self.tcx.sess.emit_err(AttSyntaxOnlyX86 { span: sp }); } if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { feature_err( @@ -82,51 +79,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If the abi was already in the list, emit an error match clobber_abis.get(&abi) { Some((prev_name, prev_sp)) => { - let mut err = self.tcx.sess.struct_span_err( - *abi_span, - &format!("`{}` ABI specified multiple times", prev_name), - ); - err.span_label(*prev_sp, "previously specified here"); - // Multiple different abi names may actually be the same ABI // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI let source_map = self.tcx.sess.source_map(); - if source_map.span_to_snippet(*prev_sp) - != source_map.span_to_snippet(*abi_span) - { - err.note("these ABIs are equivalent on the current target"); - } + let equivalent = (source_map.span_to_snippet(*prev_sp) + != source_map.span_to_snippet(*abi_span)) + .then_some(()); - err.emit(); + self.tcx.sess.emit_err(AbiSpecifiedMultipleTimes { + abi_span: *abi_span, + prev_name: *prev_name, + prev_span: *prev_sp, + equivalent, + }); } None => { - clobber_abis.insert(abi, (abi_name, *abi_span)); + clobber_abis.insert(abi, (*abi_name, *abi_span)); } } } Err(&[]) => { - self.tcx - .sess - .struct_span_err( - *abi_span, - "`clobber_abi` is not supported on this target", - ) - .emit(); + self.tcx.sess.emit_err(ClobberAbiNotSupported { abi_span: *abi_span }); } Err(supported_abis) => { - let mut err = self - .tcx - .sess - .struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); let mut abis = format!("`{}`", supported_abis[0]); for m in &supported_abis[1..] { let _ = write!(abis, ", `{}`", m); } - err.note(&format!( - "the following ABIs are supported on this target: {}", - abis - )); - err.emit(); + self.tcx.sess.emit_err(InvalidAbiClobberAbi { + abi_span: *abi_span, + supported_abis: abis, + }); } } } @@ -144,8 +127,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::Reg(s) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register `{}`: {}", s, e); - sess.struct_span_err(*op_sp, &msg).emit(); + sess.emit_err(InvalidRegister { op_span: *op_sp, s, e }); asm::InlineAsmReg::Err }) } else { @@ -155,8 +137,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::RegClass(s) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register class `{}`: {}", s, e); - sess.struct_span_err(*op_sp, &msg).emit(); + sess.emit_err(InvalidRegisterClass { op_span: *op_sp, s, e }); asm::InlineAsmRegClass::Err }) } else { @@ -282,50 +263,39 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let valid_modifiers = class.valid_modifiers(asm_arch.unwrap()); if !valid_modifiers.contains(&modifier) { - let mut err = sess.struct_span_err( - placeholder_span, - "invalid asm template modifier for this register class", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - if !valid_modifiers.is_empty() { + let sub = if !valid_modifiers.is_empty() { let mut mods = format!("`{}`", valid_modifiers[0]); for m in &valid_modifiers[1..] { let _ = write!(mods, ", `{}`", m); } - err.note(&format!( - "the `{}` register class supports \ - the following template modifiers: {}", - class.name(), - mods - )); + InvalidAsmTemplateModifierRegClassSub::SupportModifier { + class_name: class.name(), + modifiers: mods, + } } else { - err.note(&format!( - "the `{}` register class does not support template modifiers", - class.name() - )); - } - err.emit(); + InvalidAsmTemplateModifierRegClassSub::DoesNotSupportModifier { + class_name: class.name(), + } + }; + sess.emit_err(InvalidAsmTemplateModifierRegClass { + placeholder_span, + op_span: op_sp, + sub, + }); } } hir::InlineAsmOperand::Const { .. } => { - let mut err = sess.struct_span_err( + sess.emit_err(InvalidAsmTemplateModifierConst { placeholder_span, - "asm template modifiers are not allowed for `const` arguments", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - err.emit(); + op_span: op_sp, + }); } hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } => { - let mut err = sess.struct_span_err( + sess.emit_err(InvalidAsmTemplateModifierSym { placeholder_span, - "asm template modifiers are not allowed for `sym` arguments", - ); - err.span_label(placeholder_span, "template modifier"); - err.span_label(op_sp, "argument"); - err.emit(); + op_span: op_sp, + }); } } } @@ -346,12 +316,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // require that the operand name an explicit register, not a // register class. if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() { - let msg = format!( - "register class `{}` can only be used as a clobber, \ - not as an input or output", - reg_class.name() - ); - sess.struct_span_err(op_sp, &msg).emit(); + sess.emit_err(RegisterClassOnlyClobber { + op_span: op_sp, + reg_class_name: reg_class.name(), + }); continue; } @@ -391,16 +359,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { unreachable!(); }; - let msg = format!( - "register `{}` conflicts with register `{}`", - reg.name(), - reg2.name() - ); - let mut err = sess.struct_span_err(op_sp, &msg); - err.span_label(op_sp, &format!("register `{}`", reg.name())); - err.span_label(op_sp2, &format!("register `{}`", reg2.name())); - - match (op, op2) { + let in_out = match (op, op2) { ( hir::InlineAsmOperand::In { .. }, hir::InlineAsmOperand::Out { late, .. }, @@ -411,14 +370,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) => { assert!(!*late); let out_op_sp = if input { op_sp2 } else { op_sp }; - let msg = "use `lateout` instead of \ - `out` to avoid conflict"; - err.span_help(out_op_sp, msg); - } - _ => {} - } + Some(out_op_sp) + }, + _ => None, + }; - err.emit(); + sess.emit_err(RegisterConflict { + op_span1: op_sp, + op_span2: op_sp2, + reg1_name: reg.name(), + reg2_name: reg2.name(), + in_out + }); } Entry::Vacant(v) => { if r == reg { diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 3eeef0add94e6..36a9bf6e68ff3 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; -use rustc_macros::SessionDiagnostic; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::{Span, Symbol}; #[derive(SessionDiagnostic, Clone, Copy)] @@ -148,3 +148,125 @@ pub struct AsyncGeneratorsNotSupported { #[primary_span] pub span: Span, } + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::inline_asm_unsupported_target, code = "E0472")] +pub struct InlineAsmUnsupportedTarget { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::att_syntax_only_x86)] +pub struct AttSyntaxOnlyX86 { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::abi_specified_multiple_times)] +pub struct AbiSpecifiedMultipleTimes { + #[primary_span] + pub abi_span: Span, + pub prev_name: Symbol, + #[label] + pub prev_span: Span, + #[note] + pub equivalent: Option<()>, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::clobber_abi_not_supported)] +pub struct ClobberAbiNotSupported { + #[primary_span] + pub abi_span: Span, +} + +#[derive(SessionDiagnostic)] +#[note] +#[error(ast_lowering::invalid_abi_clobber_abi)] +pub struct InvalidAbiClobberAbi { + #[primary_span] + pub abi_span: Span, + pub supported_abis: String, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::invalid_register)] +pub struct InvalidRegister<'a> { + #[primary_span] + pub op_span: Span, + pub s: Symbol, + pub e: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::invalid_register_class)] +pub struct InvalidRegisterClass<'a> { + #[primary_span] + pub op_span: Span, + pub s: Symbol, + pub e: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(ast_lowering::invalid_asm_template_modifier_reg_class)] +pub struct InvalidAsmTemplateModifierRegClass { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, + #[subdiagnostic] + pub sub: InvalidAsmTemplateModifierRegClassSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidAsmTemplateModifierRegClassSub { + #[note(ast_lowering::support_modifiers)] + SupportModifier { class_name: Symbol, modifiers: String }, + #[note(ast_lowering::does_not_support_modifiers)] + DoesNotSupportModifier { class_name: Symbol }, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::invalid_asm_template_modifier_const)] +pub struct InvalidAsmTemplateModifierConst { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::invalid_asm_template_modifier_sym)] +pub struct InvalidAsmTemplateModifierSym { + #[primary_span] + #[label(ast_lowering::template_modifier)] + pub placeholder_span: Span, + #[label(ast_lowering::argument)] + pub op_span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::register_class_only_clobber)] +pub struct RegisterClassOnlyClobber { + #[primary_span] + pub op_span: Span, + pub reg_class_name: Symbol, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::register_conflict)] +pub struct RegisterConflict<'a> { + #[primary_span] + #[label(ast_lowering::register1)] + pub op_span1: Span, + #[label(ast_lowering::register2)] + pub op_span2: Span, + pub reg1_name: &'a str, + pub reg2_name: &'a str, + #[help] + pub in_out: Option, +} diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl index 47f2305b9136e..592e303b53fdd 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -49,3 +49,57 @@ ast_lowering_functional_record_update_destructuring_assignment = ast_lowering_async_generators_not_supported = `async` generators are not yet supported + +ast_lowering_inline_asm_unsupported_target = + inline assembly is unsupported on this target + +ast_lowering_att_syntax_only_x86 = + the `att_syntax` option is only supported on x86 + +ast_lowering_abi_specified_multiple_times = + `{$prev_name}` ABI specified multiple times + .label = previously specified here + .note = these ABIs are equivalent on the current target + +ast_lowering_clobber_abi_not_supported = + `clobber_abi` is not supported on this target + +ast_lowering_invalid_abi_clobber_abi = + invalid ABI for `clobber_abi` + .note = the following ABIs are supported on this target: {$supported_abis} + +ast_lowering_invalid_register = + invalid register `{$s}`: {$e} + +ast_lowering_invalid_register_class = + invalid register class `{$s}`: {$e} + +ast_lowering_invalid_asm_template_modifier_reg_class = + invalid asm template modifier for this register class + +ast_lowering_argument = argument + +ast_lowering_template_modifier = template modifier + +ast_lowering_support_modifiers = + the `{$class_name}` register class supports the following template modifiers: {$modifiers} + +ast_lowering_does_not_support_modifiers = + the `{$class_name}` register class does not support template modifiers + +ast_lowering_invalid_asm_template_modifier_const = + asm template modifiers are not allowed for `const` arguments + +ast_lowering_invalid_asm_template_modifier_sym = + asm template modifiers are not allowed for `sym` arguments + +ast_lowering_register_class_only_clobber = + register class `{$reg_class_name}` can only be used as a clobber, not as an input or output + +ast_lowering_register_conflict = + register `{$reg1_name}` conflicts with register `{$reg2_name}` + .help = use `lateout` instead of `out` to avoid conflict + +ast_lowering_register1 = register `{$reg1_name}` + +ast_lowering_register2 = register `{$reg2_name}` From 7bcfe470a85fe3751d3d3c9c8027b69fc58ac4e0 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Wed, 17 Aug 2022 21:06:55 +0000 Subject: [PATCH 18/24] unify error module docs --- library/core/src/error.md | 137 +++++++++++++++++++++++++++++++++++++ library/core/src/error.rs | 3 +- library/std/src/error.rs | 139 +------------------------------------- 3 files changed, 139 insertions(+), 140 deletions(-) create mode 100644 library/core/src/error.md diff --git a/library/core/src/error.md b/library/core/src/error.md new file mode 100644 index 0000000000000..f0a224c2a5c38 --- /dev/null +++ b/library/core/src/error.md @@ -0,0 +1,137 @@ +Interfaces for working with Errors. + +# Error Handling In Rust + +The Rust language provides two complementary systems for constructing / +representing, reporting, propagating, reacting to, and discarding errors. +These responsibilities are collectively known as "error handling." The +components of the first system, the panic runtime and interfaces, are most +commonly used to represent bugs that have been detected in your program. The +components of the second system, `Result`, the error traits, and user +defined types, are used to represent anticipated runtime failure modes of +your program. + +## The Panic Interfaces + +The following are the primary interfaces of the panic system and the +responsibilities they cover: + +* [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) +* [`PanicInfo`] (Reporting) +* [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) +* [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) + +The following are the primary interfaces of the error system and the +responsibilities they cover: + +* [`Result`] (Propagating, Reacting) +* The [`Error`] trait (Reporting) +* User defined types (Constructing / Representing) +* [`match`] and [`downcast`] (Reacting) +* The question mark operator ([`?`]) (Propagating) +* The partially stable [`Try`] traits (Propagating, Constructing) +* [`Termination`] (Reporting) + +## Converting Errors into Panics + +The panic and error systems are not entirely distinct. Often times errors +that are anticipated runtime failures in an API might instead represent bugs +to a caller. For these situations the standard library provides APIs for +constructing panics with an `Error` as it's source. + +* [`Result::unwrap`] +* [`Result::expect`] + +These functions are equivalent, they either return the inner value if the +`Result` is `Ok` or panic if the `Result` is `Err` printing the inner error +as the source. The only difference between them is that with `expect` you +provide a panic error message to be printed alongside the source, whereas +`unwrap` has a default message indicating only that you unwraped an `Err`. + +Of the two, `expect` is generally preferred since its `msg` field allows you +to convey your intent and assumptions which makes tracking down the source +of a panic easier. `unwrap` on the other hand can still be a good fit in +situations where you can trivially show that a piece of code will never +panic, such as `"127.0.0.1".parse::().unwrap()` or early +prototyping. + +# Common Message Styles + +There are two common styles for how people word `expect` messages. Using +the message to present information to users encountering a panic +("expect as error message") or using the message to present information +to developers debugging the panic ("expect as precondition"). + +In the former case the expect message is used to describe the error that +has occurred which is considered a bug. Consider the following example: + +```should_panic +// Read environment variable, panic if it is not present +let path = std::env::var("IMPORTANT_PATH").unwrap(); +``` + +In the "expect as error message" style we would use expect to describe +that the environment variable was not set when it should have been: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` is not set"); +``` + +In the "expect as precondition" style, we would instead describe the +reason we _expect_ the `Result` should be `Ok`. With this style we would +prefer to write: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); +``` + +The "expect as error message" style does not work as well with the +default output of the std panic hooks, and often ends up repeating +information that is already communicated by the source error being +unwrapped: + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 +``` + +In this example we end up mentioning that an env variable is not set, +followed by our source message that says the env is not present, the +only additional information we're communicating is the name of the +environment variable being checked. + +The "expect as precondition" style instead focuses on source code +readability, making it easier to understand what must have gone wrong in +situations where panics are being used to represent bugs exclusively. +Also, by framing our expect in terms of what "SHOULD" have happened to +prevent the source error, we end up introducing new information that is +independent from our source error. + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 +``` + +In this example we are communicating not only the name of the +environment variable that should have been set, but also an explanation +for why it should have been set, and we let the source error display as +a clear contradiction to our expectation. + +**Hint**: If you're having trouble remembering how to phrase +expect-as-precondition style error messages remember to focus on the word +"should" as in "env variable should be set by blah" or "the given binary +should be available and executable by the current user". + +[`panic_any`]: crate::panic::panic_any +[`PanicInfo`]: crate::panic::PanicInfo +[`catch_unwind`]: crate::panic::catch_unwind +[`resume_unwind`]: crate::panic::resume_unwind +[`downcast`]: crate::error::Error +[`Termination`]: crate::process::Termination +[`Try`]: crate::ops::Try +[panic hook]: crate::panic::set_hook +[`set_hook`]: crate::panic::set_hook +[`take_hook`]: crate::panic::take_hook +[panic-handler]: +[`match`]: ../../std/keyword.match.html +[`?`]: ../../std/result/index.html#the-question-mark-operator- diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 1dc213237aa78..d11debb34adca 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1,5 +1,4 @@ -//! Interfaces for working with Errors. -// FIXME(yaahc): link to std docs or common docs and try to figure out intradoc issue +#![doc = include_str!("error.md")] #![unstable(feature = "error_in_core", issue = "none")] // A note about crates and the facade: diff --git a/library/std/src/error.rs b/library/std/src/error.rs index f424c512136b7..555c6b23c8f17 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1,141 +1,4 @@ -//! Interfaces for working with Errors. -//! -//! # Error Handling In Rust -//! -//! The Rust language provides two complementary systems for constructing / -//! representing, reporting, propagating, reacting to, and discarding errors. -//! These responsibilities are collectively known as "error handling." The -//! components of the first system, the panic runtime and interfaces, are most -//! commonly used to represent bugs that have been detected in your program. The -//! components of the second system, `Result`, the error traits, and user -//! defined types, are used to represent anticipated runtime failure modes of -//! your program. -//! -//! ## The Panic Interfaces -//! -//! The following are the primary interfaces of the panic system and the -//! responsibilities they cover: -//! -//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) -//! * [`PanicInfo`] (Reporting) -//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) -//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) -//! -//! The following are the primary interfaces of the error system and the -//! responsibilities they cover: -//! -//! * [`Result`] (Propagating, Reacting) -//! * The [`Error`] trait (Reporting) -//! * User defined types (Constructing / Representing) -//! * [`match`] and [`downcast`] (Reacting) -//! * The question mark operator ([`?`]) (Propagating) -//! * The partially stable [`Try`] traits (Propagating, Constructing) -//! * [`Termination`] (Reporting) -//! -//! ## Converting Errors into Panics -//! -//! The panic and error systems are not entirely distinct. Often times errors -//! that are anticipated runtime failures in an API might instead represent bugs -//! to a caller. For these situations the standard library provides APIs for -//! constructing panics with an `Error` as it's source. -//! -//! * [`Result::unwrap`] -//! * [`Result::expect`] -//! -//! These functions are equivalent, they either return the inner value if the -//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error -//! as the source. The only difference between them is that with `expect` you -//! provide a panic error message to be printed alongside the source, whereas -//! `unwrap` has a default message indicating only that you unwraped an `Err`. -//! -//! Of the two, `expect` is generally preferred since its `msg` field allows you -//! to convey your intent and assumptions which makes tracking down the source -//! of a panic easier. `unwrap` on the other hand can still be a good fit in -//! situations where you can trivially show that a piece of code will never -//! panic, such as `"127.0.0.1".parse::().unwrap()` or early -//! prototyping. -//! -//! # Common Message Styles -//! -//! There are two common styles for how people word `expect` messages. Using -//! the message to present information to users encountering a panic -//! ("expect as error message") or using the message to present information -//! to developers debugging the panic ("expect as precondition"). -//! -//! In the former case the expect message is used to describe the error that -//! has occurred which is considered a bug. Consider the following example: -//! -//! ```should_panic -//! // Read environment variable, panic if it is not present -//! let path = std::env::var("IMPORTANT_PATH").unwrap(); -//! ``` -//! -//! In the "expect as error message" style we would use expect to describe -//! that the environment variable was not set when it should have been: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` is not set"); -//! ``` -//! -//! In the "expect as precondition" style, we would instead describe the -//! reason we _expect_ the `Result` should be `Ok`. With this style we would -//! prefer to write: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); -//! ``` -//! -//! The "expect as error message" style does not work as well with the -//! default output of the std panic hooks, and often ends up repeating -//! information that is already communicated by the source error being -//! unwrapped: -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we end up mentioning that an env variable is not set, -//! followed by our source message that says the env is not present, the -//! only additional information we're communicating is the name of the -//! environment variable being checked. -//! -//! The "expect as precondition" style instead focuses on source code -//! readability, making it easier to understand what must have gone wrong in -//! situations where panics are being used to represent bugs exclusively. -//! Also, by framing our expect in terms of what "SHOULD" have happened to -//! prevent the source error, we end up introducing new information that is -//! independent from our source error. -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we are communicating not only the name of the -//! environment variable that should have been set, but also an explanation -//! for why it should have been set, and we let the source error display as -//! a clear contradiction to our expectation. -//! -//! **Hint**: If you're having trouble remembering how to phrase -//! expect-as-precondition style error messages remember to focus on the word -//! "should" as in "env variable should be set by blah" or "the given binary -//! should be available and executable by the current user". -//! -//! [`panic_any`]: crate::panic::panic_any -//! [`PanicInfo`]: crate::panic::PanicInfo -//! [`catch_unwind`]: crate::panic::catch_unwind -//! [`resume_unwind`]: crate::panic::resume_unwind -//! [`downcast`]: crate::error::Error -//! [`Termination`]: crate::process::Termination -//! [`Try`]: crate::ops::Try -//! [panic hook]: crate::panic::set_hook -//! [`set_hook`]: crate::panic::set_hook -//! [`take_hook`]: crate::panic::take_hook -//! [panic-handler]: -//! [`match`]: ../../std/keyword.match.html -//! [`?`]: ../../std/result/index.html#the-question-mark-operator- - +#![doc = include_str!("../../core/src/error.md")] #![stable(feature = "rust1", since = "1.0.0")] // A note about crates and the facade: From 29fcfa53cf5422c3e591720355ea8fe008346b93 Mon Sep 17 00:00:00 2001 From: Jean CASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Thu, 18 Aug 2022 18:08:39 +0200 Subject: [PATCH 19/24] Migrate ast_lowering::pat to SessionDiagnostic --- compiler/rustc_ast_lowering/src/errors.rs | 38 ++++++++++++++++++- compiler/rustc_ast_lowering/src/pat.rs | 33 +++++----------- .../locales/en-US/ast_lowering.ftl | 17 +++++++++ 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 36a9bf6e68ff3..e271c4e2d3bf5 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; -use rustc_span::{Span, Symbol}; +use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic, Clone, Copy)] #[error(ast_lowering::generic_type_with_parentheses, code = "E0214")] @@ -270,3 +270,39 @@ pub struct RegisterConflict<'a> { #[help] pub in_out: Option, } + +#[derive(SessionDiagnostic, Clone, Copy)] +#[help] +#[error(ast_lowering::sub_tuple_binding)] +pub struct SubTupleBinding<'a> { + #[primary_span] + #[label] + #[suggestion_verbose( + ast_lowering::sub_tuple_binding_suggestion, + code = "..", + applicability = "maybe-incorrect" + )] + pub span: Span, + pub ident: Ident, + pub ident_name: Symbol, + pub ctx: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::extra_double_dot)] +pub struct ExtraDoubleDot<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(ast_lowering::previously_used_here)] + pub prev_span: Span, + pub ctx: &'a str, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[note] +#[error(ast_lowering::misplaced_double_dot)] +pub struct MisplacedDoubleDot { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 51f67e505f4ee..abe9b354252ac 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,3 +1,4 @@ +use super::errors::{ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding}; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode}; use crate::ImplTraitPosition; @@ -5,7 +6,6 @@ use crate::ImplTraitPosition; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::symbol::Ident; @@ -134,20 +134,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // This is not allowed as a sub-tuple pattern PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => { let sp = pat.span; - self.diagnostic() - .struct_span_err( - sp, - &format!("`{} @` is not allowed in a {}", ident.name, ctx), - ) - .span_label(sp, "this is only allowed in slice patterns") - .help("remove this and bind each tuple field independently") - .span_suggestion_verbose( - sp, - &format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident), - "..", - Applicability::MaybeIncorrect, - ) - .emit(); + self.tcx.sess.emit_err(SubTupleBinding { + span: sp, + ident_name: ident.name, + ident, + ctx, + }); } _ => {} } @@ -296,19 +288,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) { - self.diagnostic() - .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx)) - .span_label(sp, &format!("can only be used once per {} pattern", ctx)) - .span_label(prev_sp, "previously used here") - .emit(); + self.tcx.sess.emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx }); } /// Used to ban the `..` pattern in places it shouldn't be semantically. fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> { - self.diagnostic() - .struct_span_err(sp, "`..` patterns are not allowed here") - .note("only allowed in tuple, tuple struct, and slice patterns") - .emit(); + self.tcx.sess.emit_err(MisplacedDoubleDot { span: sp }); // We're not in a list context so `..` can be reasonably treated // as `_` because it should always be valid and roughly matches the diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl index 592e303b53fdd..438fbd8e57ba0 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -103,3 +103,20 @@ ast_lowering_register_conflict = ast_lowering_register1 = register `{$reg1_name}` ast_lowering_register2 = register `{$reg2_name}` + +ast_lowering_sub_tuple_binding = + `{$ident_name} @` is not allowed in a {$ctx} + .label = this is only allowed in slice patterns + .help = remove this and bind each tuple field independently + +ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields + +ast_lowering_extra_double_dot = + `..` can only be used once per {$ctx} pattern + .label = can only be used once per {$ctx} pattern + +ast_lowering_previously_used_here = previously used here + +ast_lowering_misplaced_double_dot = + `..` patterns are not allowed here + .note = only allowed in tuple, tuple struct, and slice patterns From 943f03fcfc77d31aa39b3556d9be3826f38ead9f Mon Sep 17 00:00:00 2001 From: Jean CASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Thu, 18 Aug 2022 19:30:56 +0200 Subject: [PATCH 20/24] Migrate all span_err(...) in ast_lowering to SessionDiagnostic --- compiler/rustc_ast_lowering/src/errors.rs | 21 +++++++++++++++++++ compiler/rustc_ast_lowering/src/expr.rs | 8 +++---- compiler/rustc_ast_lowering/src/item.rs | 8 ++----- compiler/rustc_ast_lowering/src/pat.rs | 7 ++++--- .../locales/en-US/ast_lowering.ftl | 9 ++++++++ 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index e271c4e2d3bf5..e403a296e05cf 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -306,3 +306,24 @@ pub struct MisplacedDoubleDot { #[primary_span] pub span: Span, } + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::misplaced_relax_trait_bound)] +pub struct MisplacedRelaxTraitBound { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::not_supported_for_lifetime_binder_async_closure)] +pub struct NotSupportedForLifetimeBinderAsyncClosure { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic, Clone, Copy)] +#[error(ast_lowering::arbitrary_expression_in_pattern)] +pub struct ArbitraryExpressionInPattern { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 011b8fc973ecb..ee164aae70ebc 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,7 +1,8 @@ use super::errors::{ AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, - GeneratorTooManyParameters, RustcBoxAttributeError, UnderscoreExprLhsAssign, + GeneratorTooManyParameters, NotSupportedForLifetimeBinderAsyncClosure, RustcBoxAttributeError, + UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; @@ -916,10 +917,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, ) -> hir::ExprKind<'hir> { if let &ClosureBinder::For { span, .. } = binder { - self.tcx.sess.span_err( - span, - "`for<...>` binders on `async` closures are not currently supported", - ); + self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); } let (binder_clause, generic_params) = self.lower_closure_binder(binder); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9e3b05801f316..f9ee45ea077a0 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,4 +1,4 @@ -use super::errors::InvalidAbi; +use super::errors::{InvalidAbi, MisplacedRelaxTraitBound}; use super::ResolverAstLoweringExt; use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; @@ -1339,11 +1339,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let is_param = *is_param.get_or_insert_with(compute_is_param); if !is_param { - self.diagnostic().span_err( - bound.span(), - "`?Trait` bounds are only permitted at the \ - point where a type parameter is declared", - ); + self.tcx.sess.emit_err(MisplacedRelaxTraitBound { span: bound.span() }); } } } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index abe9b354252ac..1efa19a3a8286 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,4 +1,6 @@ -use super::errors::{ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding}; +use super::errors::{ + ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, +}; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode}; use crate::ImplTraitPosition; @@ -330,8 +332,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} _ => { - self.diagnostic() - .span_err(expr.span, "arbitrary expressions aren't allowed in patterns"); + self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span }); return self.arena.alloc(self.expr_err(expr.span)); } } diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl index 438fbd8e57ba0..8effd9ca75017 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -120,3 +120,12 @@ ast_lowering_previously_used_here = previously used here ast_lowering_misplaced_double_dot = `..` patterns are not allowed here .note = only allowed in tuple, tuple struct, and slice patterns + +ast_lowering_misplaced_relax_trait_bound = + `?Trait` bounds are only permitted at the point where a type parameter is declared + +ast_lowering_not_supported_for_lifetime_binder_async_closure = + `for<...>` binders on `async` closures are not currently supported + +ast_lowering_arbitrary_expression_in_pattern = + arbitrary expressions aren't allowed in patterns From e34da16721ecd9dc0bab60b26c59992c4e3a81cb Mon Sep 17 00:00:00 2001 From: Jean CASPAR <55629512+JeanCASPAR@users.noreply.github.com> Date: Fri, 19 Aug 2022 14:55:06 +0200 Subject: [PATCH 21/24] Changes made in response to feedback --- compiler/rustc_ast_lowering/src/asm.rs | 22 ++++++++++++------- compiler/rustc_ast_lowering/src/errors.rs | 14 ++++++------ compiler/rustc_ast_lowering/src/lib.rs | 4 ++-- .../locales/en-US/ast_lowering.ftl | 4 ++-- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index d246510e0c1ed..0dba9da63da2a 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -124,22 +124,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .iter() .map(|(op, op_sp)| { let lower_reg = |reg| match reg { - InlineAsmRegOrRegClass::Reg(s) => { + InlineAsmRegOrRegClass::Reg(reg) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { - asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| { - sess.emit_err(InvalidRegister { op_span: *op_sp, s, e }); + asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| { + sess.emit_err(InvalidRegister { op_span: *op_sp, reg, error }); asm::InlineAsmReg::Err }) } else { asm::InlineAsmReg::Err }) } - InlineAsmRegOrRegClass::RegClass(s) => { + InlineAsmRegOrRegClass::RegClass(reg_class) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { - asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| { - sess.emit_err(InvalidRegisterClass { op_span: *op_sp, s, e }); - asm::InlineAsmRegClass::Err - }) + asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else( + |error| { + sess.emit_err(InvalidRegisterClass { + op_span: *op_sp, + reg_class, + error, + }); + asm::InlineAsmRegClass::Err + }, + ) } else { asm::InlineAsmRegClass::Err }) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index e403a296e05cf..70ddb80edc160 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -73,10 +73,10 @@ impl AddSubdiagnostic for AssocTyParenthesesSub { #[derive(SessionDiagnostic)] #[error(ast_lowering::misplaced_impl_trait, code = "E0562")] -pub struct MisplacedImplTrait { +pub struct MisplacedImplTrait<'a> { #[primary_span] pub span: Span, - pub position: String, + pub position: DiagnosticArgFromDisplay<'a>, } #[derive(SessionDiagnostic, Clone, Copy)] @@ -196,8 +196,8 @@ pub struct InvalidAbiClobberAbi { pub struct InvalidRegister<'a> { #[primary_span] pub op_span: Span, - pub s: Symbol, - pub e: &'a str, + pub reg: Symbol, + pub error: &'a str, } #[derive(SessionDiagnostic, Clone, Copy)] @@ -205,8 +205,8 @@ pub struct InvalidRegister<'a> { pub struct InvalidRegisterClass<'a> { #[primary_span] pub op_span: Span, - pub s: Symbol, - pub e: &'a str, + pub reg_class: Symbol, + pub error: &'a str, } #[derive(SessionDiagnostic)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6e2f38b7e7156..caa69a80b0840 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -51,7 +51,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Handler, StashKey}; +use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -1334,7 +1334,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(position) => { self.tcx.sess.emit_err(MisplacedImplTrait { span: t.span, - position: position.to_string(), + position: DiagnosticArgFromDisplay(&position), }); hir::TyKind::Err } diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl index 8effd9ca75017..dcb1e2b08306f 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -69,10 +69,10 @@ ast_lowering_invalid_abi_clobber_abi = .note = the following ABIs are supported on this target: {$supported_abis} ast_lowering_invalid_register = - invalid register `{$s}`: {$e} + invalid register `{$reg}`: {$error} ast_lowering_invalid_register_class = - invalid register class `{$s}`: {$e} + invalid register class `{$reg_class}`: {$error} ast_lowering_invalid_asm_template_modifier_reg_class = invalid asm template modifier for this register class From d35749b0f2ba52546fd9c616f665a5132ec55384 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Fri, 19 Aug 2022 17:31:32 +0100 Subject: [PATCH 22/24] triagebot: Autolabel `A-rustdoc-json` --- triagebot.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index b7532e016b68e..4d3f748195b80 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -129,6 +129,7 @@ trigger_files = [ # Internal tooling "src/etc/htmldocck.py", + "src/etc/check_missing_items.py", "src/tools/jsondocck", "src/tools/rustdoc-gui", "src/tools/rustdoc-js", @@ -138,6 +139,15 @@ exclude_labels = [ "T-*", ] +[autolabel."A-rustdoc-json"] +trigger_files = [ + "src/etc/check_missing_items.py", + "src/librustdoc/json/", + "src/rustdoc-json-types", + "src/test/rustdoc-json", + "src/tools/jsondocck", +] + [autolabel."T-compiler"] trigger_files = [ # Source code From 03861e5a95caaad47a04dfb364d5985b9e9024c6 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 19 Aug 2022 14:09:49 -0700 Subject: [PATCH 23/24] fix rustdoc links --- library/core/src/error.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/error.md b/library/core/src/error.md index f0a224c2a5c38..891abebbfd39b 100644 --- a/library/core/src/error.md +++ b/library/core/src/error.md @@ -122,16 +122,16 @@ expect-as-precondition style error messages remember to focus on the word "should" as in "env variable should be set by blah" or "the given binary should be available and executable by the current user". -[`panic_any`]: crate::panic::panic_any +[`panic_any`]: ../../std/panic/fn.panic_any.html [`PanicInfo`]: crate::panic::PanicInfo -[`catch_unwind`]: crate::panic::catch_unwind -[`resume_unwind`]: crate::panic::resume_unwind +[`catch_unwind`]: ../../std/panic/fn.catch_unwind.html +[`resume_unwind`]: ../../std/panic/fn.resume_unwind.html [`downcast`]: crate::error::Error -[`Termination`]: crate::process::Termination +[`Termination`]: ../../std/process/trait.Termination.html [`Try`]: crate::ops::Try -[panic hook]: crate::panic::set_hook -[`set_hook`]: crate::panic::set_hook -[`take_hook`]: crate::panic::take_hook +[panic hook]: ../../std/panic/fn.set_hook.html +[`set_hook`]: ../../std/panic/fn.set_hook.html +[`take_hook`]: ../../std/panic/fn.take_hook.html [panic-handler]: [`match`]: ../../std/keyword.match.html [`?`]: ../../std/result/index.html#the-question-mark-operator- From 3de74f7e2be7be983aaef0fe7be08e9030e4ecbb Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 20 Aug 2022 09:43:37 +0800 Subject: [PATCH 24/24] Suggest the right help message for as_ref --- .../src/infer/error_reporting/mod.rs | 3 +- src/test/ui/issues/issue-100605.rs | 9 ++++ src/test/ui/issues/issue-100605.stderr | 46 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-100605.rs create mode 100644 src/test/ui/issues/issue-100605.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 20864c657ffd7..529ddf03a8cc3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2078,7 +2078,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag.span_suggestion( span, *msg, - format!("{}.as_ref()", snippet), + // HACK: fix issue# 100605, suggesting convert from &Option to Option<&T>, remove the extra `&` + format!("{}.as_ref()", snippet.trim_start_matches('&')), Applicability::MachineApplicable, ); } diff --git a/src/test/ui/issues/issue-100605.rs b/src/test/ui/issues/issue-100605.rs new file mode 100644 index 0000000000000..917a45c15bbc8 --- /dev/null +++ b/src/test/ui/issues/issue-100605.rs @@ -0,0 +1,9 @@ +fn takes_option(_arg: Option<&String>) {} + +fn main() { + takes_option(&None); //~ ERROR 4:18: 4:23: mismatched types [E0308] + + let x = String::from("x"); + let res = Some(x); + takes_option(&res); //~ ERROR 8:18: 8:22: mismatched types [E0308] +} diff --git a/src/test/ui/issues/issue-100605.stderr b/src/test/ui/issues/issue-100605.stderr new file mode 100644 index 0000000000000..886e3cd6bb794 --- /dev/null +++ b/src/test/ui/issues/issue-100605.stderr @@ -0,0 +1,46 @@ +error[E0308]: mismatched types + --> $DIR/issue-100605.rs:4:18 + | +LL | takes_option(&None); + | ------------ ^^^^^ expected enum `Option`, found `&Option<_>` + | | + | arguments to this function are incorrect + | + = note: expected enum `Option<&String>` + found reference `&Option<_>` +note: function defined here + --> $DIR/issue-100605.rs:1:4 + | +LL | fn takes_option(_arg: Option<&String>) {} + | ^^^^^^^^^^^^ --------------------- +help: you can convert from `&Option` to `Option<&T>` using `.as_ref()` + | +LL | takes_option(None.as_ref()); + | ~~~~~~~~~~~~~ +help: consider removing the borrow + | +LL - takes_option(&None); +LL + takes_option(None); + | + +error[E0308]: mismatched types + --> $DIR/issue-100605.rs:8:18 + | +LL | takes_option(&res); + | ------------ ^^^^ + | | | + | | expected enum `Option`, found `&Option` + | | help: you can convert from `&Option` to `Option<&T>` using `.as_ref()`: `res.as_ref()` + | arguments to this function are incorrect + | + = note: expected enum `Option<&String>` + found reference `&Option` +note: function defined here + --> $DIR/issue-100605.rs:1:4 + | +LL | fn takes_option(_arg: Option<&String>) {} + | ^^^^^^^^^^^^ --------------------- + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`.