rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.38k stars 12.45k forks source link

Function works but non-capturing closure with identical signature fails with strange error #81326

Open angelsl opened 3 years ago

angelsl commented 3 years ago

Playground

I'm trying to use the solution suggested for a separate problem here.

The solution works with a coerced function item, but not a closure that is virtually identical.


use std::future::Future;

trait AsyncFn1Arg<'a, Arg: 'a, Ret: 'a> {
    type Fut: Future<Output=Ret> + 'a;
    fn call(&self, arg: Arg) -> Self::Fut;
}

impl<'a, Arg: 'a, Ret: 'a, Fut: Future<Output=Ret> + 'a, F: Fn(Arg) -> Fut> AsyncFn1Arg<'a, Arg, Ret> for F {
    type Fut = Fut;
    fn call(&self, arg: Arg) -> Fut {
        self(arg)
    }
}

async fn f(arg: &i32) {
}

async fn func<F>(f: F)
    where F: for<'a> AsyncFn1Arg<'a, &'a i32, ()>
    {
        let x: i32 = 0;
        f.call(&x).await;
}

fn main() {
    // works
    func(f);
    // fails
    func(|a| f(a));
}

produces

error[E0308]: mismatched types
  --> src/main.rs:29:5
   |
29 |     func(|a| f(a));
   |     ^^^^ lifetime mismatch
   |
   = note: expected type `FnOnce<(&'a i32,)>`
              found type `FnOnce<(&i32,)>`
note: this closure does not fulfill the lifetime requirements
  --> src/main.rs:29:10
   |
29 |     func(|a| f(a));
   |          ^^^^^^^^
note: the lifetime requirement is introduced here
  --> src/main.rs:19:14
   |
19 |     where F: for<'a> AsyncFn1Arg<'a, &'a i32, ()>
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error
angelsl commented 3 years ago

This may or may not be the same issue as #70263.

leo60228 commented 3 years ago

I've triggered almost this exact problem.

traviscross commented 6 months ago

@rustbot labels +AsyncAwait-Triaged +WG-async

We reviewed this today in WG-async triage.

This is indeed not supported in Rust today. You can't have higher ranked closures that return futures that capture higher ranked arguments.

You're going to want to use async closures for this (currently on nightly).