Merge pull request #2963 from dtolnay/diagnosticpath

Override diagnostic::on_unimplemented message for all serde_core traits
This commit is contained in:
David Tolnay
2025-09-13 14:07:43 -07:00
committed by GitHub
7 changed files with 251 additions and 12 deletions
+63
View File
@@ -158,6 +158,12 @@ macro_rules! declare_error_trait {
/// type appropriate for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Error` is not satisfied",
)
)]
pub trait Error: Sized $(+ $($supertrait)::+)* {
/// Raised when there is general error when deserializing a type.
///
@@ -471,6 +477,12 @@ impl<'a> fmt::Display for Unexpected<'a> {
/// ));
/// # }
/// ```
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Expected` is not satisfied",
)
)]
pub trait Expected {
/// Format an explanation of what data was being expected. Same signature as
/// the `Display` and `Debug` traits.
@@ -534,6 +546,9 @@ impl Display for dyn Expected + '_ {
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
// Prevents `serde_core::de::Deserialize` appearing in the error message
// in projects with no direct dependency on serde_core.
message = "the trait bound `{Self}: serde::Deserialize<'de>` is not satisfied",
note = "for local types consider adding `#[derive(serde::Deserialize)]` to your `{Self}` type",
note = "for types from other crates check whether the crate offers a `serde` feature flag",
)
@@ -610,6 +625,12 @@ pub trait Deserialize<'de>: Sized {
/// lifetimes].
///
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::DeserializeOwned` is not satisfied",
)
)]
pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
@@ -775,6 +796,12 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
/// # Ok(())
/// # }
/// ```
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::DeserializeSeed<'de>` is not satisfied",
)
)]
pub trait DeserializeSeed<'de>: Sized {
/// The type produced by using this seed.
type Value;
@@ -911,6 +938,12 @@ where
/// a basic JSON `Deserializer`.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Deserializer<'de>` is not satisfied",
)
)]
pub trait Deserializer<'de>: Sized {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -1267,6 +1300,12 @@ pub trait Deserializer<'de>: Sized {
/// }
/// }
/// ```
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::Visitor<'de>` is not satisfied",
)
)]
pub trait Visitor<'de>: Sized {
/// The value produced by this visitor.
type Value;
@@ -1693,6 +1732,12 @@ pub trait Visitor<'de>: Sized {
/// implementation of `SeqAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::SeqAccess<'de>` is not satisfied",
)
)]
pub trait SeqAccess<'de> {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -1775,6 +1820,12 @@ where
/// implementation of `MapAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::MapAccess<'de>` is not satisfied",
)
)]
pub trait MapAccess<'de> {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -1967,6 +2018,12 @@ where
/// implementation of `EnumAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::EnumAccess<'de>` is not satisfied",
)
)]
pub trait EnumAccess<'de>: Sized {
/// The error type that can be returned if some error occurs during
/// deserialization.
@@ -2014,6 +2071,12 @@ pub trait EnumAccess<'de>: Sized {
/// implementation of `VariantAccess` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::de::VariantAccess<'de>` is not satisfied",
)
)]
pub trait VariantAccess<'de>: Sized {
/// The error type that can be returned if some error occurs during
/// deserialization. Must match the error type of our `EnumAccess`.
+57
View File
@@ -139,6 +139,12 @@ macro_rules! declare_error_trait {
/// type appropriate for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::Error` is not satisfied",
)
)]
pub trait Error: Sized $(+ $($supertrait)::+)* {
/// Used when a [`Serialize`] implementation encounters any error
/// while serializing a type.
@@ -218,6 +224,9 @@ declare_error_trait!(Error: Sized + Debug + Display);
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
// Prevents `serde_core::ser::Serialize` appearing in the error message
// in projects with no direct dependency on serde_core.
message = "the trait bound `{Self}: serde::Serialize` is not satisfied",
note = "for local types consider adding `#[derive(serde::Serialize)]` to your `{Self}` type",
note = "for types from other crates check whether the crate offers a `serde` feature flag",
)
@@ -337,6 +346,12 @@ pub trait Serialize {
/// a basic JSON `Serializer`.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::Serializer` is not satisfied",
)
)]
pub trait Serializer: Sized {
/// The output type produced by this `Serializer` during successful
/// serialization. Most serializers that produce text or binary output
@@ -1494,6 +1509,12 @@ pub trait Serializer: Sized {
/// implementation of `SerializeSeq` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeSeq` is not satisfied",
)
)]
pub trait SerializeSeq {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1594,6 +1615,12 @@ pub trait SerializeSeq {
/// implementation of `SerializeTuple` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeTuple` is not satisfied",
)
)]
pub trait SerializeTuple {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1639,6 +1666,12 @@ pub trait SerializeTuple {
/// implementation of `SerializeTupleStruct` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeTupleStruct` is not satisfied",
)
)]
pub trait SerializeTupleStruct {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1697,6 +1730,12 @@ pub trait SerializeTupleStruct {
/// implementation of `SerializeTupleVariant` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeTupleVariant` is not satisfied",
)
)]
pub trait SerializeTupleVariant {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1763,6 +1802,12 @@ pub trait SerializeTupleVariant {
/// implementation of `SerializeMap` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeMap` is not satisfied",
)
)]
pub trait SerializeMap {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1853,6 +1898,12 @@ pub trait SerializeMap {
/// implementation of `SerializeStruct` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeStruct` is not satisfied",
)
)]
pub trait SerializeStruct {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -1917,6 +1968,12 @@ pub trait SerializeStruct {
/// implementation of `SerializeStructVariant` for a basic JSON data format.
///
/// [example data format]: https://serde.rs/data-format.html
#[cfg_attr(
not(no_diagnostic_namespace),
diagnostic::on_unimplemented(
message = "the trait bound `{Self}: serde::ser::SerializeStructVariant` is not satisfied",
)
)]
pub trait SerializeStructVariant {
/// Must match the `Ok` type of our `Serializer`.
type Ok;
@@ -0,0 +1,6 @@
struct MyStruct;
fn main() {
serde_test::assert_ser_tokens(&MyStruct, &[]);
serde_test::assert_de_tokens(&MyStruct, &[]);
}
@@ -0,0 +1,113 @@
error[E0277]: the trait bound `MyStruct: serde::Serialize` is not satisfied
--> tests/ui/unimplemented/required_by_dependency.rs:4:35
|
4 | serde_test::assert_ser_tokens(&MyStruct, &[]);
| ----------------------------- ^^^^^^^^^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
help: the trait `serde_core::ser::Serialize` is not implemented for `MyStruct`
--> tests/ui/unimplemented/required_by_dependency.rs:1:1
|
1 | struct MyStruct;
| ^^^^^^^^^^^^^^^
= note: for local types consider adding `#[derive(serde::Serialize)]` to your `MyStruct` type
= note: for types from other crates check whether the crate offers a `serde` feature flag
= help: the following other types implement trait `serde_core::ser::Serialize`:
&'a T
&'a mut T
()
(T,)
(T0, T1)
(T0, T1, T2)
(T0, T1, T2, T3)
(T0, T1, T2, T3, T4)
and $N others
note: required by a bound in `assert_ser_tokens`
--> $CARGO/serde_test-$VERSION/src/assert.rs
|
| pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
| ----------------- required by a bound in this function
| where
| T: ?Sized + Serialize,
| ^^^^^^^^^ required by this bound in `assert_ser_tokens`
error[E0277]: the trait bound `MyStruct: serde::Deserialize<'de>` is not satisfied
--> tests/ui/unimplemented/required_by_dependency.rs:5:34
|
5 | serde_test::assert_de_tokens(&MyStruct, &[]);
| ---------------------------- ^^^^^^^^^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
help: the trait `serde_core::de::Deserialize<'_>` is not implemented for `MyStruct`
--> tests/ui/unimplemented/required_by_dependency.rs:1:1
|
1 | struct MyStruct;
| ^^^^^^^^^^^^^^^
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `MyStruct` type
= note: for types from other crates check whether the crate offers a `serde` feature flag
= help: the following other types implement trait `serde_core::de::Deserialize<'de>`:
&'a Path
&'a [u8]
&'a str
()
(T,)
(T0, T1)
(T0, T1, T2)
(T0, T1, T2, T3)
and $N others
note: required by a bound in `assert_de_tokens`
--> $CARGO/serde_test-$VERSION/src/assert.rs
|
| pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
| ---------------- required by a bound in this function
| where
| T: Deserialize<'de> + PartialEq + Debug,
| ^^^^^^^^^^^^^^^^ required by this bound in `assert_de_tokens`
error[E0277]: can't compare `MyStruct` with `MyStruct`
--> tests/ui/unimplemented/required_by_dependency.rs:5:34
|
5 | serde_test::assert_de_tokens(&MyStruct, &[]);
| ---------------------------- ^^^^^^^^^ no implementation for `MyStruct == MyStruct`
| |
| required by a bound introduced by this call
|
= help: the trait `PartialEq` is not implemented for `MyStruct`
note: required by a bound in `assert_de_tokens`
--> $CARGO/serde_test-$VERSION/src/assert.rs
|
| pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
| ---------------- required by a bound in this function
| where
| T: Deserialize<'de> + PartialEq + Debug,
| ^^^^^^^^^ required by this bound in `assert_de_tokens`
help: consider annotating `MyStruct` with `#[derive(PartialEq)]`
|
1 + #[derive(PartialEq)]
2 | struct MyStruct;
|
error[E0277]: `MyStruct` doesn't implement `Debug`
--> tests/ui/unimplemented/required_by_dependency.rs:5:34
|
5 | serde_test::assert_de_tokens(&MyStruct, &[]);
| ---------------------------- ^^^^^^^^^ the trait `Debug` is not implemented for `MyStruct`
| |
| required by a bound introduced by this call
|
= note: add `#[derive(Debug)]` to `MyStruct` or manually `impl Debug for MyStruct`
note: required by a bound in `assert_de_tokens`
--> $CARGO/serde_test-$VERSION/src/assert.rs
|
| pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
| ---------------- required by a bound in this function
| where
| T: Deserialize<'de> + PartialEq + Debug,
| ^^^^^ required by this bound in `assert_de_tokens`
help: consider annotating `MyStruct` with `#[derive(Debug)]`
|
1 + #[derive(Debug)]
2 | struct MyStruct;
|
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `MyStruct: Serialize` is not satisfied
--> tests/ui/on_unimplemented.rs:21:15
error[E0277]: the trait bound `MyStruct: serde::Serialize` is not satisfied
--> tests/ui/unimplemented/required_locally.rs:21:15
|
21 | to_string(&MyStruct);
| --------- ^^^^^^^^^ unsatisfied trait bound
@@ -7,7 +7,7 @@ error[E0277]: the trait bound `MyStruct: Serialize` is not satisfied
| required by a bound introduced by this call
|
help: the trait `Serialize` is not implemented for `MyStruct`
--> tests/ui/on_unimplemented.rs:18:1
--> tests/ui/unimplemented/required_locally.rs:18:1
|
18 | struct MyStruct;
| ^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ help: the trait `Serialize` is not implemented for `MyStruct`
(T0, T1, T2, T3, T4)
and $N others
note: required by a bound in `to_string`
--> tests/ui/on_unimplemented.rs:6:8
--> tests/ui/unimplemented/required_locally.rs:6:8
|
4 | fn to_string<T>(_: &T) -> String
| --------- required by a bound in this function
@@ -32,14 +32,14 @@ note: required by a bound in `to_string`
6 | T: Serialize,
| ^^^^^^^^^ required by this bound in `to_string`
error[E0277]: the trait bound `MyStruct: Deserialize<'_>` is not satisfied
--> tests/ui/on_unimplemented.rs:22:23
error[E0277]: the trait bound `MyStruct: serde::Deserialize<'de>` is not satisfied
--> tests/ui/unimplemented/required_locally.rs:22:23
|
22 | let _: MyStruct = from_str("");
| ^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `Deserialize<'_>` is not implemented for `MyStruct`
--> tests/ui/on_unimplemented.rs:18:1
--> tests/ui/unimplemented/required_locally.rs:18:1
|
18 | struct MyStruct;
| ^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ help: the trait `Deserialize<'_>` is not implemented for `MyStruct`
(T0, T1, T2, T3)
and $N others
note: required by a bound in `from_str`
--> tests/ui/on_unimplemented.rs:13:8
--> tests/ui/unimplemented/required_locally.rs:13:8
|
11 | fn from_str<'de, T>(_: &'de str) -> T
| -------- required by a bound in this function
@@ -1,4 +1,4 @@
error[E0277]: the trait bound `&u8: Serializer` is not satisfied
error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied
--> tests/ui/with/incorrect_type.rs:14:10
|
14 | #[derive(Serialize, Deserialize)]
@@ -30,7 +30,7 @@ note: function defined here
9 | pub fn serialize<T, S: Serializer>(_: S) -> Result<S::Ok, S::Error> {
| ^^^^^^^^^
error[E0277]: the trait bound `&u8: Serializer` is not satisfied
error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied
--> tests/ui/with/incorrect_type.rs:15:25
|
15 | struct W(#[serde(with = "w")] u8, u8);
@@ -49,7 +49,7 @@ error[E0308]: `?` operator has incompatible types
|
= note: `?` operator cannot convert from `()` to `u8`
error[E0277]: the trait bound `&u8: Serializer` is not satisfied
error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied
--> tests/ui/with/incorrect_type.rs:17:10
|
17 | #[derive(Serialize, Deserialize)]
@@ -81,7 +81,7 @@ note: function defined here
9 | pub fn serialize<T, S: Serializer>(_: S) -> Result<S::Ok, S::Error> {
| ^^^^^^^^^
error[E0277]: the trait bound `&u8: Serializer` is not satisfied
error[E0277]: the trait bound `&u8: serde::Serializer` is not satisfied
--> tests/ui/with/incorrect_type.rs:18:35
|
18 | struct S(#[serde(serialize_with = "w::serialize")] u8, u8);