Confusing type inference error with json!() macro

The following code results in two compiler errors:

use serde::Deserialize;
use serde_json::json;

#[derive(Deserialize, Eq, PartialEq)]
struct Foo {
    bar: u32,
}

fn main() {
    let foo: Foo = serde_json::from_value(json!({"bar": 42})).unwrap();
    let glonk = Foo { bar: 42 };
    assert_eq!(foo, glonk);
}

(Playground)

The first error is "Foo doesn't implement Debug" on the last line, which is easy to understand – assert_eq!() requires Debug. The other error is quite weird, though:

error[E0283]: type annotations needed
   --> src/main.rs:10:43
    |
10  |     let foo: Foo = serde_json::from_value(json!({"bar": 42})).unwrap();
    |                                           ^^^^^^^^^^^^^^^^^^ cannot infer type for type `{integer}`
    |
    = note: multiple `impl`s satisfying `{integer}: Serialize` found in the `serde` crate:
            - impl Serialize for i128;
            - impl Serialize for i16;
            - impl Serialize for i32;
            - impl Serialize for i64;
            and 8 more
    = note: required because of the requirements on the impl of `Serialize` for `&{integer}`

This error disappears once I add a Debug implementation for Foo, or once I remove the assert_eq!(), but it's still confusing. Why is anything requiring Serialize here? And why has the compiler suddenly trouble inferring the type of the integer? Annotating the integer as 42u32 also fixed the error.

The json!() macro uses serde_json::to_value to turn 42 into a serde_json::Value. to_value needs it's argument to implement Serialize. The problem in your case is that any integer type would be valid, so rustc doesn't know which ine to choose.

That makes some amount of sense. It's still very confusing that this suddently works once I remove the assert_eq!() invocation.

Moreover, this works just fine:

let _value = serde_json::to_value(42);

Weird

I've seen this a lot myself: when there's a type/trait-related compilation failure in my program, “type annotations needed” can pop up, even in entirely unrelated places. I suspect what's happening is that the first error causes a type inference / trait resolution pass to fail, and then a later stage scans it for unresolved literal types (this also happens with ambiguous slice literals like &[], not just integers) and reports "type annotations needed" for those, before the point at which the compiler decides to stop entirely.

2 Likes