diff --git a/library/core/src/error.rs b/library/core/src/error.rs deleted file mode 100644 index 9ca91ee009ee9..0000000000000 --- a/library/core/src/error.rs +++ /dev/null @@ -1,1084 +0,0 @@ -#![doc = include_str!("error.md")] -#![stable(feature = "error_in_core", since = "1.81.0")] - -use crate::any::TypeId; -use crate::fmt::{self, Debug, Display, Formatter}; - -/// `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"); -/// ``` -/// -/// # Error source -/// -/// Errors may provide cause 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. -/// -/// In error types that wrap an underlying error, the underlying error -/// should be either returned by the outer error's `Error::source()`, or rendered -/// by the outer error's `Display` implementation, but not both. -/// -/// # Example -/// -/// Implementing the `Error` trait only requires that `Debug` and `Display` are implemented too. -/// -/// ``` -/// use std::error::Error; -/// use std::fmt; -/// use std::path::PathBuf; -/// -/// #[derive(Debug)] -/// struct ReadConfigError { -/// path: PathBuf -/// } -/// -/// impl fmt::Display for ReadConfigError { -/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// let path = self.path.display(); -/// write!(f, "unable to read configuration at {path}") -/// } -/// } -/// -/// impl Error for ReadConfigError {} -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "Error"] -#[rustc_has_incoherent_inherent_impls] -#[allow(multiple_supertrait_upcastable)] -pub trait Error: Debug + Display { - /// Returns 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 [`Request::provide_value`] and [`Request::provide_ref`] to extract - /// references to member variables from `dyn Error` trait objects. - /// - /// # Example - /// - /// ```rust - /// #![feature(error_generic_member_access)] - /// use core::fmt; - /// use core::error::{request_ref, Request}; - /// - /// #[derive(Debug)] - /// enum MyLittleTeaPot { - /// Empty, - /// } - /// - /// #[derive(Debug)] - /// struct MyBacktrace { - /// // ... - /// } - /// - /// impl MyBacktrace { - /// fn new() -> MyBacktrace { - /// // ... - /// # MyBacktrace {} - /// } - /// } - /// - /// #[derive(Debug)] - /// struct Error { - /// 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, request: &mut Request<'a>) { - /// request - /// .provide_ref::(&self.backtrace); - /// } - /// } - /// - /// fn main() { - /// let backtrace = MyBacktrace::new(); - /// let error = Error { backtrace }; - /// let dyn_error = &error as &dyn std::error::Error; - /// let backtrace_ref = request_ref::(dyn_error).unwrap(); - /// - /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); - /// assert!(request_ref::(dyn_error).is_none()); - /// } - /// ``` - #[unstable(feature = "error_generic_member_access", issue = "99301")] - #[allow(unused_variables)] - fn provide<'a>(&'a self, request: &mut Request<'a>) {} -} - -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 ! {} - -// 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) - } -} - -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) - } -} - -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.sources(); - /// - /// 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 sources(&self) -> Source<'_> { - // You may think this method would be better in the `Error` trait, and you'd be right. - // Unfortunately that doesn't work, not because of the dyn-incompatibility rules but - // because we save a reference to `self` in `Source`s below as a trait object. - // If this method was declared in `Error`, then `self` would have the type `&T` where - // `T` is some concrete type which implements `Error`. We would need to coerce `self` - // to have type `&dyn Error`, but that requires that `Self` has a known size - // (i.e., `Self: Sized`). We can't put that bound on `Error` since that would forbid - // `Error` trait objects, and we can't put that bound on the method because that means - // the method can't be called on trait objects (we'd also need the `'static` bound, - // but that isn't allowed because methods with bounds on `Self` other than `Sized` are - // dyn-incompatible). Requiring an `Unsize` bound is not backwards compatible. - - Source { current: Some(self) } - } -} - -/// Requests a value of type `T` from the given `impl Error`. -/// -/// # Examples -/// -/// Get a string value from an error. -/// -/// ```rust -/// #![feature(error_generic_member_access)] -/// use std::error::Error; -/// use core::error::request_value; -/// -/// fn get_string(err: &impl Error) -> String { -/// request_value::(err).unwrap() -/// } -/// ``` -#[unstable(feature = "error_generic_member_access", issue = "99301")] -pub fn request_value<'a, T>(err: &'a (impl Error + ?Sized)) -> Option -where - T: 'static, -{ - request_by_type_tag::<'a, tags::Value>(err) -} - -/// Requests a reference of type `T` from the given `impl Error`. -/// -/// # Examples -/// -/// Get a string reference from an error. -/// -/// ```rust -/// #![feature(error_generic_member_access)] -/// use core::error::Error; -/// use core::error::request_ref; -/// -/// fn get_str(err: &impl Error) -> &str { -/// request_ref::(err).unwrap() -/// } -/// ``` -#[unstable(feature = "error_generic_member_access", issue = "99301")] -pub fn request_ref<'a, T>(err: &'a (impl Error + ?Sized)) -> Option<&'a T> -where - T: 'static + ?Sized, -{ - request_by_type_tag::<'a, tags::Ref>>(err) -} - -/// Request a specific value by tag from the `Error`. -fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option -where - I: tags::Type<'a>, -{ - let mut tagged = Tagged { tag_id: TypeId::of::(), value: TaggedOption::<'a, I>(None) }; - err.provide(tagged.as_request()); - tagged.value.0 -} - -/////////////////////////////////////////////////////////////////////////////// -// Request and its methods -/////////////////////////////////////////////////////////////////////////////// - -/// `Request` supports generic, type-driven access to data. Its use is currently restricted to the -/// standard library in cases where trait authors wish to allow trait implementors to share generic -/// information across trait boundaries. The motivating and prototypical use case is -/// `core::error::Error` which would otherwise require a method per concrete type (eg. -/// `std::backtrace::Backtrace` instance that implementors want to expose to users). -/// -/// # Data flow -/// -/// To describe the intended data flow for Request objects, let's consider two conceptual users -/// separated by API boundaries: -/// -/// * Consumer - the consumer requests objects using a Request instance; eg a crate that offers -/// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`. -/// -/// * Producer - the producer provides objects when requested via Request; eg. a library with an -/// an `Error` implementation that automatically captures backtraces at the time instances are -/// created. -/// -/// The consumer only needs to know where to submit their request and are expected to handle the -/// request not being fulfilled by the use of `Option` in the responses offered by the producer. -/// -/// * A Producer initializes the value of one of its fields of a specific type. (or is otherwise -/// prepared to generate a value requested). eg, `backtrace::Backtrace` or -/// `std::backtrace::Backtrace` -/// * A Consumer requests an object of a specific type (say `std::backtrace::Backtrace`). In the -/// case of a `dyn Error` trait object (the Producer), there are functions called `request_ref` and -/// `request_value` to simplify obtaining an `Option` for a given type. -/// * The Producer, when requested, populates the given Request object which is given as a mutable -/// reference. -/// * The Consumer extracts a value or reference to the requested type from the `Request` object -/// wrapped in an `Option`; in the case of `dyn Error` the aforementioned `request_ref` and ` -/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at -/// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the -/// Producer cannot currently offer an instance of the requested type, not it can't or never will. -/// -/// # Examples -/// -/// The best way to demonstrate this is using an example implementation of `Error`'s `provide` trait -/// method: -/// -/// ``` -/// #![feature(error_generic_member_access)] -/// use core::fmt; -/// use core::error::Request; -/// use core::error::request_ref; -/// -/// #[derive(Debug)] -/// enum MyLittleTeaPot { -/// Empty, -/// } -/// -/// #[derive(Debug)] -/// struct MyBacktrace { -/// // ... -/// } -/// -/// impl MyBacktrace { -/// fn new() -> MyBacktrace { -/// // ... -/// # MyBacktrace {} -/// } -/// } -/// -/// #[derive(Debug)] -/// struct Error { -/// 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, request: &mut Request<'a>) { -/// request -/// .provide_ref::(&self.backtrace); -/// } -/// } -/// -/// fn main() { -/// let backtrace = MyBacktrace::new(); -/// let error = Error { backtrace }; -/// let dyn_error = &error as &dyn std::error::Error; -/// let backtrace_ref = request_ref::(dyn_error).unwrap(); -/// -/// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); -/// assert!(request_ref::(dyn_error).is_none()); -/// } -/// ``` -/// -#[unstable(feature = "error_generic_member_access", issue = "99301")] -#[repr(transparent)] -pub struct Request<'a>(Tagged + 'a>); - -impl<'a> Request<'a> { - /// Provides a value or other type with only static lifetimes. - /// - /// # Examples - /// - /// Provides an `u8`. - /// - /// ```rust - /// #![feature(error_generic_member_access)] - /// - /// use core::error::Request; - /// - /// #[derive(Debug)] - /// struct SomeConcreteType { field: u8 } - /// - /// impl std::fmt::Display for SomeConcreteType { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "{} failed", self.field) - /// } - /// } - /// - /// impl std::error::Error for SomeConcreteType { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// request.provide_value::(self.field); - /// } - /// } - /// ``` - #[unstable(feature = "error_generic_member_access", issue = "99301")] - pub fn provide_value(&mut self, value: T) -> &mut Self - where - T: 'static, - { - self.provide::>(value) - } - - /// Provides a value or other type with only static lifetimes computed using a closure. - /// - /// # Examples - /// - /// Provides a `String` by cloning. - /// - /// ```rust - /// #![feature(error_generic_member_access)] - /// - /// use core::error::Request; - /// - /// #[derive(Debug)] - /// struct SomeConcreteType { field: String } - /// - /// impl std::fmt::Display for SomeConcreteType { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "{} failed", self.field) - /// } - /// } - /// - /// impl std::error::Error for SomeConcreteType { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// request.provide_value_with::(|| self.field.clone()); - /// } - /// } - /// ``` - #[unstable(feature = "error_generic_member_access", issue = "99301")] - pub fn provide_value_with(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self - where - T: 'static, - { - self.provide_with::>(fulfil) - } - - /// Provides a reference. The referee type must be bounded by `'static`, - /// but may be unsized. - /// - /// # Examples - /// - /// Provides a reference to a field as a `&str`. - /// - /// ```rust - /// #![feature(error_generic_member_access)] - /// - /// use core::error::Request; - /// - /// #[derive(Debug)] - /// struct SomeConcreteType { field: String } - /// - /// impl std::fmt::Display for SomeConcreteType { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "{} failed", self.field) - /// } - /// } - /// - /// impl std::error::Error for SomeConcreteType { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// request.provide_ref::(&self.field); - /// } - /// } - /// ``` - #[unstable(feature = "error_generic_member_access", issue = "99301")] - pub fn provide_ref(&mut self, value: &'a T) -> &mut Self { - self.provide::>>(value) - } - - /// Provides a reference computed using a closure. The referee type - /// must be bounded by `'static`, but may be unsized. - /// - /// # Examples - /// - /// Provides a reference to a field as a `&str`. - /// - /// ```rust - /// #![feature(error_generic_member_access)] - /// - /// use core::error::Request; - /// - /// #[derive(Debug)] - /// struct SomeConcreteType { business: String, party: String } - /// fn today_is_a_weekday() -> bool { true } - /// - /// impl std::fmt::Display for SomeConcreteType { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "{} failed", self.business) - /// } - /// } - /// - /// impl std::error::Error for SomeConcreteType { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// request.provide_ref_with::(|| { - /// if today_is_a_weekday() { - /// &self.business - /// } else { - /// &self.party - /// } - /// }); - /// } - /// } - /// ``` - #[unstable(feature = "error_generic_member_access", issue = "99301")] - pub fn provide_ref_with( - &mut self, - fulfil: impl FnOnce() -> &'a T, - ) -> &mut Self { - self.provide_with::>>(fulfil) - } - - /// Provides a value with the given `Type` tag. - fn provide(&mut self, value: I::Reified) -> &mut Self - where - I: tags::Type<'a>, - { - if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::() { - res.0 = Some(value); - } - self - } - - /// Provides a value with the given `Type` tag, using a closure to prevent unnecessary work. - fn provide_with(&mut self, fulfil: impl FnOnce() -> I::Reified) -> &mut Self - where - I: tags::Type<'a>, - { - if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::() { - res.0 = Some(fulfil()); - } - self - } - - /// Checks if the `Request` would be satisfied if provided with a - /// value of the specified type. If the type does not match or has - /// already been provided, returns false. - /// - /// # Examples - /// - /// Checks if a `u8` still needs to be provided and then provides - /// it. - /// - /// ```rust - /// #![feature(error_generic_member_access)] - /// - /// use core::error::Request; - /// use core::error::request_value; - /// - /// #[derive(Debug)] - /// struct Parent(Option); - /// - /// impl std::fmt::Display for Parent { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "a parent failed") - /// } - /// } - /// - /// impl std::error::Error for Parent { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// if let Some(v) = self.0 { - /// request.provide_value::(v); - /// } - /// } - /// } - /// - /// #[derive(Debug)] - /// struct Child { - /// parent: Parent, - /// } - /// - /// impl Child { - /// // Pretend that this takes a lot of resources to evaluate. - /// fn an_expensive_computation(&self) -> Option { - /// Some(99) - /// } - /// } - /// - /// impl std::fmt::Display for Child { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "child failed: \n because of parent: {}", self.parent) - /// } - /// } - /// - /// impl std::error::Error for Child { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// // In general, we don't know if this call will provide - /// // an `u8` value or not... - /// self.parent.provide(request); - /// - /// // ...so we check to see if the `u8` is needed before - /// // we run our expensive computation. - /// if request.would_be_satisfied_by_value_of::() { - /// if let Some(v) = self.an_expensive_computation() { - /// request.provide_value::(v); - /// } - /// } - /// - /// // The request will be satisfied now, regardless of if - /// // the parent provided the value or we did. - /// assert!(!request.would_be_satisfied_by_value_of::()); - /// } - /// } - /// - /// let parent = Parent(Some(42)); - /// let child = Child { parent }; - /// assert_eq!(Some(42), request_value::(&child)); - /// - /// let parent = Parent(None); - /// let child = Child { parent }; - /// assert_eq!(Some(99), request_value::(&child)); - /// - /// ``` - #[unstable(feature = "error_generic_member_access", issue = "99301")] - pub fn would_be_satisfied_by_value_of(&self) -> bool - where - T: 'static, - { - self.would_be_satisfied_by::>() - } - - /// Checks if the `Request` would be satisfied if provided with a - /// reference to a value of the specified type. - /// - /// If the type does not match or has already been provided, returns false. - /// - /// # Examples - /// - /// Checks if a `&str` still needs to be provided and then provides - /// it. - /// - /// ```rust - /// #![feature(error_generic_member_access)] - /// - /// use core::error::Request; - /// use core::error::request_ref; - /// - /// #[derive(Debug)] - /// struct Parent(Option); - /// - /// impl std::fmt::Display for Parent { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "a parent failed") - /// } - /// } - /// - /// impl std::error::Error for Parent { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// if let Some(v) = &self.0 { - /// request.provide_ref::(v); - /// } - /// } - /// } - /// - /// #[derive(Debug)] - /// struct Child { - /// parent: Parent, - /// name: String, - /// } - /// - /// impl Child { - /// // Pretend that this takes a lot of resources to evaluate. - /// fn an_expensive_computation(&self) -> Option<&str> { - /// Some(&self.name) - /// } - /// } - /// - /// impl std::fmt::Display for Child { - /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - /// write!(f, "{} failed: \n {}", self.name, self.parent) - /// } - /// } - /// - /// impl std::error::Error for Child { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// // In general, we don't know if this call will provide - /// // a `str` reference or not... - /// self.parent.provide(request); - /// - /// // ...so we check to see if the `&str` is needed before - /// // we run our expensive computation. - /// if request.would_be_satisfied_by_ref_of::() { - /// if let Some(v) = self.an_expensive_computation() { - /// request.provide_ref::(v); - /// } - /// } - /// - /// // The request will be satisfied now, regardless of if - /// // the parent provided the reference or we did. - /// assert!(!request.would_be_satisfied_by_ref_of::()); - /// } - /// } - /// - /// let parent = Parent(Some("parent".into())); - /// let child = Child { parent, name: "child".into() }; - /// assert_eq!(Some("parent"), request_ref::(&child)); - /// - /// let parent = Parent(None); - /// let child = Child { parent, name: "child".into() }; - /// assert_eq!(Some("child"), request_ref::(&child)); - /// ``` - #[unstable(feature = "error_generic_member_access", issue = "99301")] - pub fn would_be_satisfied_by_ref_of(&self) -> bool - where - T: ?Sized + 'static, - { - self.would_be_satisfied_by::>>() - } - - fn would_be_satisfied_by(&self) -> bool - where - I: tags::Type<'a>, - { - matches!(self.0.downcast::(), Some(TaggedOption(None))) - } -} - -#[unstable(feature = "error_generic_member_access", issue = "99301")] -impl<'a> Debug for Request<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Request").finish_non_exhaustive() - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Type tags -/////////////////////////////////////////////////////////////////////////////// - -pub(crate) mod tags { - //! Type tags are used to identify a type using a separate value. This module includes type tags - //! for some very common types. - //! - //! Currently type tags are not exposed to the user. But in the future, if you want to use the - //! Request API with more complex types (typically those including lifetime parameters), you - //! will need to write your own tags. - - use crate::marker::PhantomData; - - /// This trait is implemented by specific tag types in order to allow - /// describing a type which can be requested for a given lifetime `'a`. - /// - /// A few example implementations for type-driven tags can be found in this - /// module, although crates may also implement their own tags for more - /// complex types with internal lifetimes. - pub(crate) trait Type<'a>: Sized + 'static { - /// The type of values which may be tagged by this tag for the given - /// lifetime. - type Reified: 'a; - } - - /// Similar to the [`Type`] trait, but represents a type which may be unsized (i.e., has a - /// `?Sized` bound). E.g., `str`. - pub(crate) trait MaybeSizedType<'a>: Sized + 'static { - type Reified: 'a + ?Sized; - } - - impl<'a, T: Type<'a>> MaybeSizedType<'a> for T { - type Reified = T::Reified; - } - - /// Type-based tag for types bounded by `'static`, i.e., with no borrowed elements. - #[derive(Debug)] - pub(crate) struct Value(PhantomData); - - impl<'a, T: 'static> Type<'a> for Value { - type Reified = T; - } - - /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `?Sized` bound). - #[derive(Debug)] - pub(crate) struct MaybeSizedValue(PhantomData); - - impl<'a, T: ?Sized + 'static> MaybeSizedType<'a> for MaybeSizedValue { - type Reified = T; - } - - /// Type-based tag for reference types (`&'a T`, where T is represented by - /// `>::Reified`. - #[derive(Debug)] - pub(crate) struct Ref(PhantomData); - - impl<'a, I: MaybeSizedType<'a>> Type<'a> for Ref { - type Reified = &'a I::Reified; - } -} - -/// An `Option` with a type tag `I`. -/// -/// Since this struct implements `Erased`, the type can be erased to make a dynamically typed -/// option. The type can be checked dynamically using `Tagged::tag_id` and since this is statically -/// checked for the concrete type, there is some degree of type safety. -#[repr(transparent)] -pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option); - -impl<'a, I: tags::Type<'a>> Tagged> { - pub(crate) fn as_request(&mut self) -> &mut Request<'a> { - let erased = self as &mut Tagged + 'a>; - // SAFETY: transmuting `&mut Tagged + 'a>` to `&mut Request<'a>` is safe since - // `Request` is repr(transparent). - unsafe { &mut *(erased as *mut Tagged> as *mut Request<'a>) } - } -} - -/// Represents a type-erased but identifiable object. -/// -/// This trait is exclusively implemented by the `TaggedOption` type. -unsafe trait Erased<'a>: 'a {} - -unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {} - -struct Tagged { - tag_id: TypeId, - value: E, -} - -impl<'a> Tagged + 'a> { - /// Returns some reference to the dynamic value if it is tagged with `I`, - /// or `None` otherwise. - #[inline] - fn downcast(&self) -> Option<&TaggedOption<'a, I>> - where - I: tags::Type<'a>, - { - if self.tag_id == TypeId::of::() { - // SAFETY: Just checked whether we're pointing to an I. - Some(&unsafe { &*(self as *const Self).cast::>>() }.value) - } else { - None - } - } - - /// Returns some mutable reference to the dynamic value if it is tagged with `I`, - /// or `None` otherwise. - #[inline] - fn downcast_mut(&mut self) -> Option<&mut TaggedOption<'a, I>> - where - I: tags::Type<'a>, - { - if self.tag_id == TypeId::of::() { - Some( - // SAFETY: Just checked whether we're pointing to an I. - &mut unsafe { &mut *(self as *mut Self).cast::>>() } - .value, - ) - } else { - None - } - } -} - -/// 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 Source<'a> { - current: Option<&'a (dyn Error + 'static)>, -} - -#[unstable(feature = "error_iter", issue = "58520")] -impl<'a> Iterator for Source<'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 - } - - fn size_hint(&self) -> (usize, Option) { - if self.current.is_some() { (1, None) } else { (0, Some(0)) } - } -} - -#[unstable(feature = "error_iter", issue = "58520")] -impl<'a> crate::iter::FusedIterator for Source<'a> {} - -#[stable(feature = "error_by_ref", since = "1.51.0")] -impl<'a, T: Error + ?Sized> Error for &'a T { - #[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, request: &mut Request<'b>) { - Error::provide(&**self, request); - } -} - -#[stable(feature = "fmt_error", since = "1.11.0")] -impl Error for crate::fmt::Error {} - -#[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for crate::cell::BorrowError {} - -#[stable(feature = "try_borrow", since = "1.13.0")] -impl Error for crate::cell::BorrowMutError {} - -#[stable(feature = "try_from", since = "1.34.0")] -impl Error for crate::char::CharTryFromError {} - -#[stable(feature = "duration_checked_float", since = "1.66.0")] -impl Error for crate::time::TryFromFloatSecsError {} - -#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] -impl Error for crate::ffi::FromBytesUntilNulError {} - -#[stable(feature = "get_many_mut", since = "1.86.0")] -impl Error for crate::slice::GetDisjointMutError {} diff --git a/library/core/src/error/mod.rs b/library/core/src/error/mod.rs new file mode 100644 index 0000000000000..1bec774ee6aea --- /dev/null +++ b/library/core/src/error/mod.rs @@ -0,0 +1,501 @@ +#![doc = include_str!("../error.md")] +#![stable(feature = "error_in_core", since = "1.81.0")] + +use crate::any::TypeId; +use crate::fmt::{Debug, Display}; + +mod provide; + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +pub use provide::{ + ChainRefMultiRequestBuilder, ChainRefMultiResponse, ChainValMultiRequestBuilder, + ChainValMultiResponse, EmptyMultiRequestBuilder, IntoMultiRequest, MultiRequestBuilder, + MultiResponse, Request, request_ref, request_value, +}; + +/// `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"); +/// ``` +/// +/// # Error source +/// +/// Errors may provide cause 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. +/// +/// In error types that wrap an underlying error, the underlying error +/// should be either returned by the outer error's `Error::source()`, or rendered +/// by the outer error's `Display` implementation, but not both. +/// +/// # Example +/// +/// Implementing the `Error` trait only requires that `Debug` and `Display` are implemented too. +/// +/// ``` +/// use std::error::Error; +/// use std::fmt; +/// use std::path::PathBuf; +/// +/// #[derive(Debug)] +/// struct ReadConfigError { +/// path: PathBuf +/// } +/// +/// impl fmt::Display for ReadConfigError { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// let path = self.path.display(); +/// write!(f, "unable to read configuration at {path}") +/// } +/// } +/// +/// impl Error for ReadConfigError {} +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Error"] +#[rustc_has_incoherent_inherent_impls] +#[allow(multiple_supertrait_upcastable)] +pub trait Error: Debug + Display { + /// Returns 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 [`Request::provide_value`] and [`Request::provide_ref`] to extract + /// references to member variables from `dyn Error` trait objects. + /// + /// Every individual error type can `provide` some types that contain programmatic + /// information about the error. The set of values `provide`d by a given error type + /// can normally change between different versions of that error type's library. However, + /// a library defining an error type can always make stronger backwards-compatibility + /// promises - for example, a library can declare that an error type always provides a + /// [`Location`](core::panic::Location) that provides a relevant source-code location. + /// + /// # Whether to provide by reference or by value + /// + /// [`Request::provide_value`] and [`Request::provide_ref`] are two different namespaces. + /// Therefore, when providing a type, it needs to be picked whether it will be provided + /// by reference or by value. + /// + /// If a type is provided by value, then a new copy of that type has to be created every + /// time it is provided, but if it is provided by reference, then the provided value has + /// to be stored somewhere within the error so that the reference can be returned. + /// + /// Some general rules: + /// + /// 1. If a type is [Copy], it is conventional to provide it by value. + /// 2. If a type is not [Copy] but also not computed at provide time, for example + /// backtrace types that are captured when the error is created, it is conventional + /// to provide it by reference. + /// + /// Provided types that are not [Copy] and computed at provide time are fairly rare in + /// practice. However, when using them, you should be using + /// [`Request::would_be_satisfied_by_value_of`] to avoid computing them when they + /// are not requested. + /// + /// # Common uses of `provide` + /// + /// 1. [`Location`](core::panic::Location), provided by value, to indicate a source-code + /// location relevant to the error. This allows following the [`Error::source`] + /// chain to generate a "logical" backtrace, even in the absence of debug information. + /// 2. A backtrace, provided by reference, that contains the backtrace of the error. + /// 3. Various exit code types, normally provided by value. For example, an HTTP framework + /// might request an HTTP status on an error, to allow error types to override the HTTP + /// status returned on an error (consult your framework for specific behavior). + /// + /// # Example + /// + /// ```rust + /// #![feature(error_generic_member_access)] + /// use core::fmt; + /// use core::error::{request_ref, request_value, Request}; + /// use core::panic::Location; + /// + /// #[derive(Debug)] + /// enum MyLittleTeaPot { + /// Empty, + /// } + /// + /// #[derive(Debug)] + /// struct MyBacktrace { + /// // ... + /// } + /// + /// impl MyBacktrace { + /// fn new() -> MyBacktrace { + /// // ... + /// # MyBacktrace {} + /// } + /// } + /// + /// #[derive(Debug)] + /// struct Error { + /// backtrace: MyBacktrace, + /// location: Location<'static>, + /// } + /// + /// 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, request: &mut Request<'a>) { + /// request + /// .provide_ref::(&self.backtrace) + /// .provide_value::>(self.location); + /// } + /// } + /// + /// fn main() { + /// let backtrace = MyBacktrace::new(); + /// let location = Location::caller(); + /// let error = Error { backtrace, location: *location }; + /// let dyn_error = &error as &dyn std::error::Error; + /// let backtrace_ref = request_ref::(dyn_error).unwrap(); + /// let location = request_value::>(dyn_error).unwrap(); + /// + /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); + /// assert_eq!(error.location, location); + /// assert!(request_ref::(dyn_error).is_none()); + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(unused_variables)] + fn provide<'a>(&'a self, request: &mut Request<'a>) {} +} + +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 ! {} + +// 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) + } +} + +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) + } +} + +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.sources(); + /// + /// 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 sources(&self) -> Source<'_> { + // You may think this method would be better in the `Error` trait, and you'd be right. + // Unfortunately that doesn't work, not because of the dyn-incompatibility rules but + // because we save a reference to `self` in `Source`s below as a trait object. + // If this method was declared in `Error`, then `self` would have the type `&T` where + // `T` is some concrete type which implements `Error`. We would need to coerce `self` + // to have type `&dyn Error`, but that requires that `Self` has a known size + // (i.e., `Self: Sized`). We can't put that bound on `Error` since that would forbid + // `Error` trait objects, and we can't put that bound on the method because that means + // the method can't be called on trait objects (we'd also need the `'static` bound, + // but that isn't allowed because methods with bounds on `Self` other than `Sized` are + // dyn-incompatible). Requiring an `Unsize` bound is not backwards compatible. + + Source { 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 Source<'a> { + current: Option<&'a (dyn Error + 'static)>, +} + +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> Iterator for Source<'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 + } + + fn size_hint(&self) -> (usize, Option) { + if self.current.is_some() { (1, None) } else { (0, Some(0)) } + } +} + +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> crate::iter::FusedIterator for Source<'a> {} + +#[stable(feature = "error_by_ref", since = "1.51.0")] +impl<'a, T: Error + ?Sized> Error for &'a T { + #[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, request: &mut Request<'b>) { + Error::provide(&**self, request); + } +} + +#[stable(feature = "fmt_error", since = "1.11.0")] +impl Error for crate::fmt::Error {} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowError {} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowMutError {} + +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for crate::char::CharTryFromError {} + +#[stable(feature = "duration_checked_float", since = "1.66.0")] +impl Error for crate::time::TryFromFloatSecsError {} + +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] +impl Error for crate::ffi::FromBytesUntilNulError {} + +#[stable(feature = "get_many_mut", since = "1.86.0")] +impl Error for crate::slice::GetDisjointMutError {} diff --git a/library/core/src/error/provide.rs b/library/core/src/error/provide.rs new file mode 100644 index 0000000000000..8525b7c7464fb --- /dev/null +++ b/library/core/src/error/provide.rs @@ -0,0 +1,1314 @@ +//! Implementation of [Request] + +use crate::any::TypeId; +use crate::error::Error; +use crate::fmt::{self, Debug, Formatter}; +use crate::marker::PhantomData; +use crate::ptr::NonNull; + +/// Requests a value of type `T` from the given `impl Error`. +/// +/// # Examples +/// +/// Get a string value from an error. +/// +/// ```rust +/// #![feature(error_generic_member_access)] +/// use std::error::Error; +/// use core::error::request_value; +/// +/// fn get_string(err: &impl Error) -> String { +/// request_value::(err).unwrap() +/// } +/// ``` +#[unstable(feature = "error_generic_member_access", issue = "99301")] +pub fn request_value<'a, T>(err: &'a (impl Error + ?Sized)) -> Option +where + T: 'static, +{ + request_by_type_tag::<'a, tags::Value>(err) +} + +/// Requests a reference of type `T` from the given `impl Error`. +/// +/// # Examples +/// +/// Get a string reference from an error. +/// +/// ```rust +/// #![feature(error_generic_member_access)] +/// use core::error::Error; +/// use core::error::request_ref; +/// +/// fn get_str(err: &impl Error) -> &str { +/// request_ref::(err).unwrap() +/// } +/// ``` +#[unstable(feature = "error_generic_member_access", issue = "99301")] +pub fn request_ref<'a, T>(err: &'a (impl Error + ?Sized)) -> Option<&'a T> +where + T: 'static + ?Sized, +{ + request_by_type_tag::<'a, tags::Ref>>(err) +} + +/// Request a specific value by tag from the `Error`. +fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option +where + I: tags::Type<'a>, +{ + let mut tagged = >>::new_concrete(); + err.provide(tagged.as_request()); + tagged.value.0 +} + +/////////////////////////////////////////////////////////////////////////////// +// Request and its methods +/////////////////////////////////////////////////////////////////////////////// + +/// `Request` supports generic, type-driven access to data. Its use is currently restricted to the +/// standard library in cases where trait authors wish to allow trait implementors to share generic +/// information across trait boundaries. The motivating and prototypical use case is +/// `core::error::Error` which would otherwise require a method per concrete type (eg. +/// `std::backtrace::Backtrace` instance that implementors want to expose to users). +/// +/// # Data flow +/// +/// To describe the intended data flow for Request objects, let's consider two conceptual users +/// separated by API boundaries: +/// +/// * Consumer - the consumer requests objects using a Request instance; eg a crate that offers +/// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`. +/// +/// * Producer - the producer provides objects when requested via Request; eg. a library with an +/// an `Error` implementation that automatically captures backtraces at the time instances are +/// created. +/// +/// The consumer only needs to know where to submit their request and are expected to handle the +/// request not being fulfilled by the use of `Option` in the responses offered by the producer. +/// +/// * A Producer initializes the value of one of its fields of a specific type. (or is otherwise +/// prepared to generate a value requested). eg, `backtrace::Backtrace` or +/// `std::backtrace::Backtrace` +/// * A Consumer requests an object of a specific type (say `std::backtrace::Backtrace`). In the +/// case of a `dyn Error` trait object (the Producer), there are functions called `request_ref` and +/// `request_value` to simplify obtaining an `Option` for a given type. +/// * The Producer, when requested, populates the given Request object which is given as a mutable +/// reference. +/// * The Consumer extracts a value or reference to the requested type from the `Request` object +/// wrapped in an `Option`; in the case of `dyn Error` the aforementioned `request_ref` and ` +/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at +/// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the +/// Producer cannot currently offer an instance of the requested type, not it can't or never will. +/// +/// # Examples +/// +/// The best way to demonstrate this is using an example implementation of `Error`'s `provide` trait +/// method: +/// +/// ``` +/// #![feature(error_generic_member_access)] +/// use core::fmt; +/// use core::error::Request; +/// use core::error::request_ref; +/// +/// #[derive(Debug)] +/// enum MyLittleTeaPot { +/// Empty, +/// } +/// +/// #[derive(Debug)] +/// struct MyBacktrace { +/// // ... +/// } +/// +/// impl MyBacktrace { +/// fn new() -> MyBacktrace { +/// // ... +/// # MyBacktrace {} +/// } +/// } +/// +/// #[derive(Debug)] +/// struct Error { +/// 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, request: &mut Request<'a>) { +/// request +/// .provide_ref::(&self.backtrace); +/// } +/// } +/// +/// fn main() { +/// let backtrace = MyBacktrace::new(); +/// let error = Error { backtrace }; +/// let dyn_error = &error as &dyn std::error::Error; +/// let backtrace_ref = request_ref::(dyn_error).unwrap(); +/// +/// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); +/// assert!(request_ref::(dyn_error).is_none()); +/// } +/// ``` +/// +#[unstable(feature = "error_generic_member_access", issue = "99301")] +#[repr(transparent)] +pub struct Request<'a>(Tagged + 'a>); + +impl<'a> Request<'a> { + /// Provides a value or other type with only static lifetimes. + /// + /// # Examples + /// + /// Provides an `u8`. + /// + /// ```rust + /// #![feature(error_generic_member_access)] + /// + /// use core::error::Request; + /// + /// #[derive(Debug)] + /// struct SomeConcreteType { field: u8 } + /// + /// impl std::fmt::Display for SomeConcreteType { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "{} failed", self.field) + /// } + /// } + /// + /// impl std::error::Error for SomeConcreteType { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// request.provide_value::(self.field); + /// } + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn provide_value(&mut self, value: T) -> &mut Self + where + T: 'static, + { + self.provide::>(value) + } + + /// Provides a value or other type with only static lifetimes computed using a closure. + /// + /// # Examples + /// + /// Provides a `String` by cloning. + /// + /// ```rust + /// #![feature(error_generic_member_access)] + /// + /// use core::error::Request; + /// + /// #[derive(Debug)] + /// struct SomeConcreteType { field: String } + /// + /// impl std::fmt::Display for SomeConcreteType { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "{} failed", self.field) + /// } + /// } + /// + /// impl std::error::Error for SomeConcreteType { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// request.provide_value_with::(|| self.field.clone()); + /// } + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn provide_value_with(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self + where + T: 'static, + { + self.provide_with::>(fulfil) + } + + /// Provides a reference. The referee type must be bounded by `'static`, + /// but may be unsized. + /// + /// # Examples + /// + /// Provides a reference to a field as a `&str`. + /// + /// ```rust + /// #![feature(error_generic_member_access)] + /// + /// use core::error::Request; + /// + /// #[derive(Debug)] + /// struct SomeConcreteType { field: String } + /// + /// impl std::fmt::Display for SomeConcreteType { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "{} failed", self.field) + /// } + /// } + /// + /// impl std::error::Error for SomeConcreteType { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// request.provide_ref::(&self.field); + /// } + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn provide_ref(&mut self, value: &'a T) -> &mut Self { + self.provide::>>(value) + } + + /// Provides a reference computed using a closure. The referee type + /// must be bounded by `'static`, but may be unsized. + /// + /// # Examples + /// + /// Provides a reference to a field as a `&str`. + /// + /// ```rust + /// #![feature(error_generic_member_access)] + /// + /// use core::error::Request; + /// + /// #[derive(Debug)] + /// struct SomeConcreteType { business: String, party: String } + /// fn today_is_a_weekday() -> bool { true } + /// + /// impl std::fmt::Display for SomeConcreteType { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "{} failed", self.business) + /// } + /// } + /// + /// impl std::error::Error for SomeConcreteType { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// request.provide_ref_with::(|| { + /// if today_is_a_weekday() { + /// &self.business + /// } else { + /// &self.party + /// } + /// }); + /// } + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn provide_ref_with( + &mut self, + fulfil: impl FnOnce() -> &'a T, + ) -> &mut Self { + self.provide_with::>>(fulfil) + } + + /// Provides a value with the given `Type` tag. + fn provide(&mut self, value: I::Reified) -> &mut Self + where + I: tags::Type<'a>, + { + self.0.provide::(value); + self + } + + /// Provides a value with the given `Type` tag, using a closure to prevent unnecessary work. + fn provide_with(&mut self, fulfil: impl FnOnce() -> I::Reified) -> &mut Self + where + I: tags::Type<'a>, + { + self.0.provide_with::(fulfil); + self + } + + /// Checks if the `Request` would be satisfied if provided with a + /// value of the specified type. If the type does not match or has + /// already been provided, returns false. + /// + /// # Examples + /// + /// Checks if a `u8` still needs to be provided and then provides + /// it. + /// + /// ```rust + /// #![feature(error_generic_member_access)] + /// + /// use core::error::Request; + /// use core::error::request_value; + /// + /// #[derive(Debug)] + /// struct Parent(Option); + /// + /// impl std::fmt::Display for Parent { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "a parent failed") + /// } + /// } + /// + /// impl std::error::Error for Parent { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// if let Some(v) = self.0 { + /// request.provide_value::(v); + /// } + /// } + /// } + /// + /// #[derive(Debug)] + /// struct Child { + /// parent: Parent, + /// } + /// + /// impl Child { + /// // Pretend that this takes a lot of resources to evaluate. + /// fn an_expensive_computation(&self) -> Option { + /// Some(99) + /// } + /// } + /// + /// impl std::fmt::Display for Child { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "child failed: \n because of parent: {}", self.parent) + /// } + /// } + /// + /// impl std::error::Error for Child { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// // In general, we don't know if this call will provide + /// // an `u8` value or not... + /// self.parent.provide(request); + /// + /// // ...so we check to see if the `u8` is needed before + /// // we run our expensive computation. + /// if request.would_be_satisfied_by_value_of::() { + /// if let Some(v) = self.an_expensive_computation() { + /// request.provide_value::(v); + /// } + /// } + /// + /// // The request will be satisfied now, regardless of if + /// // the parent provided the value or we did. + /// assert!(!request.would_be_satisfied_by_value_of::()); + /// } + /// } + /// + /// let parent = Parent(Some(42)); + /// let child = Child { parent }; + /// assert_eq!(Some(42), request_value::(&child)); + /// + /// let parent = Parent(None); + /// let child = Child { parent }; + /// assert_eq!(Some(99), request_value::(&child)); + /// + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn would_be_satisfied_by_value_of(&self) -> bool + where + T: 'static, + { + self.would_be_satisfied_by::>() + } + + /// Checks if the `Request` would be satisfied if provided with a + /// reference to a value of the specified type. + /// + /// If the type does not match or has already been provided, returns false. + /// + /// # Examples + /// + /// Checks if a `&str` still needs to be provided and then provides + /// it. + /// + /// ```rust + /// #![feature(error_generic_member_access)] + /// + /// use core::error::Request; + /// use core::error::request_ref; + /// + /// #[derive(Debug)] + /// struct Parent(Option); + /// + /// impl std::fmt::Display for Parent { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "a parent failed") + /// } + /// } + /// + /// impl std::error::Error for Parent { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// if let Some(v) = &self.0 { + /// request.provide_ref::(v); + /// } + /// } + /// } + /// + /// #[derive(Debug)] + /// struct Child { + /// parent: Parent, + /// name: String, + /// } + /// + /// impl Child { + /// // Pretend that this takes a lot of resources to evaluate. + /// fn an_expensive_computation(&self) -> Option<&str> { + /// Some(&self.name) + /// } + /// } + /// + /// impl std::fmt::Display for Child { + /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// write!(f, "{} failed: \n {}", self.name, self.parent) + /// } + /// } + /// + /// impl std::error::Error for Child { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// // In general, we don't know if this call will provide + /// // a `str` reference or not... + /// self.parent.provide(request); + /// + /// // ...so we check to see if the `&str` is needed before + /// // we run our expensive computation. + /// if request.would_be_satisfied_by_ref_of::() { + /// if let Some(v) = self.an_expensive_computation() { + /// request.provide_ref::(v); + /// } + /// } + /// + /// // The request will be satisfied now, regardless of if + /// // the parent provided the reference or we did. + /// assert!(!request.would_be_satisfied_by_ref_of::()); + /// } + /// } + /// + /// let parent = Parent(Some("parent".into())); + /// let child = Child { parent, name: "child".into() }; + /// assert_eq!(Some("parent"), request_ref::(&child)); + /// + /// let parent = Parent(None); + /// let child = Child { parent, name: "child".into() }; + /// assert_eq!(Some("child"), request_ref::(&child)); + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn would_be_satisfied_by_ref_of(&self) -> bool + where + T: ?Sized + 'static, + { + self.would_be_satisfied_by::>>() + } + + fn would_be_satisfied_by(&self) -> bool + where + I: tags::Type<'a>, + { + self.0.would_be_satisfied_by::() + } +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<'a> Debug for Request<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Request").finish_non_exhaustive() + } +} + +/// Base case for [IntoMultiRequest]. +#[unstable(feature = "error_generic_member_access", issue = "99301")] +#[derive(Copy, Clone, Debug)] +pub struct EmptyMultiRequestBuilder; + +/// Case of [IntoMultiRequest] that retrieves a type by value. +/// +/// Create via [MultiRequestBuilder::with_value]. +#[unstable(feature = "error_generic_member_access", issue = "99301")] +#[derive(Copy, Clone, Debug)] +pub struct ChainValMultiRequestBuilder(PhantomData<(T, NEXT)>); + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +#[derive(Copy, Clone, Debug)] +/// Case of [IntoMultiRequest] that retrieves a type by value. +/// +/// Create via [MultiRequestBuilder::with_ref]. +pub struct ChainRefMultiRequestBuilder(PhantomData<(*const T, NEXT)>); + +/// Internal trait for types that represent a request for multiple provided +/// traits in parallel. +/// +/// There is no need to use this trait directly, use [MultiRequestBuilder] instead. +#[unstable(feature = "error_generic_member_access", issue = "99301")] +#[allow(private_bounds)] +pub trait IntoMultiRequest: private::IntoMultiRequestInner + 'static {} + +mod private { + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(private_bounds)] + pub trait IntoMultiRequestInner { + #[unstable(feature = "error_generic_member_access", issue = "99301")] + type Request<'a>: super::Erased<'a> + MultiResponseInner<'a> + where + Self: 'a; + #[unstable(feature = "error_generic_member_access", issue = "99301")] + fn get_request<'a>() -> Self::Request<'a>; + } + + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(private_bounds)] + pub trait MultiResponseInner<'a> { + fn consume_with(&mut self, fulfil: impl FnOnce(I::Reified)) -> &mut Self + where + I: super::tags::Type<'a>; + } +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl IntoMultiRequest for EmptyMultiRequestBuilder {} +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl private::IntoMultiRequestInner for EmptyMultiRequestBuilder { + type Request<'a> = EmptyMultiResponse; + + fn get_request<'a>() -> Self::Request<'a> { + EmptyMultiResponse + } +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl IntoMultiRequest for ChainValMultiRequestBuilder +where + T: 'static, + NEXT: IntoMultiRequest, +{ +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl private::IntoMultiRequestInner for ChainValMultiRequestBuilder +where + T: 'static, + NEXT: IntoMultiRequest, +{ + type Request<'a> = ChainValMultiResponse<'a, T, NEXT::Request<'a>>; + + fn get_request<'a>() -> Self::Request<'a> { + ChainValMultiResponse { + inner: ChainMultiResponse { cur: None, next: NEXT::get_request(), marker: PhantomData }, + } + } +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl IntoMultiRequest for ChainRefMultiRequestBuilder +where + T: ?Sized + 'static, + NEXT: IntoMultiRequest, +{ +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl private::IntoMultiRequestInner for ChainRefMultiRequestBuilder +where + T: ?Sized + 'static, + NEXT: IntoMultiRequest, +{ + type Request<'a> = ChainRefMultiResponse<'a, T, NEXT::Request<'a>>; + + fn get_request<'a>() -> Self::Request<'a> { + ChainRefMultiResponse { + inner: ChainMultiResponse { cur: None, next: NEXT::get_request(), marker: PhantomData }, + } + } +} + +/// A response from an empty [MultiRequestBuilder::request] +#[unstable( + feature = "error_generic_member_access_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +#[derive(Debug)] +pub struct EmptyMultiResponse; + +#[derive(Debug)] +struct ChainMultiResponse<'a, I, NEXT> +where + I: tags::Type<'a>, +{ + cur: Option, + next: NEXT, + // Lifetime is invariant because it is used in an associated type + marker: PhantomData<*mut &'a ()>, +} + +/// A response from a [MultiRequestBuilder::request] after calling [MultiRequestBuilder::with_value]. +#[unstable( + feature = "error_generic_member_access_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +#[derive(Debug)] +pub struct ChainValMultiResponse<'a, T, NEXT> +where + T: 'static, +{ + inner: ChainMultiResponse<'a, tags::Value, NEXT>, +} + +/// A response from a [MultiRequestBuilder::request] after calling [MultiRequestBuilder::with_ref]. +#[unstable( + feature = "error_generic_member_access_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +#[derive(Debug)] +pub struct ChainRefMultiResponse<'a, T, NEXT> +where + T: 'static + ?Sized, +{ + inner: ChainMultiResponse<'a, tags::Ref>, NEXT>, +} + +/// A response from a [MultiRequestBuilder]. The types returned from +/// [MultiRequestBuilder::request] implement this trait. +#[unstable(feature = "error_generic_member_access", issue = "99301")] +#[allow(private_bounds)] +pub trait MultiResponse<'a> { + /// Retrieve a reference with the type `R` from this multi response, + /// + /// The reference will be passed to `fulfil` if present. This function + /// consumes the reference, so the next call to `retrieve_ref` + /// with the same type will not call `fulfil`. + /// + /// This function returns `self` to allow easy chained use. + /// + /// # Examples + /// + /// When requesting only a single type, it is better to use + /// [request_ref] - this is only an example. + /// + /// ``` + /// #![feature(error_generic_member_access)] + /// use core::error::{Error, MultiRequestBuilder, MultiResponse}; + /// + /// fn get_str(e: &dyn Error) -> Option<&str> { + /// let mut result = None; + /// MultiRequestBuilder::new() + /// .with_ref::() + /// .request(e) + /// .retrieve_ref(|res| result = Some(res)); + /// result + /// } + /// ``` + fn retrieve_ref(&mut self, fulfil: impl FnOnce(&'a R)) -> &mut Self + where + R: ?Sized + 'static; + + /// Retrieve a value with the type `V` from this multi response, + /// + /// The value will be passed to `fulfil` if present. This function + /// consumes the value, so the next call to `retrieve_value` + /// with the same type will not call `fulfil`. + /// + /// This function returns `self` to allow easy chained use. + /// + /// # Examples + /// + /// When requesting only a single type, it is better to use + /// [request_value] - this is only an example. + /// + /// ``` + /// #![feature(error_generic_member_access)] + /// use core::error::{Error, MultiRequestBuilder, MultiResponse}; + /// + /// fn get_string(e: &dyn Error) -> Option { + /// let mut result = None; + /// MultiRequestBuilder::new() + /// .with_value::() + /// .request(e) + /// .retrieve_value(|res| result = Some(res)); + /// result + /// } + /// ``` + fn retrieve_value(&mut self, fulfil: impl FnOnce(V)) -> &mut Self + where + V: 'static; +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<'a, T: private::MultiResponseInner<'a>> MultiResponse<'a> for T { + fn retrieve_ref(&mut self, fulfil: impl FnOnce(&'a R)) -> &mut Self + where + R: ?Sized + 'static, + { + self.consume_with::>>(fulfil) + } + + fn retrieve_value(&mut self, fulfil: impl FnOnce(V)) -> &mut Self + where + V: 'static, + { + self.consume_with::>(fulfil) + } +} +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<'a> private::MultiResponseInner<'a> for EmptyMultiResponse { + #[allow(private_bounds)] + fn consume_with(&mut self, _fulfil: impl FnOnce(I::Reified)) -> &mut Self + where + I: tags::Type<'a>, + { + self + } +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<'a, J, NEXT> private::MultiResponseInner<'a> for ChainMultiResponse<'a, J, NEXT> +where + J: tags::Type<'a>, + NEXT: private::MultiResponseInner<'a>, +{ + fn consume_with(&mut self, fulfil: impl FnOnce(I::Reified)) -> &mut Self + where + I: tags::Type<'a>, + { + // SAFETY: cast is safe because type ids are equal implies types are equal + unsafe { + // this `if` is const. Equality is always decidable for tag types, but we can't prove that to the type system. + if TypeId::of::() == TypeId::of::() { + // cast is safe because type ids are equal + let cur = + &mut *(&mut self.cur as *mut Option as *mut Option); + if let Some(val) = cur.take() { + fulfil(val); + return self; + } + } + } + self.next.consume_with::(fulfil); + self + } +} +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<'a, T, NEXT> private::MultiResponseInner<'a> for ChainValMultiResponse<'a, T, NEXT> +where + T: 'static, + NEXT: private::MultiResponseInner<'a>, +{ + #[allow(private_bounds)] + fn consume_with(&mut self, fulfil: impl FnOnce(I::Reified)) -> &mut Self + where + I: tags::Type<'a>, + { + self.inner.consume_with::(fulfil); + self + } +} +#[unstable(feature = "error_generic_member_access", issue = "99301")] +// SAFETY: delegates to inner impl +unsafe impl<'a, T, NEXT> Erased<'a> for ChainValMultiResponse<'a, T, NEXT> +where + T: 'static, + NEXT: Erased<'a>, +{ + unsafe fn consume_closure( + this: impl FnOnce() -> *const Self, + type_id: TypeId, + ) -> Option> { + // SAFETY: delegation + unsafe { ChainMultiResponse::consume_closure(move || &raw const (*this()).inner, type_id) } + } + + unsafe fn consume(self: *const Self, type_id: TypeId) -> Option> { + // SAFETY: same safety conditions + unsafe { Self::consume_closure(move || self, type_id) } + } +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<'a, T, NEXT> private::MultiResponseInner<'a> for ChainRefMultiResponse<'a, T, NEXT> +where + T: 'static + ?Sized, + NEXT: private::MultiResponseInner<'a>, +{ + #[allow(private_bounds)] + fn consume_with(&mut self, fulfil: impl FnOnce(I::Reified)) -> &mut Self + where + I: tags::Type<'a>, + { + self.inner.consume_with::(fulfil); + self + } +} +#[unstable(feature = "error_generic_member_access", issue = "99301")] +// SAFETY: delegates to inner impl +unsafe impl<'a, T, NEXT> Erased<'a> for ChainRefMultiResponse<'a, T, NEXT> +where + T: 'static + ?Sized, + NEXT: Erased<'a>, +{ + unsafe fn consume_closure( + this: impl FnOnce() -> *const Self, + type_id: TypeId, + ) -> Option> { + // SAFETY: delegation + unsafe { ChainMultiResponse::consume_closure(move || &raw const (*this()).inner, type_id) } + } + + unsafe fn consume(self: *const Self, type_id: TypeId) -> Option> { + // SAFETY: same safety conditions + unsafe { Self::consume_closure(move || self, type_id) } + } +} + +unsafe impl<'a> Erased<'a> for EmptyMultiResponse { + unsafe fn consume_closure( + _this: impl FnOnce() -> *const Self, + _type_id: TypeId, + ) -> Option> { + None + } + + unsafe fn consume(self: *const Self, type_id: TypeId) -> Option> { + // SAFETY: same safety conditions + unsafe { Self::consume_closure(move || self, type_id) } + } +} + +unsafe impl<'a, I, NEXT> Erased<'a> for ChainMultiResponse<'a, I, NEXT> +where + I: tags::Type<'a>, + NEXT: Erased<'a>, +{ + unsafe fn consume_closure( + this: impl FnOnce() -> *const Self, + type_id: TypeId, + ) -> Option> { + // SAFETY: dereferencing *this guaranteed to be valid. + unsafe { + if type_id == TypeId::of::() { + // SAFETY: returning an Option as requested + Some( + NonNull::new_unchecked((&raw const (*this()).cur) as *mut Option) + .cast(), + ) + } else { + // SAFETY: safe to delegate consume_closure + NEXT::consume_closure(move || &raw const (*this()).next, type_id) + } + } + } + + unsafe fn consume(self: *const Self, type_id: TypeId) -> Option> { + // SAFETY: same safety conditions + unsafe { Self::consume_closure(move || self, type_id) } + } +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +#[derive(Copy, Clone, Debug)] +/// A [MultiRequestBuilder] is used to request multiple types from an [Error] at once. +/// +/// Requesting a type from an [Error] is fairly fast - normally faster than formatting +/// an error - but if you need to request many different error types, it is better +/// to use this API to request them at once. +/// +/// # Examples +/// +/// ``` +/// #![feature(error_generic_member_access)] +/// use core::fmt; +/// use core::error::{Error, MultiResponse, Request}; +/// +/// #[derive(Debug)] +/// struct MyError { +/// str_field: &'static str, +/// val_field: MyExitCode, +/// } +/// +/// #[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// struct MyExitCode(u32); +/// +/// impl fmt::Display for MyError { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "Example Error") +/// } +/// } +/// +/// impl Error for MyError { +/// fn provide<'a>(&'a self, request: &mut Request<'a>) { +/// request +/// .provide_ref::(self.str_field) +/// .provide_value::(self.val_field); +/// } +/// } +/// +/// fn main() { +/// let e = MyError { +/// str_field: "hello", +/// val_field: MyExitCode(3), +/// }; +/// +/// let mut str_val = None; +/// let mut exit_code_val = None; +/// let mut string_val = None; +/// let mut value = core::error::MultiRequestBuilder::new() +/// // request by reference +/// .with_ref::() +/// // and by value +/// .with_value::() +/// // and some type that isn't in the error +/// .with_value::() +/// .request(&e) +/// // The error has str by reference +/// .retrieve_ref::(|val| str_val = Some(val)) +/// // The error has MyExitCode by value +/// .retrieve_value::(|val| exit_code_val = Some(val)) +/// // The error does not have a string field, consume will not be called +/// .retrieve_value::(|val| string_val = Some(val)); +/// +/// assert_eq!(exit_code_val, Some(MyExitCode(3))); +/// assert_eq!(str_val, Some("hello")); +/// assert_eq!(string_val, None); +/// } +/// ``` +pub struct MultiRequestBuilder { + inner: PhantomData, +} + +impl MultiRequestBuilder { + /// Create a new [MultiRequestBuilder] + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn new() -> Self { + MultiRequestBuilder { inner: PhantomData } + } +} + +impl MultiRequestBuilder { + /// Create a [MultiRequestBuilder] that requests a value. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_generic_member_access)] + /// use core::error::{Error, MultiRequestBuilder, MultiResponse}; + /// + /// fn get_string(e: &dyn Error) -> Option { + /// let mut result = None; + /// MultiRequestBuilder::new() + /// .with_value::() + /// .request(e) + /// .retrieve_value(|res| result = Some(res)); + /// result + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn with_value( + self, + ) -> MultiRequestBuilder> { + MultiRequestBuilder { inner: PhantomData } + } + + /// Create a [MultiRequestBuilder] that requests a reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_generic_member_access)] + /// use core::error::{Error, MultiRequestBuilder, MultiResponse}; + /// + /// fn get_string(e: &dyn Error) -> Option { + /// let mut result = None; + /// MultiRequestBuilder::new() + /// .with_value::() + /// .request(e) + /// .retrieve_value(|res| result = Some(res)); + /// result + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn with_ref( + self, + ) -> MultiRequestBuilder> { + MultiRequestBuilder { inner: PhantomData } + } + + /// Request provided values from a given error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request<'a>(self, err: &'a (impl Error + ?Sized)) -> impl MultiResponse<'a> { + let mut tagged = Tagged::new_virtual(INNER::get_request()); + err.provide(tagged.as_request()); + tagged.value + } +} + +// special type id, used to mark a `Tagged` where calls should be done virtually +struct ErasedMarker; + +/////////////////////////////////////////////////////////////////////////////// +// Type tags +/////////////////////////////////////////////////////////////////////////////// + +pub(crate) mod tags { + //! Type tags are used to identify a type using a separate value. This module includes type tags + //! for some very common types. + //! + //! Currently type tags are not exposed to the user. But in the future, if you want to use the + //! Request API with more complex types (typically those including lifetime parameters), you + //! will need to write your own tags. + + use crate::any::TypeId; + use crate::marker::PhantomData; + use crate::ptr::NonNull; + + /// This trait is implemented by specific tag types in order to allow + /// describing a type which can be requested for a given lifetime `'a`. + /// + /// A few example implementations for type-driven tags can be found in this + /// module, although crates may also implement their own tags for more + /// complex types with internal lifetimes. + pub(crate) unsafe trait Type<'a>: Sized + 'static { + /// The type of values which may be tagged by this tag for the given + /// lifetime. + type Reified: 'a; + + // This requires `sink` to be a valid pointer, and if `type_id == TypeId::of::`` and + // the function returns Some, returns a pointer with the same lifetime and + // mutability as `sink` to `Option<>::Reified>`. + unsafe fn consume( + sink: *const super::TaggedOption<'a, Self>, + type_id: TypeId, + ) -> Option>; + } + + /// Similar to the [`Type`] trait, but represents a type which may be unsized (i.e., has a + /// `?Sized` bound). E.g., `str`. + pub(crate) trait MaybeSizedType<'a>: Sized + 'static { + type Reified: 'a + ?Sized; + } + + impl<'a, T: Type<'a>> MaybeSizedType<'a> for T { + type Reified = T::Reified; + } + + /// Type-based tag for types bounded by `'static`, i.e., with no borrowed elements. + #[derive(Debug)] + pub(crate) struct Value(PhantomData); + + unsafe impl<'a, T: 'static> Type<'a> for Value { + type Reified = T; + + unsafe fn consume( + sink: *const super::TaggedOption<'a, Self>, + type_id: TypeId, + ) -> Option> { + // SAFETY: sink is a valid pointer + unsafe { + if (*sink).0.is_none() && type_id == TypeId::of::() { + Some(NonNull::new_unchecked(&raw const (*sink).0 as *mut Self::Reified).cast()) + } else { + None + } + } + } + } + + /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `?Sized` bound). + #[derive(Debug)] + pub(crate) struct MaybeSizedValue(PhantomData); + + impl<'a, T: ?Sized + 'static> MaybeSizedType<'a> for MaybeSizedValue { + type Reified = T; + } + + /// Type-based tag for reference types (`&'a T`, where T is represented by + /// `>::Reified`. + #[derive(Debug)] + pub(crate) struct Ref(PhantomData); + + unsafe impl<'a, I: MaybeSizedType<'a>> Type<'a> for Ref + where + I::Reified: 'static, + { + type Reified = &'a I::Reified; + + unsafe fn consume( + sink: *const super::TaggedOption<'a, Self>, + type_id: TypeId, + ) -> Option> { + // SAFETY: sink is a valid pointer + unsafe { + if (*sink).0.is_none() && type_id == TypeId::of::() { + Some(NonNull::new_unchecked(&raw const (*sink).0 as *mut Self::Reified).cast()) + } else { + None + } + } + } + } +} + +/// An `Option` with a type tag `I`. +/// +/// Since this struct implements `Erased`, the type can be erased to make a dynamically typed +/// option. The type can be checked dynamically using `Tagged::tag_id` and since this is statically +/// checked for the concrete type, there is some degree of type safety. +#[repr(transparent)] +pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option); + +impl<'a, I: tags::Type<'a>> Tagged> { + fn new_concrete() -> Self { + Tagged { tag_id: TypeId::of::(), value: TaggedOption::<'a, I>(None) } + } +} + +impl<'a, T: Erased<'a>> Tagged { + fn new_virtual(value: T) -> Self { + Tagged { tag_id: TypeId::of::(), value } + } +} + +impl<'a, T: Erased<'a>> Tagged { + pub(crate) fn as_request(&mut self) -> &mut Request<'a> { + let erased = self as &mut Tagged + 'a>; + // SAFETY: transmuting `&mut Tagged + 'a>` to `&mut Request<'a>` is safe since + // `Request` is repr(transparent). + unsafe { &mut *(erased as *mut Tagged> as *mut Request<'a>) } + } +} + +/// Represents a type-erased but identifiable object. +/// +/// This trait is exclusively implemented by the `TaggedOption` type. +unsafe trait Erased<'a>: 'a { + // This requires `self` to be a valid pointer, and if `type_id == TypeId::of::`` and + // the function returns Some, returns a pointer with the same lifetime and + // mutability as `self` to `Option<>::Reified>`. + + // in consume_closure, `self = this()`. + // The optimizer does not do the branch table optimization if your function takes + // a self pointer, do the closure hack to work around it + unsafe fn consume_closure( + this: impl FnOnce() -> *const Self, + type_id: TypeId, + ) -> Option> + where + Self: Sized; + + unsafe fn consume(self: *const Self, type_id: TypeId) -> Option>; +} + +unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> { + // This impl is not really used since TaggedOptions are not virtual, but leave it here + unsafe fn consume_closure( + this: impl FnOnce() -> *const Self, + type_id: TypeId, + ) -> Option> { + // SAFETY: this is a valid pointer + unsafe { I::consume(&*this(), type_id) } + } + + unsafe fn consume(self: *const Self, type_id: TypeId) -> Option> { + // SAFETY: same safety conditions + unsafe { Self::consume_closure(move || self, type_id) } + } +} + +struct Tagged { + tag_id: TypeId, + value: E, +} + +impl<'a> Tagged + 'a> { + fn is_virtual(&self) -> bool { + self.tag_id == TypeId::of::() + } + + #[inline] + fn would_be_satisfied_by(&self) -> bool + where + I: tags::Type<'a>, + { + if self.is_virtual() { + // consume returns None if the space is not satisfied + // SAFETY: `&raw const self.value` is valid + unsafe { (&raw const self.value).consume(TypeId::of::()).is_some() } + } else { + matches!(self.downcast::(), Some(TaggedOption(None))) + } + } + + #[inline] + fn provide(&mut self, value: I::Reified) + where + I: tags::Type<'a>, + { + if self.is_virtual() { + // SAFETY: consume_mut is defined to return either None or Some(I::Reified) + unsafe { + if let Some(res) = (&raw const self.value).consume(TypeId::of::()) { + let mut ptr: NonNull> = res.cast(); + // cast is fine since consume_mut returns a pointer to an Option + // could use `ptr::write` here, but this is not expected to be important enough + *ptr.as_mut() = Some(value); + } + } + } else { + if let Some(res @ TaggedOption(None)) = self.downcast_mut::() { + res.0 = Some(value); + } + } + } + + #[inline] + fn provide_with(&mut self, fulfil: impl FnOnce() -> I::Reified) + where + I: tags::Type<'a>, + { + if self.is_virtual() { + // SAFETY: consume_mut is defined to return either None or Some(I::Reified) + unsafe { + if let Some(res) = (&raw const self.value).consume(TypeId::of::()) { + let mut ptr: NonNull> = res.cast(); + // cast is fine since consume_mut returns a pointer to an Option + // could use `ptr::write` here, but this is not expected to be important enough + *ptr.as_mut() = Some(fulfil()); + } + } + } else { + if let Some(res @ TaggedOption(None)) = self.downcast_mut::() { + res.0 = Some(fulfil()); + } + } + } + + /// Returns some reference to the dynamic value if it is tagged with `I`, + /// or `None` otherwise. + #[inline] + fn downcast(&self) -> Option<&TaggedOption<'a, I>> + where + I: tags::Type<'a>, + { + if self.tag_id == TypeId::of::() { + // SAFETY: Just checked whether we're pointing to an I. + Some(&unsafe { &*(self as *const Self).cast::>>() }.value) + } else { + None + } + } + + /// Returns some mutable reference to the dynamic value if it is tagged with `I`, + /// or `None` otherwise. + #[inline] + fn downcast_mut(&mut self) -> Option<&mut TaggedOption<'a, I>> + where + I: tags::Type<'a>, + { + if self.tag_id == TypeId::of::() { + Some( + // SAFETY: Just checked whether we're pointing to an I. + &mut unsafe { &mut *(self as *mut Self).cast::>>() } + .value, + ) + } else { + None + } + } +} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a1c7990f2311d..0673e57d35e07 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -95,6 +95,7 @@ // // Library features: // tidy-alphabetical-start +#![feature(arbitrary_self_types_pointers)] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(bigint_helper_methods)] diff --git a/library/coretests/tests/error.rs b/library/coretests/tests/error.rs index 996566d3848bd..645f9a989e366 100644 --- a/library/coretests/tests/error.rs +++ b/library/coretests/tests/error.rs @@ -12,12 +12,23 @@ impl std::fmt::Display for SomeConcreteType { } } +struct Invalid; +#[derive(Debug, PartialEq, Eq)] +struct Valid; + impl std::error::Error for SomeConcreteType { fn provide<'a>(&'a self, request: &mut Request<'a>) { request .provide_ref::(&self.some_string) .provide_ref::(&self.some_string) - .provide_value_with::(|| "bye".to_owned()); + .provide_value_with::(|| "bye".to_owned()) + .provide_value_with::(|| panic!("should not be called")); + if request.would_be_satisfied_by_ref_of::() { + panic!("should not be satisfied"); + } + if request.would_be_satisfied_by_ref_of::() { + request.provide_ref(&Valid); + } } } @@ -29,6 +40,7 @@ fn test_error_generic_member_access() { assert_eq!(request_ref::(&*obj).unwrap(), "hello"); assert_eq!(request_value::(&*obj).unwrap(), "bye"); assert_eq!(request_value::(&obj), None); + assert_eq!(request_ref::(&obj), Some(&Valid)); } // Test the Error.provide and request mechanisms with a by-reference trait object. @@ -39,6 +51,7 @@ fn test_request_constructor() { assert_eq!(request_ref::(&*obj).unwrap(), "hello"); assert_eq!(request_value::(&*obj).unwrap(), "bye"); assert_eq!(request_value::(&obj), None); + assert_eq!(request_ref::(&obj), Some(&Valid)); } // Test the Error.provide and request mechanisms with a boxed trait object. @@ -49,6 +62,7 @@ fn test_error_generic_member_access_boxed() { assert_eq!(request_ref::(&*obj).unwrap(), "hello"); assert_eq!(request_value::(&*obj).unwrap(), "bye"); + assert_eq!(request_ref::(&*obj), Some(&Valid)); // NOTE: Box only implements Error when E: Error + Sized, which means we can't pass a // Box to request_value. @@ -63,4 +77,58 @@ fn test_error_generic_member_access_concrete() { assert_eq!(request_ref::(&obj).unwrap(), "hello"); assert_eq!(request_value::(&obj).unwrap(), "bye"); assert_eq!(request_value::(&obj), None); + assert_eq!(request_ref::(&obj), Some(&Valid)); +} + +#[test] +fn test_error_combined_access_concrete() { + let obj = SomeConcreteType { some_string: "hello".to_owned() }; + + let mut string_val = None; + let mut string_ref = None; + let mut u8_val = None; + let mut valid_ref = None; + + MultiRequestBuilder::new() + .with_value::() + .with_ref::() + .with_value::() + .with_ref::() + .request(&obj) + .retrieve_value::(|val| string_val = Some(val)) + .retrieve_ref::(|val| string_ref = Some(val)) + .retrieve_value::(|val| u8_val = Some(val)) + .retrieve_ref::(|val| valid_ref = Some(val)); + + assert_eq!(string_ref.unwrap(), "hello"); + assert_eq!(string_val.unwrap(), "bye"); + assert_eq!(u8_val, None); + assert_eq!(valid_ref.unwrap(), Valid); +} + +#[test] +fn test_error_combined_access_dyn() { + let obj = SomeConcreteType { some_string: "hello".to_owned() }; + let obj: &dyn Error = &obj; + + let mut string_val = None; + let mut string_ref = None; + let mut u8_val = None; + let mut valid_ref = None; + + MultiRequestBuilder::new() + .with_value::() + .with_ref::() + .with_value::() + .with_ref::() + .request(&obj) + .retrieve_value::(|val| string_val = Some(val)) + .retrieve_ref::(|val| string_ref = Some(val)) + .retrieve_value::(|val| u8_val = Some(val)) + .retrieve_ref::(|val| valid_ref = Some(val)); + + assert_eq!(string_ref.unwrap(), "hello"); + assert_eq!(string_val.unwrap(), "bye"); + assert_eq!(u8_val, None); + assert_eq!(valid_ref.unwrap(), Valid); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 7f4dad873cd6f..440f9c0a8f60a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -5871,6 +5871,18 @@ The tracking issue for this feature is: [#99301] [#99301]: https://github.com/rust-lang/rust/issues/99301 +------------------------ +"##, + default_severity: Severity::Allow, + warn_since: None, + deny_since: None, + }, + Lint { + label: "error_generic_member_access_internals", + description: r##"# `error_generic_member_access_internals` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + ------------------------ "##, default_severity: Severity::Allow, diff --git a/tests/codegen-llvm/error-provide.rs b/tests/codegen-llvm/error-provide.rs index 7f091e34359e4..ba84c5f2c8d33 100644 --- a/tests/codegen-llvm/error-provide.rs +++ b/tests/codegen-llvm/error-provide.rs @@ -3,6 +3,10 @@ //@ compile-flags: -Copt-level=3 #![crate_type = "lib"] #![feature(error_generic_member_access)] + +extern crate core; + +use core::error::MultiResponse; use std::error::Request; use std::fmt; @@ -30,17 +34,20 @@ impl fmt::Display for MyError { } impl std::error::Error for MyError { - // CHECK-LABEL: @provide #[no_mangle] fn provide<'a>(&'a self, request: &mut Request<'a>) { - // LLVM should be able to optimize multiple .provide_* calls into a switch table - // and eliminate redundant ones, rather than compare one-by-one. - - // CHECK-NEXT: start: - // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr - // CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [ - // CHECK-COUNT-3: i128 {{.*}}, label %{{.*}} - // CHECK-NEXT: ] + // In an ideal world, LLVM would be able to generate a jump table here. + // Currently it can not, mostly because it can't prove that the tag id + // is not modified. However, this shouldn't matter much since this + // API shouldn't be called many times - when requesting a large number + // of items, MultiRequestBuilder should be used. + // + // We could make a MIR optimization pass that flattens + // the reads of the tag id - this is sound, since it is mutably borrowed, + // but this has a fairly low cost/benefit ratio - `provide` should + // only be called O(1) times per error constructed, and it's already + // not much slower than constructing the error (and much faster + // if an allocation, backtrace or formatting is involved). request .provide_ref::(&self.backtrace1) .provide_ref::(&self.other) @@ -48,3 +55,35 @@ impl std::error::Error for MyError { .provide_ref::(&self.backtrace3); } } + +pub fn provide_multi( + e: &dyn std::error::Error, +) -> (Option<&[u8; 0]>, Option<&[u8; 1]>, Option<&[u8; 2]>) { + let (mut bt1, mut bt2, mut bt3) = (None, None, None); + let mut value = core::error::MultiRequestBuilder::new() + .with_ref::<[u8; 0]>() + .with_ref::<[u8; 1]>() + .with_ref::<[u8; 2]>() + .with_ref::<[u8; 3]>() + .with_ref::<[u8; 4]>() + .with_ref::<[u8; 5]>() + .with_ref::<[u8; 6]>() + .with_ref::<[u8; 7]>() + .request(e) + .retrieve_ref(|b| bt1 = Some(b)) + .retrieve_ref(|b| bt2 = Some(b)) + .retrieve_ref(|b| bt3 = Some(b)); + (bt1, bt2, bt3) +} + +// Check that the virtual function generated has a switch + +// CHECK: define {{.*}}4core5error7provide{{.*}}21ChainRefMultiResponse +// CHECK-NEXT: start: +// CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i128, ptr +// CHECK-NEXT: switch i128 %[[SCRUTINEE]], label %{{.*}} [ +// The request we write has 8 arms. However, LLVM puts the "bottom-most" 3 arms in +// a separate branch, before it produces a switch. This still leaves us with +// O(log n) performance [LLVM generates a binary tree for ] +// CHECK-COUNT-5: i128 {{.*}}, label %{{.*}} +// CHECK-NEXT: ] diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr index d2f780bdbcb43..fde9f332f54ac 100644 --- a/tests/ui/span/issue-71363.stderr +++ b/tests/ui/span/issue-71363.stderr @@ -10,7 +10,7 @@ help: the trait `std::fmt::Display` is not implemented for `MyError` 3 | struct MyError; | ^^^^^^^^^^^^^^ note: required by a bound in `std::error::Error` - --> $SRC_DIR/core/src/error.rs:LL:COL + --> $SRC_DIR/core/src/error/mod.rs:LL:COL error[E0277]: `MyError` doesn't implement `Debug` --> $DIR/issue-71363.rs:4:28 @@ -20,7 +20,7 @@ error[E0277]: `MyError` doesn't implement `Debug` | = note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError` note: required by a bound in `std::error::Error` - --> $SRC_DIR/core/src/error.rs:LL:COL + --> $SRC_DIR/core/src/error/mod.rs:LL:COL help: consider annotating `MyError` with `#[derive(Debug)]` | 3 + #[derive(Debug)]