Override diagnostic::on_unimplemented message of all serde_core traits

This prevents diagnostics being rendered like `serde_core::ser::Serialize`
and `serde_core::de::Deserialize` in projects that have no direct
dependency on serde_core.

The attributes make error messages arguably sometimes worse than
pre-serde_core by always rendering `serde::Serialize` and never
`Serialize` when `use serde::Serialize` is in scope, which rustc's
default message construction knows to recognize. But this is probably
negligible.

I explored the alternative of setting `[lib] name = "serde"` in
serde_core/Cargo.toml which also prevents `serde_core::ser::Serialize`
in messages, but has the unwanted effect of also inserting the following
noise into every such error:

    note: there are multiple different versions of crate `serde` in the dependency graph
        --> $WORKSPACE/serde_core/src/ser/mod.rs:225:1
         |
     225 | pub trait Serialize {
         | ^^^^^^^^^^^^^^^^^^^ this is the required trait
         |
        ::: src/main.rs:1:1
         |
       1 | struct MyStruct;
         | --------------- this type doesn't implement the required trait
    ...
       4 |     let _ = serde_json::to_string(&MyStruct);
         |             ----------
         |             |
         |             one version of crate `serde` used here, as a dependency of crate `serde`
         |             one version of crate `serde` used here, as a dependency of crate `serde_json`
         |
        ::: $WORKSPACE/serde/src/private/de.rs:2347:1
         |
    2347 | pub trait IdentifierDeserializer<'de, E: Error> {
         | ----------------------------------------------- this is the found trait
         = help: you can use `cargo tree` to explore your dependency tree

The "this is the found trait" pointing to `IdentifierDeserializer` seems
like a compiler bug...
This commit is contained in:
David Tolnay
2025-09-12 19:32:00 -07:00
parent 908f32175a
commit 4bddf1b953
5 changed files with 128 additions and 8 deletions
+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;