diff --git a/Cargo.toml b/Cargo.toml index ac94fb08c..41c11afaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,4 @@ serde = { path = "serde" } [workspace.dependencies] proc-macro2 = { version = "1.0.74", default-features = false } quote = { version = "1.0.35", default-features = false } -syn = { version = "2.0.46", default-features = false } +syn = { version = "2.0.81", default-features = false } diff --git a/serde_derive/src/bound.rs b/serde_derive/src/bound.rs index fe8ccfff5..2ff6521fe 100644 --- a/serde_derive/src/bound.rs +++ b/serde_derive/src/bound.rs @@ -227,7 +227,9 @@ pub fn with_bound( match bound { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path), - syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {} + syn::TypeParamBound::Lifetime(_) + | syn::TypeParamBound::PreciseCapture(_) + | syn::TypeParamBound::Verbatim(_) => {} _ => {} } } diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 5cc4a4087..908e96fcf 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) @@ -757,7 +761,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 => { @@ -839,7 +847,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 => { @@ -873,7 +885,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)? } } @@ -956,13 +972,7 @@ fn deserialize_struct( // Skip fields that shouldn't be deserialized or that were flattened, // so they don't appear in the storage in their literal form .filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(i, field)| { - ( - field.attrs.name().deserialize_name(), - field_i(i), - field.attrs.aliases(), - ) - }) + .map(|(i, field)| (field_i(i), field.attrs.aliases())) .collect(); let has_flatten = has_flatten(fields); @@ -1022,9 +1032,7 @@ fn deserialize_struct( let fields_stmt = if has_flatten { None } else { - let field_names = field_names_idents - .iter() - .flat_map(|&(_, _, aliases)| aliases); + let field_names = field_names_idents.iter().flat_map(|&(_, aliases)| aliases); Some(quote! { #[doc(hidden)] @@ -1121,13 +1129,7 @@ fn deserialize_struct_in_place( .iter() .enumerate() .filter(|&(_, field)| !field.attrs.skip_deserializing()) - .map(|(i, field)| { - ( - field.attrs.name().deserialize_name(), - field_i(i), - field.attrs.aliases(), - ) - }) + .map(|(i, field)| (field_i(i), field.attrs.aliases())) .collect(); let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs, false); @@ -1139,9 +1141,7 @@ fn deserialize_struct_in_place( }; let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs)); - let field_names = field_names_idents - .iter() - .flat_map(|&(_, _, aliases)| aliases); + let field_names = field_names_idents.iter().flat_map(|&(_, aliases)| aliases); let type_name = cattrs.name().deserialize_name(); let in_place_impl_generics = de_impl_generics.in_place(); @@ -1232,24 +1232,20 @@ fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { let variant_names_idents: Vec<_> = deserialized_variants .clone() - .map(|(i, variant)| { - ( - variant.attrs.name().deserialize_name(), - field_i(i), - variant.attrs.aliases(), - ) - }) + .map(|(i, variant)| (field_i(i), variant.attrs.aliases())) .collect(); let fallthrough = deserialized_variants .position(|(_, variant)| variant.attrs.other()) .map(|other_idx| { - let ignore_variant = variant_names_idents[other_idx].1.clone(); + let ignore_variant = variant_names_idents[other_idx].0.clone(); quote!(_serde::__private::Ok(__Field::#ignore_variant)) }); let variants_stmt = { - let variant_names = variant_names_idents.iter().map(|(name, _, _)| name); + let variant_names = variant_names_idents + .iter() + .flat_map(|&(_, aliases)| aliases); quote! { #[doc(hidden)] const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; @@ -2015,14 +2011,14 @@ fn deserialize_untagged_newtype_variant( } fn deserialize_generated_identifier( - fields: &[(&str, Ident, &BTreeSet)], + fields: &[(Ident, &BTreeSet)], has_flatten: bool, is_variant: bool, ignore_variant: Option, fallthrough: Option, ) -> Fragment { let this_value = quote!(__Field); - let field_idents: &Vec<_> = &fields.iter().map(|(_, ident, _)| ident).collect(); + let field_idents: &Vec<_> = &fields.iter().map(|(ident, _)| ident).collect(); let visitor_impl = Stmts(deserialize_identifier( &this_value, @@ -2072,7 +2068,7 @@ fn deserialize_generated_identifier( /// Generates enum and its `Deserialize` implementation that represents each /// non-skipped field of the struct fn deserialize_field_identifier( - fields: &[(&str, Ident, &BTreeSet)], + fields: &[(Ident, &BTreeSet)], cattrs: &attr::Container, has_flatten: bool, ) -> Stmts { @@ -2149,16 +2145,10 @@ fn deserialize_custom_identifier( let names_idents: Vec<_> = ordinary .iter() - .map(|variant| { - ( - variant.attrs.name().deserialize_name(), - variant.ident.clone(), - variant.attrs.aliases(), - ) - }) + .map(|variant| (variant.ident.clone(), variant.attrs.aliases())) .collect(); - let names = names_idents.iter().flat_map(|&(_, _, aliases)| aliases); + let names = names_idents.iter().flat_map(|&(_, aliases)| aliases); let names_const = if fallthrough.is_some() { None @@ -2214,18 +2204,18 @@ fn deserialize_custom_identifier( fn deserialize_identifier( this_value: &TokenStream, - fields: &[(&str, Ident, &BTreeSet)], + fields: &[(Ident, &BTreeSet)], is_variant: bool, fallthrough: Option, fallthrough_borrowed: Option, collect_other_fields: bool, expecting: Option<&str>, ) -> Fragment { - let str_mapping = fields.iter().map(|(_, ident, aliases)| { + let str_mapping = fields.iter().map(|(ident, aliases)| { // `aliases` also contains a main name quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident)) }); - let bytes_mapping = fields.iter().map(|(_, ident, aliases)| { + let bytes_mapping = fields.iter().map(|(ident, aliases)| { // `aliases` also contains a main name let aliases = aliases .iter() @@ -2380,7 +2370,7 @@ fn deserialize_identifier( } } } else { - let u64_mapping = fields.iter().enumerate().map(|(i, (_, ident, _))| { + let u64_mapping = fields.iter().enumerate().map(|(i, (ident, _))| { let i = i as u64; quote!(#i => _serde::__private::Ok(#this_value::#ident)) }); @@ -2667,7 +2657,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 => { @@ -2837,7 +2831,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 => { @@ -2876,6 +2874,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 { @@ -2890,7 +2895,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, }) @@ -2981,7 +2986,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 */ } } @@ -3024,6 +3033,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 ac5f5d9a5..dd9e2b7dd 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 @@ -888,13 +889,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 { @@ -1170,13 +1171,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/internals/receiver.rs b/serde_derive/src/internals/receiver.rs index 852e857b8..1e7fc54f1 100644 --- a/serde_derive/src/internals/receiver.rs +++ b/serde_derive/src/internals/receiver.rs @@ -209,7 +209,9 @@ impl ReplaceReceiver<'_> { match bound { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path), - TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {} + TypeParamBound::Lifetime(_) + | TypeParamBound::PreciseCapture(_) + | TypeParamBound::Verbatim(_) => {} _ => {} } } diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 35f8ca4bd..9a45b81d4 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -1220,9 +1220,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>, } diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index b26ec8722..685bf329d 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -782,7 +782,7 @@ fn test_unknown_field_rename_enum() { variant: "SailorMoon", len: 3, }], - "unknown variant `SailorMoon`, expected `sailor_moon`", + "unknown variant `SailorMoon`, expected `sailor_moon` or `usagi_tsukino`", ); assert_de_tokens_error::( diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs new file mode 100644 index 000000000..63a88fed6 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs @@ -0,0 +1,22 @@ +//! Ensures that error message points to the path in attribute +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(tag = "tag", content = "content")] +enum Enum { + // Newtype variants does not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + Tuple( + u8, + #[serde(default = "main")] i8, + ), + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.stderr new file mode 100644 index 000000000..eefe58500 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.stderr @@ -0,0 +1,35 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:11:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +11 | #[serde(default = "main")] i8, + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:14:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +14 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_adjacently_tagged.rs:17:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +17 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs new file mode 100644 index 000000000..ae6144d8b --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs @@ -0,0 +1,21 @@ +//! Ensures that error message points to the path in attribute +use serde_derive::Deserialize; + +#[derive(Deserialize)] +enum Enum { + // Newtype variants does not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + Tuple( + u8, + #[serde(default = "main")] i8, + ), + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.stderr new file mode 100644 index 000000000..dd6f8b0d6 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_externally_tagged.stderr @@ -0,0 +1,35 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:10:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +10 | #[serde(default = "main")] i8, + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:13:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +13 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_externally_tagged.rs:16:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +16 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs new file mode 100644 index 000000000..d50264155 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs @@ -0,0 +1,19 @@ +//! Ensures that error message points to the path in attribute +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(tag = "tag")] +enum Enum { + // Newtype variants does not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + // Tuple variants does not supported in internally tagged enums + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.stderr new file mode 100644 index 000000000..752806b64 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_internally_tagged.stderr @@ -0,0 +1,23 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs:11:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +11 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_internally_tagged.rs:14:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +14 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.rs b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.rs new file mode 100644 index 000000000..8fa6c04e9 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.rs @@ -0,0 +1,22 @@ +//! Ensures that error message points to the path in attribute +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(untagged)] +enum Enum { + // Newtype variants does not use the provided path, so it is forbidden here + // Newtype(#[serde(default = "main")] u8), + Tuple( + u8, + #[serde(default = "main")] i8, + ), + Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.stderr new file mode 100644 index 000000000..9ffa6bb4e --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_enum_untagged.stderr @@ -0,0 +1,35 @@ +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_untagged.rs:11:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +11 | #[serde(default = "main")] i8, + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_untagged.rs:14:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +14 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_enum_untagged.rs:17:27 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +17 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_newtype.rs b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.rs new file mode 100644 index 000000000..7db2a3d4b --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.rs @@ -0,0 +1,8 @@ +//! Ensures that error message points to the path in attribute +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "main")] +struct Newtype(#[serde(default = "main")] u8); + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_newtype.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.stderr new file mode 100644 index 000000000..b8910514e --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_newtype.stderr @@ -0,0 +1,37 @@ +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:5:19 + | +5 | #[serde(default = "main")] + | ^^^^^^ + | | + | expected `Newtype`, found `()` + | expected due to this + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:6:34 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +5 | #[serde(default = "main")] +6 | struct Newtype(#[serde(default = "main")] u8); + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:5:19 + | +5 | #[serde(default = "main")] + | ^^^^^^ expected `Newtype`, found `()` +6 | struct Newtype(#[serde(default = "main")] u8); + | ------- expected due to this + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_newtype.rs:6:34 + | +4 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +5 | #[serde(default = "main")] +6 | struct Newtype(#[serde(default = "main")] u8); + | ^^^^^^ expected `u8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_struct.rs b/test_suite/tests/ui/default-attribute/incorrect_type_struct.rs new file mode 100644 index 000000000..52d5af9aa --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_struct.rs @@ -0,0 +1,14 @@ +//! Ensures that error message points to the path in attribute +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "main")] +struct Struct { + #[serde(default = "main")] + f1: u8, + f2: u8, + #[serde(default = "main")] + f3: i8, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_struct.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_struct.stderr new file mode 100644 index 000000000..5663c3200 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_struct.stderr @@ -0,0 +1,58 @@ +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:5:19 + | +5 | #[serde(default = "main")] + | ^^^^^^ + | | + | expected `Struct`, found `()` + | expected due to this + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_struct.rs:7:23 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `u8` + | `match` arms have incompatible types +... +7 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_struct.rs:10:23 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +10 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:5:19 + | +5 | #[serde(default = "main")] + | ^^^^^^ expected `Struct`, found `()` +6 | struct Struct { + | ------ expected due to this + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:7:23 + | +4 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +... +7 | #[serde(default = "main")] + | ^^^^^^ expected `u8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_struct.rs:10:23 + | +4 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +... +10 | #[serde(default = "main")] + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_tuple.rs b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.rs new file mode 100644 index 000000000..b5f0c5c9e --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.rs @@ -0,0 +1,11 @@ +//! Ensures that error message points to the path in attribute +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "main")] +struct Tuple( + u8, + #[serde(default = "main")] i8, +); + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/incorrect_type_tuple.stderr b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.stderr new file mode 100644 index 000000000..e473e6ff6 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/incorrect_type_tuple.stderr @@ -0,0 +1,37 @@ +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:5:19 + | +5 | #[serde(default = "main")] + | ^^^^^^ + | | + | expected `Tuple`, found `()` + | expected due to this + +error[E0308]: `match` arms have incompatible types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:8:23 + | +4 | #[derive(Deserialize)] + | ----------- + | | + | this is found to be of type `i8` + | `match` arms have incompatible types +... +8 | #[serde(default = "main")] i8, + | ^^^^^^ expected `i8`, found `()` + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:5:19 + | +5 | #[serde(default = "main")] + | ^^^^^^ expected `Tuple`, found `()` +6 | struct Tuple( + | ----- expected due to this + +error[E0308]: mismatched types + --> tests/ui/default-attribute/incorrect_type_tuple.rs:8:23 + | +4 | #[derive(Deserialize)] + | ----------- expected due to the type of this binding +... +8 | #[serde(default = "main")] i8, + | ^^^^^^ expected `i8`, found `()` diff --git a/test_suite/tests/ui/default-attribute/union.rs b/test_suite/tests/ui/default-attribute/union.rs new file mode 100644 index 000000000..296512ff0 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/union.rs @@ -0,0 +1,9 @@ +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default)] +union Union { + f: u8, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/union.stderr b/test_suite/tests/ui/default-attribute/union.stderr new file mode 100644 index 000000000..d0268ce34 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/union.stderr @@ -0,0 +1,14 @@ +error: #[serde(default)] can only be used on structs + --> tests/ui/default-attribute/union.rs:4:9 + | +4 | #[serde(default)] + | ^^^^^^^ + +error: Serde does not support derive for unions + --> tests/ui/default-attribute/union.rs:4:1 + | +4 | / #[serde(default)] +5 | | union Union { +6 | | f: u8, +7 | | } + | |_^ diff --git a/test_suite/tests/ui/default-attribute/union_path.rs b/test_suite/tests/ui/default-attribute/union_path.rs new file mode 100644 index 000000000..e57f4d1a0 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/union_path.rs @@ -0,0 +1,9 @@ +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "default_u")] +union Union { + f: u8, +} + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/union_path.stderr b/test_suite/tests/ui/default-attribute/union_path.stderr new file mode 100644 index 000000000..08e89ee18 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/union_path.stderr @@ -0,0 +1,14 @@ +error: #[serde(default = "...")] can only be used on structs + --> tests/ui/default-attribute/union_path.rs:4:9 + | +4 | #[serde(default = "default_u")] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: Serde does not support derive for unions + --> tests/ui/default-attribute/union_path.rs:4:1 + | +4 | / #[serde(default = "default_u")] +5 | | union Union { +6 | | f: u8, +7 | | } + | |_^ diff --git a/test_suite/tests/ui/default-attribute/unit.rs b/test_suite/tests/ui/default-attribute/unit.rs new file mode 100644 index 000000000..c0500545f --- /dev/null +++ b/test_suite/tests/ui/default-attribute/unit.rs @@ -0,0 +1,7 @@ +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default)] +struct Unit; + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/unit.stderr b/test_suite/tests/ui/default-attribute/unit.stderr new file mode 100644 index 000000000..c99c3bb17 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/unit.stderr @@ -0,0 +1,7 @@ +error: #[serde(default)] can only be used on structs that have fields + --> tests/ui/default-attribute/unit.rs:3:10 + | +3 | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/test_suite/tests/ui/default-attribute/unit_path.rs b/test_suite/tests/ui/default-attribute/unit_path.rs new file mode 100644 index 000000000..25705fad5 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/unit_path.rs @@ -0,0 +1,7 @@ +use serde_derive::Deserialize; + +#[derive(Deserialize)] +#[serde(default = "default_u")] +struct Unit; + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/unit_path.stderr b/test_suite/tests/ui/default-attribute/unit_path.stderr new file mode 100644 index 000000000..430136120 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/unit_path.stderr @@ -0,0 +1,5 @@ +error: #[serde(default = "...")] can only be used on structs that have fields + --> tests/ui/default-attribute/unit_path.rs:4:9 + | +4 | #[serde(default = "default_u")] + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/test_suite/tests/ui/with/incorrect_type.rs b/test_suite/tests/ui/with/incorrect_type.rs new file mode 100644 index 000000000..c1502bb45 --- /dev/null +++ b/test_suite/tests/ui/with/incorrect_type.rs @@ -0,0 +1,23 @@ +use serde_derive::{Deserialize, Serialize}; + +mod w { + use serde::{Deserializer, Serializer}; + + pub fn deserialize<'de, D: Deserializer<'de>>(_: D) -> Result<(), D::Error> { + unimplemented!() + } + pub fn serialize(_: S) -> Result { + unimplemented!() + } +} + +#[derive(Serialize, Deserialize)] +struct W(#[serde(with = "w")] u8, u8); + +#[derive(Serialize, Deserialize)] +struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + +#[derive(Serialize, Deserialize)] +struct D(#[serde(deserialize_with = "w::deserialize")] u8, u8); + +fn main() {} diff --git a/test_suite/tests/ui/with/incorrect_type.stderr b/test_suite/tests/ui/with/incorrect_type.stderr new file mode 100644 index 000000000..9981948b5 --- /dev/null +++ b/test_suite/tests/ui/with/incorrect_type.stderr @@ -0,0 +1,97 @@ +error[E0277]: the trait bound `&u8: Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:14:10 + | +14 | #[derive(Serialize, Deserialize)] + | ^^^^^^^^^ the trait `Serializer` is not implemented for `&u8` +15 | struct W(#[serde(with = "w")] u8, u8); + | --- required by a bound introduced by this call + | + = help: the following other types implement trait `Serializer`: + &'a mut Formatter<'b> + FlatMapSerializer<'a, M> + _::_serde::__private::ser::content::ContentSerializer +note: required by a bound in `w::serialize` + --> tests/ui/with/incorrect_type.rs:9:28 + | +9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^^ required by this bound in `serialize` + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> tests/ui/with/incorrect_type.rs:15:25 + | +15 | struct W(#[serde(with = "w")] u8, u8); + | ^^^ unexpected argument #2 of type `__S` + | +note: function defined here + --> tests/ui/with/incorrect_type.rs:9:12 + | +9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^ ---- + +error[E0277]: the trait bound `&u8: Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:15:25 + | +15 | struct W(#[serde(with = "w")] u8, u8); + | ^^^ the trait `Serializer` is not implemented for `&u8` + | + = help: the following other types implement trait `Serializer`: + &'a mut Formatter<'b> + FlatMapSerializer<'a, M> + _::_serde::__private::ser::content::ContentSerializer + +error[E0308]: `?` operator has incompatible types + --> tests/ui/with/incorrect_type.rs:15:25 + | +15 | struct W(#[serde(with = "w")] u8, u8); + | ^^^ expected `u8`, found `()` + | + = note: `?` operator cannot convert from `()` to `u8` + +error[E0277]: the trait bound `&u8: Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:17:10 + | +17 | #[derive(Serialize, Deserialize)] + | ^^^^^^^^^ the trait `Serializer` is not implemented for `&u8` +18 | struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + | -------------- required by a bound introduced by this call + | + = help: the following other types implement trait `Serializer`: + &'a mut Formatter<'b> + FlatMapSerializer<'a, M> + _::_serde::__private::ser::content::ContentSerializer +note: required by a bound in `w::serialize` + --> tests/ui/with/incorrect_type.rs:9:28 + | +9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^^ required by this bound in `serialize` + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> tests/ui/with/incorrect_type.rs:18:35 + | +18 | struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + | ^^^^^^^^^^^^^^ unexpected argument #2 of type `__S` + | +note: function defined here + --> tests/ui/with/incorrect_type.rs:9:12 + | +9 | pub fn serialize(_: S) -> Result { + | ^^^^^^^^^ ---- + +error[E0277]: the trait bound `&u8: Serializer` is not satisfied + --> tests/ui/with/incorrect_type.rs:18:35 + | +18 | struct S(#[serde(serialize_with = "w::serialize")] u8, u8); + | ^^^^^^^^^^^^^^ the trait `Serializer` is not implemented for `&u8` + | + = help: the following other types implement trait `Serializer`: + &'a mut Formatter<'b> + FlatMapSerializer<'a, M> + _::_serde::__private::ser::content::ContentSerializer + +error[E0308]: `?` operator has incompatible types + --> tests/ui/with/incorrect_type.rs:21:37 + | +21 | struct D(#[serde(deserialize_with = "w::deserialize")] u8, u8); + | ^^^^^^^^^^^^^^^^ expected `u8`, found `()` + | + = note: `?` operator cannot convert from `()` to `u8`