Skip to content

Recursively-defined trait misevaluation due to "harmless" extra bounds #141371

Closed as duplicate of#24066
@apodolsk

Description

@apodolsk

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions