Merge pull request #182 from dtolnay/provider
Expose backtrace via generic member access
This commit is contained in:
commit
905680eee0
|
@ -59,45 +59,53 @@ fn impl_struct(input: Struct) -> TokenStream {
|
|||
}
|
||||
});
|
||||
|
||||
let backtrace_method = input.backtrace_field().map(|backtrace_field| {
|
||||
let provide_method = input.backtrace_field().map(|backtrace_field| {
|
||||
let demand = quote!(demand);
|
||||
let backtrace = &backtrace_field.member;
|
||||
let body = if let Some(source_field) = input.source_field() {
|
||||
let source = &source_field.member;
|
||||
let source_backtrace = if type_is_option(source_field.ty) {
|
||||
let source_provide = if type_is_option(source_field.ty) {
|
||||
quote_spanned! {source.span()=>
|
||||
self.#source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
|
||||
if let std::option::Option::Some(source) = &self.#source {
|
||||
source.as_dyn_error().provide(#demand);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {source.span()=>
|
||||
self.#source.as_dyn_error().backtrace()
|
||||
self.#source.as_dyn_error().provide(#demand);
|
||||
}
|
||||
};
|
||||
let combinator = if source == backtrace {
|
||||
source_backtrace
|
||||
let self_provide = if source == backtrace {
|
||||
None
|
||||
} else if type_is_option(backtrace_field.ty) {
|
||||
quote! {
|
||||
#source_backtrace.or(self.#backtrace.as_ref())
|
||||
}
|
||||
Some(quote! {
|
||||
if let std::option::Option::Some(backtrace) = &self.#backtrace {
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
quote! {
|
||||
std::option::Option::Some(#source_backtrace.unwrap_or(&self.#backtrace))
|
||||
}
|
||||
Some(quote! {
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(&self.#backtrace);
|
||||
})
|
||||
};
|
||||
quote! {
|
||||
use thiserror::__private::AsDynError;
|
||||
#combinator
|
||||
#source_provide
|
||||
#self_provide
|
||||
}
|
||||
} else if type_is_option(backtrace_field.ty) {
|
||||
quote! {
|
||||
self.#backtrace.as_ref()
|
||||
if let std::option::Option::Some(backtrace) = &self.#backtrace {
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
std::option::Option::Some(&self.#backtrace)
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(&self.#backtrace);
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
|
||||
fn provide<'_demand>(&'_demand self, #demand: &mut std::any::Demand<'_demand>) {
|
||||
#body
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +185,7 @@ fn impl_struct(input: Struct) -> TokenStream {
|
|||
#[allow(unused_qualifications)]
|
||||
impl #impl_generics #error_trait for #ty #ty_generics #error_where_clause {
|
||||
#source_method
|
||||
#backtrace_method
|
||||
#provide_method
|
||||
}
|
||||
#display_impl
|
||||
#from_impl
|
||||
|
@ -237,7 +245,8 @@ fn impl_enum(input: Enum) -> TokenStream {
|
|||
None
|
||||
};
|
||||
|
||||
let backtrace_method = if input.has_backtrace() {
|
||||
let provide_method = if input.has_backtrace() {
|
||||
let demand = quote!(demand);
|
||||
let arms = input.variants.iter().map(|variant| {
|
||||
let ident = &variant.ident;
|
||||
match (variant.backtrace_field(), variant.source_field()) {
|
||||
|
@ -247,22 +256,26 @@ fn impl_enum(input: Enum) -> TokenStream {
|
|||
let backtrace = &backtrace_field.member;
|
||||
let source = &source_field.member;
|
||||
let varsource = quote!(source);
|
||||
let source_backtrace = if type_is_option(source_field.ty) {
|
||||
let source_provide = if type_is_option(source_field.ty) {
|
||||
quote_spanned! {source.span()=>
|
||||
#varsource.as_ref().and_then(|source| source.as_dyn_error().backtrace())
|
||||
if let std::option::Option::Some(source) = #varsource {
|
||||
source.as_dyn_error().provide(#demand);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {source.span()=>
|
||||
#varsource.as_dyn_error().backtrace()
|
||||
#varsource.as_dyn_error().provide(#demand);
|
||||
}
|
||||
};
|
||||
let combinator = if type_is_option(backtrace_field.ty) {
|
||||
let self_provide = if type_is_option(backtrace_field.ty) {
|
||||
quote! {
|
||||
#source_backtrace.or(backtrace.as_ref())
|
||||
if let std::option::Option::Some(backtrace) = backtrace {
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
std::option::Option::Some(#source_backtrace.unwrap_or(backtrace))
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
|
@ -272,7 +285,8 @@ fn impl_enum(input: Enum) -> TokenStream {
|
|||
..
|
||||
} => {
|
||||
use thiserror::__private::AsDynError;
|
||||
#combinator
|
||||
#source_provide
|
||||
#self_provide
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,40 +295,50 @@ fn impl_enum(input: Enum) -> TokenStream {
|
|||
{
|
||||
let backtrace = &backtrace_field.member;
|
||||
let varsource = quote!(source);
|
||||
let source_backtrace = if type_is_option(source_field.ty) {
|
||||
let source_provide = if type_is_option(source_field.ty) {
|
||||
quote_spanned! {backtrace.span()=>
|
||||
#varsource.as_ref().and_then(|source| source.as_dyn_error().backtrace())
|
||||
if let std::option::Option::Some(source) = #varsource {
|
||||
source.as_dyn_error().provide(#demand);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {backtrace.span()=>
|
||||
#varsource.as_dyn_error().backtrace()
|
||||
#varsource.as_dyn_error().provide(#demand);
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
#ty::#ident {#backtrace: #varsource, ..} => {
|
||||
use thiserror::__private::AsDynError;
|
||||
#source_backtrace
|
||||
#source_provide
|
||||
}
|
||||
}
|
||||
}
|
||||
(Some(backtrace_field), _) => {
|
||||
let backtrace = &backtrace_field.member;
|
||||
let body = if type_is_option(backtrace_field.ty) {
|
||||
quote!(backtrace.as_ref())
|
||||
quote! {
|
||||
if let std::option::Option::Some(backtrace) = backtrace {
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote!(std::option::Option::Some(backtrace))
|
||||
quote! {
|
||||
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
#ty::#ident {#backtrace: backtrace, ..} => #body,
|
||||
#ty::#ident {#backtrace: backtrace, ..} => {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, _) => quote! {
|
||||
#ty::#ident {..} => std::option::Option::None,
|
||||
#ty::#ident {..} => {}
|
||||
},
|
||||
}
|
||||
});
|
||||
Some(quote! {
|
||||
fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
|
||||
fn provide<'_demand>(&'_demand self, #demand: &mut std::any::Demand<'_demand>) {
|
||||
#[allow(deprecated)]
|
||||
match self {
|
||||
#(#arms)*
|
||||
|
@ -420,7 +444,7 @@ fn impl_enum(input: Enum) -> TokenStream {
|
|||
#[allow(unused_qualifications)]
|
||||
impl #impl_generics #error_trait for #ty #ty_generics #error_where_clause {
|
||||
#source_method
|
||||
#backtrace_method
|
||||
#provide_method
|
||||
}
|
||||
#display_impl
|
||||
#(#from_impls)*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// FIXME: needs to be updated to provide_ref/request_ref API.
|
||||
#![cfg(any())]
|
||||
#![cfg_attr(thiserror_nightly_testing, feature(backtrace))]
|
||||
#![cfg_attr(
|
||||
thiserror_nightly_testing,
|
||||
feature(error_generic_member_access, provide_any)
|
||||
)]
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -18,8 +19,8 @@ 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;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -90,44 +91,44 @@ pub mod structs {
|
|||
let error = PlainBacktrace {
|
||||
backtrace: Backtrace::capture(),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = ExplicitBacktrace {
|
||||
backtrace: Backtrace::capture(),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = OptBacktrace {
|
||||
backtrace: Some(Backtrace::capture()),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = ArcBacktrace {
|
||||
backtrace: Arc::new(Backtrace::capture()),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = BacktraceFrom::from(Inner);
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = CombinedBacktraceFrom::from(InnerBacktrace {
|
||||
backtrace: Backtrace::capture(),
|
||||
});
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = OptBacktraceFrom::from(Inner);
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = ArcBacktraceFrom::from(Inner);
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(thiserror_nightly_testing)]
|
||||
pub mod enums {
|
||||
use super::{Inner, InnerBacktrace};
|
||||
use std::any;
|
||||
use std::backtrace::Backtrace;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -212,36 +213,36 @@ pub mod enums {
|
|||
let error = PlainBacktrace::Test {
|
||||
backtrace: Backtrace::capture(),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = ExplicitBacktrace::Test {
|
||||
backtrace: Backtrace::capture(),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = OptBacktrace::Test {
|
||||
backtrace: Some(Backtrace::capture()),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = ArcBacktrace::Test {
|
||||
backtrace: Arc::new(Backtrace::capture()),
|
||||
};
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = BacktraceFrom::from(Inner);
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = CombinedBacktraceFrom::from(InnerBacktrace {
|
||||
backtrace: Backtrace::capture(),
|
||||
});
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = OptBacktraceFrom::from(Inner);
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
|
||||
let error = ArcBacktraceFrom::from(Inner);
|
||||
assert!(error.backtrace().is_some());
|
||||
assert!(any::request_ref::<Backtrace>(&error).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// FIXME: needs to be updated to provide_ref/request_ref API.
|
||||
#![cfg(any())]
|
||||
#![cfg_attr(thiserror_nightly_testing, feature(backtrace))]
|
||||
#![cfg_attr(
|
||||
thiserror_nightly_testing,
|
||||
feature(error_generic_member_access, provide_any)
|
||||
)]
|
||||
|
||||
#[cfg(thiserror_nightly_testing)]
|
||||
pub mod structs {
|
||||
|
|
Loading…
Reference in New Issue