Description
Simple example:
fn foo(x: Result<i32, ()>) -> Result<(), ()> {
let y: u32 = x?;
Ok(())
}
Compilation result (rust version 1.44.0-nightly (52fa23add 2020-04-18)
):
error[E0308]: try expression alternatives have incompatible types
--> src/lib.rs:2:18
|
2 | let y: u32 = x?;
| ^^ expected `u32`, found `i32`
|
help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
|
2 | let y: u32 = x?.try_into().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^
Parts of this diagnostic are great, showing the mismatched types (u32
and i32
) and even suggesting a valid possible fix. But the wording of the error itself is confusing. What "try expression alternatives"? I don't see any alternatives.
Taking a glance at the compiler implementation, it's referring to the arms of the match
block that ?
desugars into. But it's confusing to talk about those, because:
-
They're not visible to the user.
-
Why would there be a type mismatch between the arms in the first place, if there are only two arms and one of them always ends in a
return
rather than producing a value? Did type inference infer the error branch as having typeu32
due to the context?If so, the message is technically accurate, but unhelpful: from the user's point of view, the 'real' issue is a mismatch between the expected type of
x?
(namelyi32
) and the context. As far as I can imagine, this is the only possible cause of a type mismatch between the arms of a desugared?
. So it seems like it would be fine to just change the error message to not mention the arms.
As a sidenote, if I take the -Zunpretty=hir
output and try to compile that:
#![feature(try_trait)]
use std::ops::Try;
use std::convert::From;
fn foo(x: Result<i32, ()>) -> Result<(), ()> {
let y: u32 = match Try::into_result(x) {
Ok(val) => val,
Err(err) => return Try::from_error(From::from(err)),
};
Ok(())
}
...oddly enough, I don't get a "match arms have incompatible types" error, but a more helpful one instead:
error[E0308]: mismatched types
--> q.rs:6:20
|
6 | Ok(val) => val,
| ^^^ expected `u32`, found `i32`
|
help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
|
6 | Ok(val) => val.try_into().unwrap(),
| ^^^^