diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index e3b737c61c..30f553749c 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -371,7 +371,11 @@ fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { } else { let value = match field.attrs.default() { attr::Default::Default => quote!(_serde::__private::Default::default()), - attr::Default::Path(path) => quote!(#path()), + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => quote_spanned!(path.span()=> #path()), attr::Default::None => quote!(_serde::__private::PhantomData), }; quote!(#member: #value) @@ -751,7 +755,11 @@ fn deserialize_seq( attr::Default::Default => Some(quote!( let __default: Self::Value = _serde::__private::Default::default(); )), - attr::Default::Path(path) => Some(quote!( + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> let __default: Self::Value = #path(); )), attr::Default::None => { @@ -833,7 +841,11 @@ fn deserialize_seq_in_place( attr::Default::Default => Some(quote!( let __default: #this_type #ty_generics = _serde::__private::Default::default(); )), - attr::Default::Path(path) => Some(quote!( + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> let __default: #this_type #ty_generics = #path(); )), attr::Default::None => { @@ -867,7 +879,11 @@ fn deserialize_newtype_struct( } } Some(path) => { - quote! { + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(with = "...")] + // ^^^^^ + quote_spanned! {path.span()=> #path(__e)? } } @@ -2634,7 +2650,11 @@ fn deserialize_map( attr::Default::Default => Some(quote!( let __default: Self::Value = _serde::__private::Default::default(); )), - attr::Default::Path(path) => Some(quote!( + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> let __default: Self::Value = #path(); )), attr::Default::None => { @@ -2801,7 +2821,11 @@ fn deserialize_map_in_place( attr::Default::Default => Some(quote!( let __default: #this_type #ty_generics = _serde::__private::Default::default(); )), - attr::Default::Path(path) => Some(quote!( + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> let __default: #this_type #ty_generics = #path(); )), attr::Default::None => { @@ -2840,6 +2864,13 @@ fn wrap_deserialize_with( split_with_de_lifetime(params); let delife = params.borrowed.de_lifetime(); + // If #deserialize_with returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(with = "...")] + // ^^^^^ + let value = quote_spanned! {deserialize_with.span()=> + #deserialize_with(__deserializer)? + }; let wrapper = quote! { #[doc(hidden)] struct __DeserializeWith #de_impl_generics #where_clause { @@ -2854,7 +2885,7 @@ fn wrap_deserialize_with( __D: _serde::Deserializer<#delife>, { _serde::__private::Ok(__DeserializeWith { - value: #deserialize_with(__deserializer)?, + value: #value, phantom: _serde::__private::PhantomData, lifetime: _serde::__private::PhantomData, }) @@ -2945,7 +2976,11 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { return quote_expr!(#func()); } attr::Default::Path(path) => { - return quote_expr!(#path()); + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + return Fragment::Expr(quote_spanned!(path.span()=> #path())); } attr::Default::None => { /* below */ } } @@ -2988,6 +3023,10 @@ fn expr_is_missing_seq( return quote_spanned!(span=> #assign_to _serde::__private::Default::default()); } attr::Default::Path(path) => { + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ return quote_spanned!(path.span()=> #assign_to #path()); } attr::Default::None => { /* below */ } diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index 0cfb23bf1f..07c9fe9a3c 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -8,6 +8,7 @@ use std::iter::FromIterator; use syn::meta::ParseNestedMeta; use syn::parse::ParseStream; use syn::punctuated::Punctuated; +use syn::spanned::Spanned; use syn::{parse_quote, token, Ident, Lifetime, Token}; // This module handles parsing of `#[serde(...)]` attributes. The entrypoints @@ -898,13 +899,13 @@ impl Variant { ser_path .path .segments - .push(Ident::new("serialize", Span::call_site()).into()); + .push(Ident::new("serialize", ser_path.span()).into()); serialize_with.set(&meta.path, ser_path); let mut de_path = path; de_path .path .segments - .push(Ident::new("deserialize", Span::call_site()).into()); + .push(Ident::new("deserialize", de_path.span()).into()); deserialize_with.set(&meta.path, de_path); } } else if meta.path == SERIALIZE_WITH { @@ -1180,13 +1181,13 @@ impl Field { ser_path .path .segments - .push(Ident::new("serialize", Span::call_site()).into()); + .push(Ident::new("serialize", ser_path.span()).into()); serialize_with.set(&meta.path, ser_path); let mut de_path = path; de_path .path .segments - .push(Ident::new("deserialize", Span::call_site()).into()); + .push(Ident::new("deserialize", de_path.span()).into()); deserialize_with.set(&meta.path, de_path); } } else if meta.path == BOUND { diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 7d89d22125..7d10c287e7 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -1229,9 +1229,15 @@ fn wrap_serialize_with( }) }); - quote!({ + // If #serialize_with returns wrong type, error will be reported on here. + // We attach span of the path to this piece so error will be reported + // on the #[serde(with = "...")] + // ^^^^^ + quote_spanned!(serialize_with.span()=> { #[doc(hidden)] struct __SerializeWith #wrapper_impl_generics #where_clause { + // If #field_tys is empty, `values` does not used + #[allow(dead_code)] values: (#(&'__a #field_tys, )*), phantom: _serde::__private::PhantomData<#this_type #ty_generics>, }