Skip to content

Bad error messages if functions passed to #[serde(with)] have wrong signatures #2636

@mkrasnitski

Description

@mkrasnitski

I am unsure if this is more a rustc problem than a serde one. A small motivating example:

use serde::{Serialize, Deserialize};
use std::num::NonZeroU64;

#[derive(Serialize, Deserialize)]
struct Foo(#[serde(with = "snowflake")] NonZeroU64);

mod snowflake {
    use super::*;
    
    use std::fmt;
    use serde::{Deserializer, Serializer};
    use serde::de::Visitor;
    
    pub fn serialize<S>(id: &NonZeroU64, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer
    {
        unimplemented!()
    }
    
    pub fn deserialize<'de, D>(deserializer: D) -> Result<NonZeroU64, D::Error>
    where
        D: Deserializer<'de>
    {
        unimplemented!()
    }
}

If snowflake::serialize is changed to take NonZeroU64 instead of &NonZeroU64, the help message produced by the compiler is pretty outrageous:

Click to expand error
error[E0308]: mismatched types
  --> src/main.rs:4:10
   |
4  | #[derive(Serialize, Deserialize)]
   |          ^^^^^^^^^
   |          |
   |          expected `NonZeroU64`, found `&NonZeroU64`
   |          arguments to this function are incorrect
   |
note: function defined here
  --> src/main.rs:14:12
   |
14 |     pub fn serialize<S>(id: NonZeroU64, serializer: S) -> Result<S::Ok, S::Error>
   |            ^^^^^^^^^    --------------
   = note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider using clone here
   |
4  | #[derive(Serialize.clone(), Deserialize)]
   |                   ++++++++

For more information about this error, try `rustc --explain E0308`.

A similar problem occurs if snowflake::deserialize is changed to take &D instead of D, but at least in that case there is no weird help message and instead just a slightly cryptic error:

Click to expand error
error[E0308]: mismatched types
  --> src/main.rs:4:21
   |
4  | #[derive(Serialize, Deserialize)]
   |                     ^^^^^^^^^^^
   |                     |
   |                     expected `&_`, found type parameter `__E`
   |                     arguments to this function are incorrect
   |
   = note:   expected reference `&_`
           found type parameter `__E`
note: function defined here
  --> src/main.rs:21:12
   |
21 |     pub fn deserialize<'de, D>(deserializer: &D) -> Result<NonZeroU64, D::Error>
   |            ^^^^^^^^^^^         ----------------
   = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
  --> src/main.rs:4:21
   |
4  | #[derive(Serialize, Deserialize)]
   |                     ^^^^^^^^^^^
   |                     |
   |                     expected `&_`, found type parameter `__D`
   |                     arguments to this function are incorrect
   |
   = note:   expected reference `&_`
           found type parameter `__D`
note: function defined here
  --> src/main.rs:21:12
   |
21 |     pub fn deserialize<'de, D>(deserializer: &D) -> Result<NonZeroU64, D::Error>
   |            ^^^^^^^^^^^         ----------------
   = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.

I don't know how feasible it is to improve these error message and from what side this would need to be done. Is this something that's being tracked already in rustc? I'm guessing it touches on the larger topic of better error-generation for macros in general.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions