Skip to content

Commit

Permalink
Consistently use quote! when emitting 'source'
Browse files Browse the repository at this point in the history
When a macro generates part of the derive input, the call-site hygiene
may be different than the hygiene of a field. Therefore, we need to
be sure to use the same hygiene information for any identifiers we
generate, instead of relying on the hygiene from a particular span
via `quote_spanned!`
  • Loading branch information
Aaron1011 committed Feb 18, 2021
1 parent d0f521c commit e7e7afd
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 5 deletions.
12 changes: 7 additions & 5 deletions impl/src/expand.rs
Expand Up @@ -171,9 +171,10 @@ fn impl_enum(input: Enum) -> TokenStream {
} else {
None
};
let dyn_error = quote_spanned!(source.span()=> source #asref.as_dyn_error());
let source_literal = quote! { source };
let dyn_error = quote_spanned!(source.span()=> #source_literal #asref.as_dyn_error());
quote! {
#ty::#ident {#source: source, ..} => std::option::Option::Some(#dyn_error),
#ty::#ident {#source: #source_literal, ..} => std::option::Option::Some(#dyn_error),
}
} else {
quote! {
Expand Down Expand Up @@ -203,13 +204,14 @@ fn impl_enum(input: Enum) -> TokenStream {
{
let backtrace = &backtrace_field.member;
let source = &source_field.member;
let source_literal = quote! { source };
let source_backtrace = if type_is_option(source_field.ty) {
quote_spanned! {source.span()=>
source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
#source_literal.as_ref().and_then(|source| #source_literal.as_dyn_error().backtrace())
}
} else {
quote_spanned! {source.span()=>
source.as_dyn_error().backtrace()
#source_literal.as_dyn_error().backtrace()
}
};
let combinator = if type_is_option(backtrace_field.ty) {
Expand All @@ -224,7 +226,7 @@ fn impl_enum(input: Enum) -> TokenStream {
quote! {
#ty::#ident {
#backtrace: backtrace,
#source: source,
#source: #source_literal,
..
} => {
use thiserror::private::AsDynError;
Expand Down
13 changes: 13 additions & 0 deletions tests/test_source.rs
Expand Up @@ -48,3 +48,16 @@ fn test_boxed_source() {
let error = BoxedSource { source };
error.source().unwrap().downcast_ref::<io::Error>().unwrap();
}

macro_rules! error_from_macro {
($name:ident, $($variants:tt)*) => {
#[derive(Error)]
#[derive(Debug)]
pub enum Foo {
$($variants)*
}
}
}

// Test that we generate impls with the proper hygiene
error_from_macro!(MacroSource, #[error("Something")] Variant(#[from] io::Error));

0 comments on commit e7e7afd

Please sign in to comment.