I've a function which takes a generic parameter, gets what it needs out of that, then returns a future. The future does not actually store the generic data, it is completely monomorphic.
For convenience I wanted to use an async fn
to create the future, which I understand requires returning an impl Future
as async fn
return opaque types: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c3b061d12a126dc30099ac3bd018c273
use std::io::{Read, stdin};
use std::fs::File;
use std::future::Future;
use std::path::Path;
fn caller(p: Option<&Path>) -> impl Future<Output=()> {
if let Some(p) = p {
f(File::open(p).unwrap())
} else {
f(stdin())
}
}
fn f<R: Read>(_: R) -> impl Future<Output=()> {
fut()
}
async fn fut() {}
However rustc freaks out in the conditional as the caller side is absolutely convinced the future must somehow be different between the two branches:
error[E0308]: `if` and `else` have incompatible types
--> src/lib.rs:10:9
|
7 | / if let Some(p) = p {
8 | | f(File::open(p).unwrap())
| | ------------------------- expected because of this
9 | | } else {
10 | | f(stdin())
| | ^^^^^^^^^^ expected struct `File`, found struct `Stdin`
11 | | }
| |_____- `if` and `else` have incompatible types
...
14 | fn f<R: Read>(_: R) -> impl Future<Output=()> {
| ---------------------- the found opaque type
|
= note: expected type `impl Future<Output = ()>` (struct `File`)
found opaque type `impl Future<Output = ()>` (struct `Stdin`)
Is there a way to fix this aside from boxing the future or hand-rolling fut
in order to end up with a single concrete type?
I don't think you can avoid boxing, but at least you can avoid boxing the future itself:
use std::io::{Read, stdin};
use std::fs::File;
use std::future::Future;
use std::path::Path;
fn caller(p: Option<&Path>) -> impl Future<Output=()> {
let read = if let Some(p) = p {
Box::new(File::open(p).unwrap()) as Box<dyn Read>
} else {
Box::new(stdin())
};
f(read)
}
fn f<R: Read>(_: R) -> impl Future<Output=()> {
fut()
}
async fn fut() {}
As my understanding, the problem is not the future, but that is actually building different types for the parameters, and somehow floods into the return type. It would makes sense it wouldn't though.
Playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With