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: