Skip to content

Trait *definition* is rejected if assoc type has bound with an implied predicate on itself #149677

@danielhenrymantilla

Description

@danielhenrymantilla

Imagine you have the following (cf. https://docs.rs/imply-hack, and/or https://docs.rs/implied-bounds):

// 0.
mod implied_bounds {
    pub trait ImpliedPredicate<X: ?Sized> : HasAssociatedImpls<X, Impls = X> {}
    pub trait HasAssociatedImpls<X: ?Sized> { type Impls: ?Sized; }
    
    impl<T: ?Sized, X: ?Sized> ImpliedPredicate<X> for T {}
    impl<T: ?Sized, X: ?Sized> HasAssociatedImpls<X> for T { type Impls = X; }
}
use implied_bounds::ImpliedPredicate;

trait SomeBound {}

// 1.
trait HasImpliedBoundOnSelf
:
    ImpliedPredicate<Self ,Impls: SomeBound> // <- the specific bound does not matter
{}

// 2. HEREIN LIES THE ISSUE
trait HasAssocWithImplyingBoundSuperTrait {
    // ERROR, missing `SomeBound` on `Self::Assoc`.
    type Assoc: HasImpliedBoundOnSelf;
}

I expected to see this happen: trait declarations (with no "bad" impls) to be allowed.

Instead, this happened: the trait HasAssocWithImplyingBoundSuperTrait definition is rejected.

error[E0277]: the trait bound `<Self as HasAssocWithImplyingBoundSuperTrait>::Assoc: SomeBound` is not satisfied
  --> <source>:21:17
   |
21 |     type Assoc: HasImpliedBoundOnSelf; // <- ERROR, missing `Send` on `Self::Assoc`.
   |                 ^^^^^^^^^^^^^^^^^^^^^ the trait `SomeBound` is not implemented for `<Self as HasAssocWithImplyingBoundSuperTrait>::Assoc`
   |
note: required by a bound in `HasImpliedBoundOnSelf`
  --> <source>:16:35
   |
14 | trait HasImpliedBoundOnSelf
   |       --------------------- required by a bound in this trait
15 | :
16 |     ImpliedPredicate<Self ,Impls: SomeBound> // <- the specific bound does not matter
   |                                   ^^^^^^^^^ required by this bound in `HasImpliedBoundOnSelf`
help: consider further restricting the associated type
   |
20 | trait HasAssocWithImplyingBoundSuperTrait where <Self as HasAssocWithImplyingBoundSuperTrait>::Assoc: SomeBound {
   |                                           +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Meta

rustc --version --verbose: This happens since 1.79.0 (permalink), when the assoc type bounds got stabilized, all the way to current nightly:

1.93.0-nightly 2025-12-04 b33119ffdd483969934b

@rustbot label +A-trait-system +F-associated_type_bounds


Rationale

Click to see

As to some rationale behind the odd pattern (e.g., rather than a mere super-trait on Self in this instance): https://docs.rs/named-generics-bundle.

There, I want a trait to imply certain non-dyn-safe bounds such as Clone (to work around non-perfect derives later on with type-level-only generics), but I also want the trait, or a close version thereof, to be dyn-safe.

I achieve this by doing the following:

trait TargetTrait<Helper = Self>: ImpliedPredicate<Helper ,Impls: Clone> {
    type Assoc :;
    // …
}

This way:

  1. dyn TargetTrait<(), …> is well-formed;
  2. X: TargetTrait entails : Clone.

From there, I can do the following:

impl<Dyn : ?Sized + TargetTrait<()>> TargetTrait for PhantomData<Dyn> {
    type Assoc = Dyn::Assoc;
}

// So that `PhantomData<dyn TargetTrait<(), Assoc = …>> : TargetTrait`!

Final, ergonomic touch:

macro_rules! TargetTrait {( $($assoc:tt)* ) => (
    ::core::marker::PhantomData<
        dyn TargetTrait<(), $($assoc)*>
    >
)}

And we get the final result:

fn some_api<T: TargetTrait>() {
    let _: T::SomeAssoc; // It Works!
}

some_api::<TargetTrait![SomeAssoc = …]>() // Named generic params!

But doing all this runs into issues the moment someone does:

trait AnotherTrait {
    type Assoc: TargetTrait; // <- Error, `Self::Assoc : Clone` is not fulfilled!
}

which is what this very issue is about.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-trait-systemArea: Trait systemC-bugCategory: This is a bug.F-associated_type_bounds`#![feature(associated_type_bounds)]`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