I tried this code:
use std::marker::PhantomData;
use std::ops::Deref;
use std::fmt::Debug;
struct Foo {
}
impl Deref for Foo {
type Target=Bar;
fn deref(&self) -> &Self::Target {
todo!()
}
}
struct FooGeneric<V> {
_a: PhantomData<V>,
}
impl<V> Deref for FooGeneric<V> {
type Target=Bar;
fn deref(&self) -> &Self::Target {
todo!()
}
}
struct Bar;
pub trait DerefToBar {}
impl DerefToBar for Bar {}
impl<T> DerefToBar for T
where
T: Deref,
T::Target: DerefToBar
{}
fn require_trait<T>()
where
T: DerefToBar,
{
}
fn test<V>()
where
// Comment this out and rustc is happy.
FooGeneric<V>: Deref,
// Bounds involving totally unrelated traits are fine.
FooGeneric<V>: Debug,
// Explicitly requiring the full recursive trait is fine.
// FooGeneric<V>: DerefToBar,
// Types without a generic param are fine.
Foo: Deref,
{
require_trait::<Foo>();
require_trait::<FooGeneric<V>>();
}
I expect this to compile, but instead rustc can't find a DerefToBar impl for FooGeneric<V>, seemingly because it forgets that FooGeneric::Target is Bar:
error[E0277]: the trait bound `<FooGeneric<V> as Deref>::Target: Deref` is not satisfied
--> src/lib.rs:62:21
|
62 | require_trait::<FooGeneric<V>>();
| ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `<FooGeneric<V> as Deref>::Target`
|
= help: the trait `DerefToBar` is implemented for `Bar`
note: required for `<FooGeneric<V> as Deref>::Target` to implement `DerefToBar`
--> src/lib.rs:34:9
|
34 | impl<T> DerefToBar for T
| ^^^^^^^^^^ ^
35 | where
36 | T: Deref,
| ----- unsatisfied trait bound introduced here
= note: 1 redundant requirement hidden
= note: required for `FooGeneric<V>` to implement `DerefToBar`
note: required by a bound in `require_trait`
...
error[E0277]: the size for values of type `<FooGeneric<V> as Deref>::Target` cannot be known at compilation time
...
error[E0275]: overflow evaluating the requirement `{type error}: DerefToBar`
I noticed two interesting things here:
- The error disappears if you remove the seemingly harmless explicit
FooGeneric<V>: Deref bound.
- The error doesn't happen for a type without generic parameters, like
Foo, regardless of explicit bounds.
While the Deref bound is entirely pointless in test(), I think that I do need an explicit "induction trait" bound in real life. I can work around it by using the equivalent of a DerefToBar bound instead, but in the my real case that trait is an implementation detail that I'd like to avoid leaking.
This repros on 1.87 stable (https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=dc207f4b5c603d28024cb0da4fc42d70), though I'm running on nightly.
Meta
rustc --version --verbose:
rustc 1.87.0-nightly (43a2e9d2c 2025-03-17)
binary: rustc
commit-hash: 43a2e9d2c72db101f5fedac8b3acb78981b06bf2
commit-date: 2025-03-17
host: x86_64-unknown-linux-gnu
release: 1.87.0-nightly
LLVM version: 20.1.0
I tried this code:
I expect this to compile, but instead rustc can't find a
DerefToBarimpl forFooGeneric<V>, seemingly because it forgets thatFooGeneric::TargetisBar:I noticed two interesting things here:
FooGeneric<V>: Derefbound.Foo, regardless of explicit bounds.While the
Derefbound is entirely pointless intest(), I think that I do need an explicit "induction trait" bound in real life. I can work around it by using the equivalent of aDerefToBarbound instead, but in the my real case that trait is an implementation detail that I'd like to avoid leaking.This repros on 1.87 stable (https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=dc207f4b5c603d28024cb0da4fc42d70), though I'm running on nightly.
Meta
rustc --version --verbose: