Type inference for Result<Option<T>, ()>.unwrap().unwrap()


#1

I am tracking down a recent Serde regression that causes it to generate code that does not compile. I have narrowed it down to something equivalent to this:

fn f<F>() -> Result<Option<F>, ()> {
    panic!()
}

fn g<G>() -> Option<G> where Option<G>: Sized {
    f().unwrap().unwrap()
}

This fails with:

 expected `std::option::Option<G>`,
    found `G`
(expected enum `std::option::Option`,
    found type parameter) [E0308]
src/main.rs:6     f().unwrap().unwrap()
                  ^~~~~~~~~~~~~~~~~~~~~

I don’t understand how type inference works, but in this case my expectation would be that f() returns Result<Option<F>, ()> so the type of f().unwrap().unwrap() is F, and we want the type to be Option<G>, so F == Option<G>. Indeed, this is how things work if there is no where clause.

Any idea why the where clause puts a spanner in the works? Is this something that can be fixed?

It works if I change it to f::<Option<G>>().unwrap().unwrap(), but shouldn’t that be inferred?


#2

That is indeed a surprising error, and it seems like a bug to me. Does the turbofish (::<Option<G>>) solve your problem in practice?


#3

Constructing the minimal example above is as far as I got before work today (it is pretty far removed from the original 100+ lines across a dozen traits and structs and dozens of methods). I will try implementing the turbofish workaround tonight to see whether it solves the problem in practice.


#4

Turbofish solved the problem in practice (PR serde#308). Also thanks to @notriddle for filing a Rust ticket to look at whether this situation can be improved.