Repository: rust
Issue: Confusing interaction between associated types, `async fn` and `impl Future`
Labels: A-lifetimes,T-compiler,C-bug,A-async-await,AsyncAwait-Triaged,WG-async,S-needs-repro

With the following files:
`Cargo.toml`:
```toml
[package]
name = "future_pin_issue"
version = "0.1.0"
authors = ["Joe Doyle <joethedoyle@protonmail.com>"]
edition = "2018"

[dependencies]
futures = "0.3.16"

[features]
use_async_fn = []
```
`src/main.rs`:
```rust
use futures::Future;
use std::pin::Pin;

pub struct MyBackend<'a> {
    _marker: std::marker::PhantomData<&'a ()>,
}

impl<'a> Backend<'a> for MyBackend<'a> {
    type MyStorage = AtomicStorage;
}

pub trait Storage<'a> {}

pub struct AtomicStorage {}
impl<'a> Storage<'a> for AtomicStorage {}

pub trait Backend<'a>: Send {
    type MyStorage: Storage<'a>;
    fn store<F>(&mut self, _update: F) -> Pin<Box<dyn Future<Output = ()> + Send>>
    where
        F: Fn(Self::MyStorage),
    {
        unimplemented!()
    }
}

// https://stackoverflow.com/questions/50547766/how-can-i-get-impl-trait-to-use-the-appropriate-lifetime-for-a-mutable-reference
pub trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}

#[cfg(feature = "use_async_fn")]
pub async fn transfer<'a, B: 'a + Backend<'a> + Send + Sync>(backend: &mut B) {
    backend.store(|_t| {}).await
}

#[cfg(not(feature = "use_async_fn"))]
pub fn transfer<'a, 'b, B: 'a + Backend<'a> + Send + Sync>(
    backend: &'b mut B,
) -> impl 'b + Captures<'a> + std::future::Future<Output = ()> + Send {
    async move { backend.store(|_t| {}).await }
}

// This works
fn _test1<'a>(mut backend: impl 'a + Backend<'a> + Send + Sync) {
    let _: Pin<Box<dyn Send>> = Box::pin(async {
        transfer(&mut backend).await;
    });
}

// This doesn't
fn _test2<'a>(mut backend: MyBackend<'a>) {
    let _: Pin<Box<dyn Send>> = Box::pin(async {
        transfer(&mut backend).await;
    });
}

fn _hidemytype<'a>(backend: MyBackend<'a>) -> impl 'a + Backend<'a> + Send + Sync {
    backend
}

// This does!
fn _test3<'a>(backend: MyBackend<'a>) {
    let _: Pin<Box<dyn Send>> = Box::pin(async {
        transfer(&mut _hidemytype(backend)).await;
    });
}

// And so does this
fn _test4<'a>(backend: MyBackend<'a>) {
    _test1(backend);
}

fn main() {}
```

It succeeds with `cargo build` (using the second `transfer`), but if you use the first `transfer` by running `cargo build --features use_async_fn`, you get a very confusing error:
```
$ cargo build --features use_async_fn
   Compiling future_pin_issue v0.1.0 (/home/joe/issue-test)
error: implementation of `Backend` is not general enough
  --> src/main.rs:52:33
   |
52 |       let _: Pin<Box<dyn Send>> = Box::pin(async {
   |  _________________________________^
53 | |         transfer(&mut backend).await;
54 | |     });
   | |______^ implementation of `Backend` is not general enough
   |
   = note: `Backend<'1>` would have to be implemented for the type `MyBackend<'0>`, for any two lifetimes `'0` and `'1`...
   = note: ...but `Backend<'2>` is actually implemented for the type `MyBackend<'2>`, for some specific lifetime `'2`

error: could not compile `future_pin_issue` due to previous error
```

The second `transfer` implementation (used when `use_async_fn` is off) is a workaround based on the desugar of `async fn`, plus a `Captures` trait I found on stackoverflow.

Confusingly, the error only ever occurs in `_test2`. `_test3` is especially concerning, because it means that "forgetting" information about the type makes the typechecking succeed somehow!

Removing the `Backend::<'a>::MyStorage` associated type, changing `store` to `store<F,MyStorage: Storage<'a>>`, and calling `backend.store::<_,AtomicStorage>(...)` rather than `backend.store(...)` also fixes the error.

This looks like a potential type inference bug, but it might be expected behavior. If it's expected, I think the error messages could use some work.

### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->

`rustc --version --verbose`:
```
$ rustc --version --verbose
rustc 1.55.0 (c8dfcfe04 2021-09-06)
binary: rustc
commit-hash: c8dfcfe046a7680554bf4eb612bad840e7631c4b
commit-date: 2021-09-06
host: x86_64-unknown-linux-gnu
release: 1.55.0
LLVM version: 12.0.1
```
```
$ cargo --version --verbose
cargo 1.55.0 (32da73ab1 2021-08-23)
release: 1.55.0
commit-hash: 32da73ab19417aa89686e1d85c1440b72fdf877d
commit-date: 2021-08-23
```