|
1 | 1 | use proc_macro2::TokenStream; |
2 | | -use quote::quote; |
| 2 | +use quote::{quote, quote_spanned}; |
3 | 3 | use syn::parse_quote; |
| 4 | +use syn::spanned::Spanned; |
4 | 5 |
|
5 | 6 | pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { |
6 | 7 | let decoder_ty = quote! { __D }; |
@@ -104,27 +105,30 @@ fn decodable_body( |
104 | 105 | } |
105 | 106 |
|
106 | 107 | fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream { |
| 108 | + let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span()); |
| 109 | + |
107 | 110 | let decode_inner_method = if let syn::Type::Reference(_) = field.ty { |
108 | 111 | quote! { ::rustc_middle::ty::codec::RefDecodable::decode } |
109 | 112 | } else { |
110 | 113 | quote! { ::rustc_serialize::Decodable::decode } |
111 | 114 | }; |
112 | 115 | let (decode_method, opt_field_name) = if is_struct { |
113 | 116 | let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string()); |
114 | | - ( |
115 | | - proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()), |
116 | | - quote! { #field_name, }, |
117 | | - ) |
| 117 | + (proc_macro2::Ident::new("read_struct_field", field_span), quote! { #field_name, }) |
118 | 118 | } else { |
119 | | - ( |
120 | | - proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()), |
121 | | - quote! {}, |
122 | | - ) |
| 119 | + (proc_macro2::Ident::new("read_enum_variant_arg", field_span), quote! {}) |
| 120 | + }; |
| 121 | + |
| 122 | + let __decoder = quote! { __decoder }; |
| 123 | + // Use the span of the field for the method call, so |
| 124 | + // that backtraces will point to the field. |
| 125 | + let decode_call = quote_spanned! {field_span=> |
| 126 | + ::rustc_serialize::Decoder::#decode_method( |
| 127 | + #__decoder, #opt_field_name #decode_inner_method) |
123 | 128 | }; |
124 | 129 |
|
125 | 130 | quote! { |
126 | | - match ::rustc_serialize::Decoder::#decode_method( |
127 | | - __decoder, #opt_field_name #decode_inner_method) { |
| 131 | + match #decode_call { |
128 | 132 | ::std::result::Result::Ok(__res) => __res, |
129 | 133 | ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err), |
130 | 134 | } |
|
0 commit comments