This seems related to #42424, except I don't see an obvious workaround like in #42424.
#![feature(async_await)]
use std::io::Error;
fn make_unit() -> Result<(), Error> {
Ok(())
}
fn main() {
let fut = async {
make_unit()?;
Ok(())
};
}
Fails with the error
error[E0282]: type annotations needed for `impl std::future::Future`
--> src/main.rs:11:9
|
10 | let fut = async {
| --- consider giving `fut` the explicit type `impl std::future::Future`, with the type parameters specified
11 | make_unit()?;
| ^^^^^^^^^^^^ cannot infer type
First of all, it seems like this shouldn't be an error--it should be able to deduce that the return type is Result<(), io::Error>, but also the diagnostic does not work. If you try to add impl std::future::Future<Output=Result<(), Error>> as a type annotation, it also fails to compile because impl Trait is only allowed as return types and argument types.
Opened https://github.com/rust-lang/rust/issues/63504 for the incorrect suggestion. For the main issue, ? interacts in non-obvious ways with type inference because it does implicit conversion. In this case, because fut doesn't explicitly constraint what the expected type is, rustc doesn't know what Result<(), std::io:Error> should be converted to.
There are other similar tickets filed about these kind of type inference issues: https://github.com/rust-lang/rust/issues/49391, https://github.com/rust-lang/rust/issues/38508, https://github.com/rust-lang/rust/issues/46333, https://github.com/rust-lang/rust/issues/46680, https://github.com/rust-lang/rust/issues/48089, https://github.com/rust-lang/rust/issues/61152, https://github.com/rust-lang/rust/issues/58517 and https://github.com/rust-lang/rust/issues/63082.
(larger work around ? tracked in https://github.com/rust-lang/rust/issues/31436)
I don't see an obvious workaround
The workaround is this:
use std::io::Error;
fn make_unit() -> Result<(), Error> {
Ok(())
}
fn main() {
let fut = async {
make_unit()?;
Ok::<(), Error>(())
};
}
Discussing as part of a "triage effort". A few notes:
Error value can be Into'd into. We lack a syntax. So maybe we can give a better diagnostic that at least hints at the solution. Or maybe an extended error code description.
For this case, we probably could suggest a temporary local binding with an explicit type:
let fut = async {
let x: Result<_, Error> = make_unit();
x?;
Ok(())
};
As for the syntax, we could borrow the closure syntax and allow something like async -> Result<(), Error> {} or async::<Result<(), Error> {}, but those are uuuugly.
CC https://github.com/rust-lang/rust/issues/62570, as it is not the same error, but it is similar enough code that these two errors will likely happen in short temporal distance of each other.
@estebank did you mean to include the ? after the x in your example above?
Yes, but was missing the final expr Ok(()) to be correctly equivalent the original code. Just updated it.
@estebank That code still would not compile-- the error type annotation doesn't help there because it gets .into()'d in the ? usage. To make it work, you need to annotate the type of the final Ok value.
You're absolutely right. Need more coffee.
doesn't ? still use From rather than Into, or did I miss some happy RFC?
Most helpful comment
The workaround is this: