Compiler bug? Two trait bounds that should be independent seem to get confused

⚓ Rust    📅 2026-03-31    👤 surdeus    👁️ 7      

surdeus

This is the best MRE I could come up with:

struct A;
struct B;

impl From<B> for A {
    fn from(_: B) -> A {
        A
    }
}

trait V {
    type E;
}

trait W {
    type E;
}

struct X;

impl W for X {
    type E = B;
}

fn inner<T>(_: T)
where
    T: W,
    A: From<<T as W>::E>,
{
}

fn outer<T>(_: T)
where
    T: V,
    A: From<<T as V>::E>,
{
    inner(X);
}

(Playground)

This results in a compile-time error:

error[E0271]: type mismatch resolving `<X as W>::E == <T as V>::E`
  --> src/lib.rs:36:5
   |
36 |     inner(X);
   |     ^^^^^^^^ type mismatch resolving `<X as W>::E == <T as V>::E`
   |
note: expected this to be `<T as V>::E`
  --> src/lib.rs:21:14
   |
21 |     type E = B;
   |              ^
   = note: expected associated type `<T as V>::E`
                       found struct `B`
help: consider constraining the associated type `<T as V>::E` to `B`
   |
33 |     T: V<E = B>,
   |         +++++++

For more information about this error, try `rustc --explain E0271`.

It seems the compiler concludes that since A is bounded by From<T> on both functions, and one calls the other, that the two Ts must be the same, but this is false. There are two ways to make this compile:

  1. Remove the A: From<<T as V>::E> bound from outer.
  2. Change the bound to A: From<<T as V>::E> + From<<X as W>::E>, even though the additional bound shouldn't be required.
  3. Transform one of the bounds to the equivalent Into bound.

The fact that the first option allows the code to compile shows that the two Ts in From<T> are in fact totally independent -- there's just something about this specific pattern where the compiler seems to get confused and conclude they must be the same type.

Is there something I'm missing here or is this a bug? (Honestly, I have a strong suspicion I've seen this before and it was a bug, but if so then I can't come up with the search terms to find it again.)

In my real code, option 1 doesn't work since I need that bound, but option 2 is awkward because the W trait is private and the function is public.

3 posts - 2 participants

Read full topic

🏷️ Rust_feed