Dubious compiler error when using `#[derive(Deserialize)]` on `Option<bool>` with incorrect `deserialize_with`

I ended up with a weird compiler error message with the following code (see playground).

use serde::Deserialize;

pub fn custom_deserialize<'de, D>(deserializer: D) -> Result<bool, D::Error>
    D: serde::Deserializer<'de>,

struct Foo {
    #[serde(deserialize_with = "custom_deserialize")]
    bar: Option<bool>,

The error message that seems dubious is

error[E0308]: mismatched types
  --> src/lib.rs:10:10
10 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^ expected enum `std::option::Option`, found `bool`
   = note: expected enum `std::option::Option<bool>`
              found type `bool`
   = note: this error originates in the macro `try` (in Nightly builds, run with -Z macro-backtrace for more info)
help: try wrapping the expression in `Some`
10 | #[derive(Some(Deserialize))]
   |          +++++           +

Note that the code does have an error since the struct takes an Option<bool> but the custom_deserialize function returns only a bool. In this case, I'm wondering if this is more a compiler problem? Or a macro problem (on serde side)?

My goal is to report an issue, but I prefer to not report on the wrong project.

This is a compiler suggestion, so the bug is in the compiler. It tries to be smart by suggesting adding Some(T) around a value of type T when T is found in code but an Option<T> is requested. However, it uses span and source information from the code where it found the error, and apparently, the #[derive]d implementation is spanned to the macro invocation site (hence, the argument of the derive attribute itself).

I'm not sure whether this is possible to resolve without changing the compiler. The problem is that the derive macro itself generates new code that is in no way related to the existing code. Hence, it's not possible for the macro itself to generate a meaningful, fresh span by itself (at least not via the current proc_macro API). Here, the compiler would have to be smarter to realize that it should output the actual generated expression that errors, instead of nonsensically surrounding the macro attribute itself with Some(…).

1 Like

There have been other cases where the compiler has been taught not to suggest code edits around "call site" spans from a derive macro, so at least in theory the compiler could determine not to emit the bad suggestion.

1 Like