Failure to consistently choose between inherent impl and trait method inside an async block
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.2k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
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
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the self-contained reproduction in src/main.rs and compile it with the reported rustc nightly version. Compare the behavior of foo, fee, fae, and bar, focusing on method selection inside the async block. Done means the equivalent async forms consistently select the applicable method or the behavior is clearly covered by a compiler test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100