Repository: rust
Issue: TAIT: hidden type cannot be another opaque type from the same scope
Labels: A-diagnostics,P-low,T-compiler,A-impl-trait,F-type_alias_impl_trait

I wanted to write a function that statically allocates an `async fn` future: [playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=c94b09d28daffb9b2a3d44d97c754a74)

```rust
fn task(arg: Foo) -> &'static mut impl Future {
    async fn task_inner(arg: Foo) {
        // code
    }

    type Fut = impl Future;
    static mut FUT: MaybeUninit<Fut> = MaybeUninit::uninit();
    unsafe { FUT.write(task_inner(arg)) }
}
```

This fails with the following error:

```
error: opaque type's hidden type cannot be another opaque type from the same scope
  [--> src/lib.rs:8:47
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
8  |   fn task(arg: Foo) -> &'static mut impl Future {
   |  _______________________________________________^
9  | |     async fn task_inner(arg: Foo) {
10 | |         // code
11 | |     }
...  |
15 | |     unsafe { FUT.write(task_inner(arg)) }
16 | | }
   | |_^ one of the two opaque types used here has to be outside its defining scope
   |
note: opaque type whose hidden type is being assigned
  [--> src/lib.rs:8:35
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
8  | fn task(arg: Foo) -> &'static mut impl Future {
   |                                   ^^^^^^^^^^^
note: opaque type being used as hidden type
  [--> src/lib.rs:13:16
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
13 |     type Fut = impl Future;
   |                ^^^^^^^^^^^
```

One workaround is to move the `Fut` to the top level, but that's undesirable because it makes the entire file to be the defining scope, which interferes with other code.

A better workaround suggested by @oli-obk is to wrap the inner future in a "dumb" wrapper, so that the types are no longer equal (the RPIT can't be another opaque type itself, but it can still contain one): [playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=b99429198d4e559c57401fd9bfeea301)

```rust
struct FutureWrapper<F>(F);
impl<F: Future> Future for FutureWrapper<F> {
    type Output = F::Output;
    fn poll(
        self: Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }.poll(cx)
    }
}

fn task(arg: Foo) -> &'static mut impl Future {
    async fn task_inner(arg: Foo) {
        // code
    }

    type Fut = impl Future;
    static mut FUT: MaybeUninit<FutureWrapper<Fut>> = MaybeUninit::uninit();
    unsafe { FUT.write(FutureWrapper(task_inner(arg))) }
}
```

First, it would be interesting to see if these "nested opaque types" can be allowed in some cases such as this one.

> @oli-obk we could possibly allow your case (which has an obvious order of which opaque type should be the hidden type of the other one, or just by equating their hidden types)
> The fixes to just allow it are likely not complex in implementation, but require quite some design work to make sure we don't paint ourselves into a corner
> We could just put it behind a feature gate tho

Second, it would be helpful if the diagnostic suggested the "wrapper" workaround. It would've saved me a lot of time at least :) 

See also: [Zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/315482-t-compiler.2Fetc.2Fopaque-types/topic/hidden.20type.20cannot.20be.20another.20opaque.20type.20from.20the.20same.20scop)