Repository: rust
Issue: Failure to consistently choose between inherent impl and trait method inside an async block
Labels: A-type-system,T-lang,T-compiler,C-bug,T-types

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

I tried this code:

```rust
use core::ptr;
use std::fmt::Debug;
use std::future::Future;
use std::marker::PhantomData;

struct MaybeDebug<T>(PhantomData<T>);
impl<T> MaybeDebug<T> {
    fn new(_: *const T) -> Self {
        Self(PhantomData)
    }
}

impl<T: Debug> MaybeDebug<T> {
    // This method is preferred, but only exists if T has a Debug implementation
    pub fn maybe_debug(&self) -> Option<&dyn Debug> {
        Some(&self.0)
    }
}

trait NoDebug {
    // The trait method should take over if there is no debug implementation.
    fn maybe_debug(&self) -> Option<&dyn Debug> {
        None
    }
}
impl<T> NoDebug for MaybeDebug<T> {}

// There is no Debug impl for X, so the trait method should be chosen for X
pub struct X;

// This works
fn foo() -> X {
    let p = ptr::null();
    if false {
        return unsafe { ptr::read(p) };
    }
    let q = MaybeDebug::new(p);
    println!("{:?}", q.maybe_debug());
    X
}

// This works too
fn fee() -> impl Fn() -> X {
    || {
        let p = ptr::null();
        if false {
            return unsafe { ptr::read(p) };
        }
        let q = MaybeDebug::new(p);
        println!("{:?}", q.maybe_debug());
        X
    }
}

// Even this works
async fn fae() -> X {
    let p = ptr::null();
    if false {
        return unsafe { ptr::read(p) };
    }
    let q = MaybeDebug::new(p);
    println!("{:?}", q.maybe_debug());
    X
}

// This doesn't
fn bar() -> impl Future<Output = X> {
    async {
        let p = ptr::null();
        if false {
            return unsafe { ptr::read(p) };
        }
        let q = MaybeDebug::new(p);
        println!("{:?}", q.maybe_debug());
        X
    }
}

fn main() {}
```
In each function the type of variable `p` is constrained to be `*const X`.
This constrains `q` to be of type `MaybeDebug<X>`.
Since `X` doesn't have a `Debug` impl, the inherent impl `MaybeDebug::<X>::maybe_debug` doesn't exist and the trait method `<MaybeDebug::<X> as NoDebug>::maybe_debug` is chosen instead.
Especially `fae` and `bar` should behave absolutely identical.
Instead `bar` fails to compile with following error:
```
error[E0277]: `X` doesn't implement `Debug`
  --> src/main.rs:74:28
   |
74 |         println!("{:?}", q.maybe_debug());
   |                            ^^^^^^^^^^^ `X` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `X`
   = note: add `#[derive(Debug)]` to `X` or manually `impl Debug for X`
note: required by a bound in `MaybeDebug::<T>::maybe_debug`
  --> src/main.rs:13:9
   |
13 | impl<T: Debug> MaybeDebug<T> {
   |         ^^^^^ required by this bound in `MaybeDebug::<T>::maybe_debug`
14 |     // This method is preferred, but only exists if T has a Debug implementation
15 |     pub fn maybe_debug(&self) -> Option<&dyn Debug> {
   |            ----------- required by a bound in this associated function
help: consider annotating `X` with `#[derive(Debug)]`
   |
29 + #[derive(Debug)]
30 | pub struct X;
   |

For more information about this error, try `rustc --explain E0277`.
error: could not compile `fooobar` (bin "fooobar") due to 1 previous error
```

### 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 1.77.0-nightly (e51e98dde 2023-12-31)
binary: rustc
commit-hash: e51e98dde6a60637b6a71b8105245b629ac3fe77
commit-date: 2023-12-31
host: x86_64-unknown-linux-gnu
release: 1.77.0-nightly
LLVM version: 17.0.6
```
</p>
</details>