Skip to content

Commit febacff

Browse files
committed
Make compile error message point to field type instead of call site for not implemented Serialize trait
1 parent 4b3178b commit febacff

File tree

11 files changed

+486
-24
lines changed

11 files changed

+486
-24
lines changed

serde_derive/src/ser.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTra
311311
match cattrs.tag() {
312312
attr::TagType::Internal { tag } => {
313313
let type_name = cattrs.name().serialize_name();
314-
let func = struct_trait.serialize_field(Span::call_site());
314+
let func = struct_trait.serialize_field(None);
315315
quote! {
316316
#func(&mut __serde_state, #tag, #type_name)?;
317317
}
@@ -1081,8 +1081,13 @@ fn serialize_tuple_struct_visitor(
10811081
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
10821082
}
10831083

1084-
let span = field.original.span();
1085-
let func = tuple_trait.serialize_element(span);
1084+
let ty = if field.attrs.serialize_with().is_none() {
1085+
Some(field.ty)
1086+
} else {
1087+
None
1088+
};
1089+
1090+
let func = tuple_trait.serialize_element(ty);
10861091
let ser = quote! {
10871092
#func(&mut __serde_state, #field_expr)?;
10881093
};
@@ -1131,7 +1136,13 @@ fn serialize_struct_visitor(
11311136
#func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state))?;
11321137
}
11331138
} else {
1134-
let func = struct_trait.serialize_field(span);
1139+
let ty = if field.attrs.serialize_with().is_none() {
1140+
Some(field.ty)
1141+
} else {
1142+
None
1143+
};
1144+
1145+
let func = struct_trait.serialize_field(ty);
11351146
quote! {
11361147
#func(&mut __serde_state, #key_expr, #field_expr)?;
11371148
}
@@ -1300,16 +1311,17 @@ enum StructTrait {
13001311
}
13011312

13021313
impl StructTrait {
1303-
fn serialize_field(&self, span: Span) -> TokenStream {
1314+
fn serialize_field(&self, ty: Option<&syn::Type>) -> TokenStream {
1315+
let ty = ty.into_iter();
13041316
match *self {
13051317
StructTrait::SerializeMap => {
1306-
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
1318+
quote!(_serde::ser::SerializeMap::serialize_entry #( ::<_, #ty> )* )
13071319
}
13081320
StructTrait::SerializeStruct => {
1309-
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
1321+
quote!(_serde::ser::SerializeStruct::serialize_field #( ::<#ty> )* )
13101322
}
13111323
StructTrait::SerializeStructVariant => {
1312-
quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field)
1324+
quote!(_serde::ser::SerializeStructVariant::serialize_field #( ::<#ty> )* )
13131325
}
13141326
}
13151327
}
@@ -1334,16 +1346,17 @@ enum TupleTrait {
13341346
}
13351347

13361348
impl TupleTrait {
1337-
fn serialize_element(&self, span: Span) -> TokenStream {
1349+
fn serialize_element(&self, ty: Option<&syn::Type>) -> TokenStream {
1350+
let ty = ty.into_iter();
13381351
match *self {
13391352
TupleTrait::SerializeTuple => {
1340-
quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element)
1353+
quote!(_serde::ser::SerializeTuple::serialize_element #( ::<#ty> )*)
13411354
}
13421355
TupleTrait::SerializeTupleStruct => {
1343-
quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field)
1356+
quote!(_serde::ser::SerializeTupleStruct::serialize_field #( ::<#ty> )*)
13441357
}
13451358
TupleTrait::SerializeTupleVariant => {
1346-
quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field)
1359+
quote!(_serde::ser::SerializeTupleVariant::serialize_field #( ::<#ty> )*)
13471360
}
13481361
}
13491362
}

test_suite/tests/ui/on_unimplemented.rs renamed to test_suite/tests/ui/on-unimplemented/fn_param.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use serde::de::Deserialize;
22
use serde::ser::Serialize;
33

4+
45
fn to_string<T>(_: &T) -> String
56
where
67
T: Serialize,

test_suite/tests/ui/on_unimplemented.stderr renamed to test_suite/tests/ui/on-unimplemented/fn_param.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
error[E0277]: the trait bound `MyStruct: Serialize` is not satisfied
2-
--> tests/ui/on_unimplemented.rs:21:15
2+
--> tests/ui/on-unimplemented/fn_param.rs:22:15
33
|
4-
21 | to_string(&MyStruct);
4+
22 | to_string(&MyStruct);
55
| --------- ^^^^^^^^^ the trait `Serialize` is not implemented for `MyStruct`
66
| |
77
| required by a bound introduced by this call
@@ -19,18 +19,18 @@ error[E0277]: the trait bound `MyStruct: Serialize` is not satisfied
1919
(T0, T1, T2, T3, T4)
2020
and $N others
2121
note: required by a bound in `to_string`
22-
--> tests/ui/on_unimplemented.rs:6:8
22+
--> tests/ui/on-unimplemented/fn_param.rs:7:8
2323
|
24-
4 | fn to_string<T>(_: &T) -> String
24+
5 | fn to_string<T>(_: &T) -> String
2525
| --------- required by a bound in this function
26-
5 | where
27-
6 | T: Serialize,
26+
6 | where
27+
7 | T: Serialize,
2828
| ^^^^^^^^^ required by this bound in `to_string`
2929

3030
error[E0277]: the trait bound `MyStruct: Deserialize<'_>` is not satisfied
31-
--> tests/ui/on_unimplemented.rs:22:23
31+
--> tests/ui/on-unimplemented/fn_param.rs:23:23
3232
|
33-
22 | let _: MyStruct = from_str("");
33+
23 | let _: MyStruct = from_str("");
3434
| ^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `MyStruct`
3535
|
3636
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `MyStruct` type
@@ -46,10 +46,10 @@ error[E0277]: the trait bound `MyStruct: Deserialize<'_>` is not satisfied
4646
(T0, T1, T2, T3)
4747
and $N others
4848
note: required by a bound in `from_str`
49-
--> tests/ui/on_unimplemented.rs:13:8
49+
--> tests/ui/on-unimplemented/fn_param.rs:14:8
5050
|
51-
11 | fn from_str<'de, T>(_: &'de str) -> T
51+
12 | fn from_str<'de, T>(_: &'de str) -> T
5252
| -------- required by a bound in this function
53-
12 | where
54-
13 | T: Deserialize<'de>,
53+
13 | where
54+
14 | T: Deserialize<'de>,
5555
| ^^^^^^^^^^^^^^^^ required by this bound in `from_str`
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use serde_derive::{Deserialize, Serialize};
2+
3+
struct NoImpls;
4+
5+
#[derive(Serialize, Deserialize)]
6+
struct S {
7+
x1: u32,
8+
x2: NoImpls,
9+
}
10+
11+
fn main() {}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
error[E0277]: the trait bound `NoImpls: Serialize` is not satisfied
2+
--> tests/ui/on-unimplemented/struct_field.rs:8:9
3+
|
4+
8 | x2: NoImpls,
5+
| ^^^^^^^ the trait `Serialize` is not implemented for `NoImpls`
6+
|
7+
= note: for local types consider adding `#[derive(serde::Serialize)]` to your `NoImpls` type
8+
= note: for types from other crates check whether the crate offers a `serde` feature flag
9+
= help: the following other types implement trait `Serialize`:
10+
&'a T
11+
&'a mut T
12+
()
13+
(T,)
14+
(T0, T1)
15+
(T0, T1, T2)
16+
(T0, T1, T2, T3)
17+
(T0, T1, T2, T3, T4)
18+
and $N others
19+
note: required by a bound in `_::_serde::ser::SerializeStruct::serialize_field`
20+
--> $WORKSPACE/serde/src/ser/mod.rs
21+
|
22+
| fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
23+
| --------------- required by a bound in this associated function
24+
| where
25+
| T: ?Sized + Serialize;
26+
| ^^^^^^^^^ required by this bound in `SerializeStruct::serialize_field`
27+
28+
error[E0277]: the trait bound `NoImpls: Deserialize<'_>` is not satisfied
29+
--> tests/ui/on-unimplemented/struct_field.rs:8:9
30+
|
31+
8 | x2: NoImpls,
32+
| ^^^^^^^ the trait `Deserialize<'_>` is not implemented for `NoImpls`
33+
|
34+
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `NoImpls` type
35+
= note: for types from other crates check whether the crate offers a `serde` feature flag
36+
= help: the following other types implement trait `Deserialize<'de>`:
37+
&'a Path
38+
&'a [u8]
39+
&'a str
40+
()
41+
(T,)
42+
(T0, T1)
43+
(T0, T1, T2)
44+
(T0, T1, T2, T3)
45+
and $N others
46+
note: required by a bound in `next_element`
47+
--> $WORKSPACE/serde/src/de/mod.rs
48+
|
49+
| fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error>
50+
| ------------ required by a bound in this associated function
51+
| where
52+
| T: Deserialize<'de>,
53+
| ^^^^^^^^^^^^^^^^ required by this bound in `SeqAccess::next_element`
54+
55+
error[E0277]: the trait bound `NoImpls: Deserialize<'_>` is not satisfied
56+
--> tests/ui/on-unimplemented/struct_field.rs:8:9
57+
|
58+
8 | x2: NoImpls,
59+
| ^^^^^^^ the trait `Deserialize<'_>` is not implemented for `NoImpls`
60+
|
61+
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `NoImpls` type
62+
= note: for types from other crates check whether the crate offers a `serde` feature flag
63+
= help: the following other types implement trait `Deserialize<'de>`:
64+
&'a Path
65+
&'a [u8]
66+
&'a str
67+
()
68+
(T,)
69+
(T0, T1)
70+
(T0, T1, T2)
71+
(T0, T1, T2, T3)
72+
and $N others
73+
note: required by a bound in `next_value`
74+
--> $WORKSPACE/serde/src/de/mod.rs
75+
|
76+
| fn next_value<V>(&mut self) -> Result<V, Self::Error>
77+
| ---------- required by a bound in this associated function
78+
| where
79+
| V: Deserialize<'de>,
80+
| ^^^^^^^^^^^^^^^^ required by this bound in `MapAccess::next_value`
81+
82+
error[E0277]: the trait bound `NoImpls: Deserialize<'_>` is not satisfied
83+
--> tests/ui/on-unimplemented/struct_field.rs:5:21
84+
|
85+
5 | #[derive(Serialize, Deserialize)]
86+
| ^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `NoImpls`
87+
|
88+
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `NoImpls` type
89+
= note: for types from other crates check whether the crate offers a `serde` feature flag
90+
= help: the following other types implement trait `Deserialize<'de>`:
91+
&'a Path
92+
&'a [u8]
93+
&'a str
94+
()
95+
(T,)
96+
(T0, T1)
97+
(T0, T1, T2)
98+
(T0, T1, T2, T3)
99+
and $N others
100+
note: required by a bound in `_::_serde::__private::de::missing_field`
101+
--> $WORKSPACE/serde/src/private/de.rs
102+
|
103+
| pub fn missing_field<'de, V, E>(field: &'static str) -> Result<V, E>
104+
| ------------- required by a bound in this function
105+
| where
106+
| V: Deserialize<'de>,
107+
| ^^^^^^^^^^^^^^^^ required by this bound in `missing_field`
108+
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
109+
110+
error[E0277]: the trait bound `NoImpls: Deserialize<'_>` is not satisfied
111+
--> tests/ui/on-unimplemented/struct_field.rs:5:21
112+
|
113+
5 | #[derive(Serialize, Deserialize)]
114+
| ^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `NoImpls`, which is required by `InPlaceSeed<'_, NoImpls>: DeserializeSeed<'_>`
115+
|
116+
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `NoImpls` type
117+
= note: for types from other crates check whether the crate offers a `serde` feature flag
118+
= help: the following other types implement trait `Deserialize<'de>`:
119+
&'a Path
120+
&'a [u8]
121+
&'a str
122+
()
123+
(T,)
124+
(T0, T1)
125+
(T0, T1, T2)
126+
(T0, T1, T2, T3)
127+
and $N others
128+
= note: required for `InPlaceSeed<'_, NoImpls>` to implement `DeserializeSeed<'_>`
129+
note: required by a bound in `next_element_seed`
130+
--> $WORKSPACE/serde/src/de/mod.rs
131+
|
132+
| fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
133+
| ----------------- required by a bound in this associated function
134+
| where
135+
| T: DeserializeSeed<'de>;
136+
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `SeqAccess::next_element_seed`
137+
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
138+
139+
error[E0277]: the trait bound `NoImpls: Deserialize<'_>` is not satisfied
140+
--> tests/ui/on-unimplemented/struct_field.rs:5:21
141+
|
142+
5 | #[derive(Serialize, Deserialize)]
143+
| ^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `NoImpls`, which is required by `InPlaceSeed<'_, NoImpls>: DeserializeSeed<'_>`
144+
|
145+
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `NoImpls` type
146+
= note: for types from other crates check whether the crate offers a `serde` feature flag
147+
= help: the following other types implement trait `Deserialize<'de>`:
148+
&'a Path
149+
&'a [u8]
150+
&'a str
151+
()
152+
(T,)
153+
(T0, T1)
154+
(T0, T1, T2)
155+
(T0, T1, T2, T3)
156+
and $N others
157+
= note: required for `InPlaceSeed<'_, NoImpls>` to implement `DeserializeSeed<'_>`
158+
note: required by a bound in `next_value_seed`
159+
--> $WORKSPACE/serde/src/de/mod.rs
160+
|
161+
| fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
162+
| --------------- required by a bound in this associated function
163+
| where
164+
| V: DeserializeSeed<'de>;
165+
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `MapAccess::next_value_seed`
166+
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use serde_derive::{Deserialize, Serialize};
2+
3+
struct NoImpls;
4+
5+
#[derive(Serialize, Deserialize)]
6+
enum E {
7+
S { x1: u32, x2: NoImpls },
8+
}
9+
10+
fn main() {}

0 commit comments

Comments
 (0)