Open
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