-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
error where expected and found future are the same #112010
Comments
Slightly smaller version without futures: playground fn call_a_callback<F, FR>(_: F)
where
F: Fn(&str) -> FR,
{}
fn make_future(_: &str) -> impl FnOnce() + '_ {
|| ()
}
fn main() {
call_a_callback(make_future);
}
related: #102400 Why this happensTo call the function The desugaring of the function item looks something like this: /// Type of the fn item `make_future`. Note no generics.
struct MakeFuture;
impl<'a> Fn<&'a str> for MakeFuture {
type Output = MakeFutureReturn<'a>;
fn call(_: &'a str) -> MakeFutureReturn<'a> { /* ... */ }
}
/// "Opaque" type of the return value of `make_future`.
/// Generic over the lifetime of the fn arg of `make_future`.
struct MakeFutureReturn<'a> { /* ... capture the `&'a str` maybe ... */ }
impl<'a> Future for MakeFutureReturn<'a> { /* ... */ } So the function call with the generic parameters filled in becomes: fn main() {
// Note that the compiler has to choose a concrete lifetime 'b here.
call_a_callback::<MakeFuture, MakeFutureReturn<'b>>(make_future);
} Next, the compiler has to verify the Maybe the diagnostic could ouput something like this?
How to make it workpile of bad code, unrelated to the diagnostics issueTo make the error go away, you have to prevent the compiler from choosing the wrong lifetime for use std::pin::Pin;
use std::future::Future;
async fn call_a_callback<F>(f: F)
where
F: for<'a> Fn(&'a str) -> Box<dyn Future<Output = ()> + 'a>
{
let s = "hello";
Pin::from(f(&s)).await
}
async fn print_s(s: &str) {
println!("got {s}");
}
fn make_future<'a>(s: &'a str) -> Box<dyn Future<Output=()> + 'a> {
Box::new(print_s(s))
}
#[tokio::main]
async fn main() {
call_a_callback(|s| Box::new(print_s(s))).await;
call_a_callback(make_future).await;
call_a_callback(|s| Box::new(async move {
println!("got {s}");
})).await;
} But muh zero-cost abstractions?!?If you really want to make this work without boxing, this can be done with a combination of generic associated types (GAT) and type alias impl trait (TAIT) on the nightly compiler: playground #![feature(type_alias_impl_trait)]
use std::future::Future;
trait FutureFamily<Output> {
type Future<'a>: Future<Output = Output>;
}
async fn call_a_callback<F, FR: FutureFamily<()>>(f: F)
where
F: for<'a> Fn(&'a str) -> FR::Future<'a>,
{
let s = "hello";
f(&s).await
}
async fn print_s(s: &str) {
println!("got {s}");
}
type NamedFuture<'a> = impl Future<Output=()> + 'a;
struct NamedFutureFamily;
impl FutureFamily<()> for NamedFutureFamily {
type Future<'a> = NamedFuture<'a>;
}
fn make_future<'a>(s: &'a str) -> NamedFuture<'a> {
print_s(s)
}
#[tokio::main]
async fn main() {
call_a_callback::<_, NamedFutureFamily>(make_future).await;
} This is quite ugly, but works, because now the generic |
Thank you so much for diving deep on my report! |
This looks like the same issue as #74497, so I'll resolve it in favor of that one. The main thing to fix here is some kind of improve error message. |
I tried this code:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5c0da276115b23a4478fd825fb91f21a
(I'm trying to get some way to port the rustup test suite which uses closures to run test within the context of the framework over to async code)
I got this error:
On
The following error
Meta
rustc --version --verbose
: (from playground, not sure how to get --verbose there)I'm not entirely sure what is going on.
What I hoped would happen is that the future returned from make_future would be suitable for awaiting on in call_a_callback - the bigger picture is I'm trying to port rustups test suite to async, and this is a minimal reproduction of the code style there, where async lifetime errors are being a nuisance ;)
The text was updated successfully, but these errors were encountered: