diff --git a/build.rs b/build.rs index 004dfb0..85d1198 100644 --- a/build.rs +++ b/build.rs @@ -4,23 +4,40 @@ use std::path::Path; use std::process::{Command, ExitStatus, Stdio}; use std::str; -// This code exercises the surface area that we expect of the Provider API. If -// the current toolchain is able to compile it, then thiserror is able to use -// providers for backtrace support. +// This code exercises the surface area that we expect of the Error trait's generic member access. +// If the current toolchain is able to compile it, then thiserror is able to offer backtrace +// support via generic member access. const PROBE: &str = r#" - #![feature(provide_any)] + #![feature(error_generic_member_access)] - use std::any::{Demand, Provider}; + use std::any::Request; - fn _f<'a, P: Provider>(p: &'a P, demand: &mut Demand<'a>) { - p.provide(demand); + #[derive(Debug)] + struct ErrorWithGenericMemberAccess { + it: u32, + } + + impl std::fmt::Display for ErrorWithGenericMemberAccess { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ErrorWithGenericMemberAccess") + } + } + + impl std::error::Error for ErrorWithGenericMemberAccess { + fn provide<'a>(&'a self, request: &mut Request<'a>) { + request.provide_value::(self.it); + } + } + + fn _get_u32(e: &dyn std::error::Error) -> Option { + e.request_value::() } "#; fn main() { match compile_probe() { - Some(status) if status.success() => println!("cargo:rustc-cfg=provide_any"), - _ => {} + Some(status) if status.success() => println!("cargo:rustc-cfg=error_generic_member_access"), + _ => {}, } } diff --git a/impl/src/expand.rs b/impl/src/expand.rs index ef8eaf3..5e98dc3 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -60,19 +60,19 @@ fn impl_struct(input: Struct) -> TokenStream { }); let provide_method = input.backtrace_field().map(|backtrace_field| { - let demand = quote!(demand); + let request = quote!(request); let backtrace = &backtrace_field.member; let body = if let Some(source_field) = input.source_field() { let source = &source_field.member; let source_provide = if type_is_option(source_field.ty) { quote_spanned! {source.span()=> if let std::option::Option::Some(source) = &self.#source { - source.thiserror_provide(#demand); + source.provide(#request); } } } else { quote_spanned! {source.span()=> - self.#source.thiserror_provide(#demand); + self.#source.provide(#request); } }; let self_provide = if source == backtrace { @@ -80,32 +80,31 @@ fn impl_struct(input: Struct) -> TokenStream { } else if type_is_option(backtrace_field.ty) { Some(quote! { if let std::option::Option::Some(backtrace) = &self.#backtrace { - #demand.provide_ref::(backtrace); + #request.provide_ref::(backtrace); } }) } else { Some(quote! { - #demand.provide_ref::(&self.#backtrace); + #request.provide_ref::(&self.#backtrace); }) }; quote! { - use thiserror::__private::ThiserrorProvide; #source_provide #self_provide } } else if type_is_option(backtrace_field.ty) { quote! { if let std::option::Option::Some(backtrace) = &self.#backtrace { - #demand.provide_ref::(backtrace); + #request.provide_ref::(backtrace); } } } else { quote! { - #demand.provide_ref::(&self.#backtrace); + #request.provide_ref::(&self.#backtrace); } }; quote! { - fn provide<'_demand>(&'_demand self, #demand: &mut std::any::Demand<'_demand>) { + fn provide<'_request>(&'_request self, #request: &mut std::any::Request<'_request>) { #body } } @@ -246,7 +245,7 @@ fn impl_enum(input: Enum) -> TokenStream { }; let provide_method = if input.has_backtrace() { - let demand = quote!(demand); + let request = quote!(request); let arms = input.variants.iter().map(|variant| { let ident = &variant.ident; match (variant.backtrace_field(), variant.source_field()) { @@ -259,23 +258,23 @@ fn impl_enum(input: Enum) -> TokenStream { let source_provide = if type_is_option(source_field.ty) { quote_spanned! {source.span()=> if let std::option::Option::Some(source) = #varsource { - source.thiserror_provide(#demand); + source.provide(#request); } } } else { quote_spanned! {source.span()=> - #varsource.thiserror_provide(#demand); + #varsource.provide(#request); } }; let self_provide = if type_is_option(backtrace_field.ty) { quote! { if let std::option::Option::Some(backtrace) = backtrace { - #demand.provide_ref::(backtrace); + #request.provide_ref::(backtrace); } } } else { quote! { - #demand.provide_ref::(backtrace); + #request.provide_ref::(backtrace); } }; quote! { @@ -284,7 +283,6 @@ fn impl_enum(input: Enum) -> TokenStream { #source: #varsource, .. } => { - use thiserror::__private::ThiserrorProvide; #source_provide #self_provide } @@ -298,17 +296,16 @@ fn impl_enum(input: Enum) -> TokenStream { let source_provide = if type_is_option(source_field.ty) { quote_spanned! {backtrace.span()=> if let std::option::Option::Some(source) = #varsource { - source.thiserror_provide(#demand); + source.provide(#request); } } } else { quote_spanned! {backtrace.span()=> - #varsource.thiserror_provide(#demand); + #varsource.provide(#request); } }; quote! { #ty::#ident {#backtrace: #varsource, ..} => { - use thiserror::__private::ThiserrorProvide; #source_provide } } @@ -318,12 +315,12 @@ fn impl_enum(input: Enum) -> TokenStream { let body = if type_is_option(backtrace_field.ty) { quote! { if let std::option::Option::Some(backtrace) = backtrace { - #demand.provide_ref::(backtrace); + #request.provide_ref::(backtrace); } } } else { quote! { - #demand.provide_ref::(backtrace); + #request.provide_ref::(backtrace); } }; quote! { @@ -338,7 +335,7 @@ fn impl_enum(input: Enum) -> TokenStream { } }); Some(quote! { - fn provide<'_demand>(&'_demand self, #demand: &mut std::any::Demand<'_demand>) { + fn provide<'_request>(&'_request self, #request: &mut std::any::Request<'_request>) { #[allow(deprecated)] match self { #(#arms)* diff --git a/src/lib.rs b/src/lib.rs index d419ed1..3c5d01f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -236,12 +236,10 @@ clippy::return_self_not_must_use, clippy::wildcard_imports, )] -#![cfg_attr(provide_any, feature(provide_any))] +#![cfg_attr(error_generic_member_access, feature(error_generic_member_access))] mod aserror; mod display; -#[cfg(provide_any)] -mod provide; pub use thiserror_impl::*; @@ -250,6 +248,4 @@ pub use thiserror_impl::*; pub mod __private { pub use crate::aserror::AsDynError; pub use crate::display::{DisplayAsDisplay, PathAsDisplay}; - #[cfg(provide_any)] - pub use crate::provide::ThiserrorProvide; } diff --git a/src/provide.rs b/src/provide.rs deleted file mode 100644 index 524e743..0000000 --- a/src/provide.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::any::{Demand, Provider}; - -pub trait ThiserrorProvide: Sealed { - fn thiserror_provide<'a>(&'a self, demand: &mut Demand<'a>); -} - -impl ThiserrorProvide for T { - #[inline] - fn thiserror_provide<'a>(&'a self, demand: &mut Demand<'a>) { - self.provide(demand); - } -} - -pub trait Sealed {} -impl Sealed for T {} diff --git a/tests/test_backtrace.rs b/tests/test_backtrace.rs index 43f68b8..59a59f8 100644 --- a/tests/test_backtrace.rs +++ b/tests/test_backtrace.rs @@ -1,6 +1,6 @@ #![cfg_attr( thiserror_nightly_testing, - feature(error_generic_member_access, provide_any) + feature(error_generic_member_access) )] use thiserror::Error; @@ -19,7 +19,6 @@ pub struct InnerBacktrace { #[cfg(thiserror_nightly_testing)] pub mod structs { use super::{Inner, InnerBacktrace}; - use std::any; use std::backtrace::Backtrace; use std::error::Error; use std::sync::Arc; @@ -106,74 +105,54 @@ pub mod structs { let error = PlainBacktrace { backtrace: Backtrace::capture(), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = ExplicitBacktrace { backtrace: Backtrace::capture(), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = OptBacktrace { backtrace: Some(Backtrace::capture()), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = ArcBacktrace { backtrace: Arc::new(Backtrace::capture()), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = BacktraceFrom::from(Inner); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = CombinedBacktraceFrom::from(InnerBacktrace { backtrace: Backtrace::capture(), }); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = OptBacktraceFrom::from(Inner); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = ArcBacktraceFrom::from(Inner); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = AnyhowBacktrace { source: anyhow::Error::msg("..."), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = BoxDynErrorBacktrace { source: Box::new(PlainBacktrace { backtrace: Backtrace::capture(), }), }; - assert!(any::request_ref::(&error).is_some()); - } - - // https://github.com/dtolnay/thiserror/issues/185 -- std::error::Error and - // std::any::Provide both have a method called 'provide', so directly - // calling it from generated code could be ambiguous. - #[test] - fn test_provide_name_collision() { - use std::any::Provider; - - #[derive(Error, Debug)] - #[error("...")] - struct MyError { - #[source] - #[backtrace] - x: std::io::Error, - } - - let _: dyn Error; - let _: dyn Provider; + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); } } #[cfg(thiserror_nightly_testing)] pub mod enums { use super::{Inner, InnerBacktrace}; - use std::any; use std::backtrace::Backtrace; use std::sync::Arc; use thiserror::Error; @@ -259,36 +238,36 @@ pub mod enums { let error = PlainBacktrace::Test { backtrace: Backtrace::capture(), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = ExplicitBacktrace::Test { backtrace: Backtrace::capture(), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = OptBacktrace::Test { backtrace: Some(Backtrace::capture()), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = ArcBacktrace::Test { backtrace: Arc::new(Backtrace::capture()), }; - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = BacktraceFrom::from(Inner); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = CombinedBacktraceFrom::from(InnerBacktrace { backtrace: Backtrace::capture(), }); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = OptBacktraceFrom::from(Inner); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); let error = ArcBacktraceFrom::from(Inner); - assert!(any::request_ref::(&error).is_some()); + assert!((&error as &dyn std::error::Error).request_ref::().is_some()); } } diff --git a/tests/test_option.rs b/tests/test_option.rs index ed5287d..1228dd4 100644 --- a/tests/test_option.rs +++ b/tests/test_option.rs @@ -1,6 +1,6 @@ #![cfg_attr( thiserror_nightly_testing, - feature(error_generic_member_access, provide_any) + feature(error_generic_member_access) )] #[cfg(thiserror_nightly_testing)]