Does trait bound ordering matter?

Can anyone shed some light on why this may be happening? Not sure if this is a compiler bug (known or unknown) or just a gap in my understanding.
I'm half expecting the reply "GAT hasn't landed yet" :smile:

The issue

A type Num derived from a trait is bound by both Mul<Self::Num> and Mul<Self::Distraction>.
When I attempt to multiply two values of the Num type, the compiler errors:
expected Trait::Distraction, found Trait::Num.

I stumbled upon this oddity in a larger context (unit conversion system where I use the result of the multiplication for further processing before returning from the function), but I didn't believe the compiler error.
Simplifying down to the essentials, it also duplicates on the playground:

pub trait Trait {
    type Num: Copy
        + Mul<Self::Num, Output = Self::Num>
        + Mul<Self::Distraction, Output = Self::Num>;
    type Distraction: Copy;
}
/// ... snip from a larger type impl ...
fn mul<T: Trait>(a: T::Num, b: T::Num) -> T::Num {
    // using explicit function -- WORKS!
    let explicit_function: T::Num = <T::Num as Mul<T::Num>>::mul(a, b);
    // original impl -- COMPILE ERROR: expected Trait::Distraction, found Trait::Num
    a * b
}

Strange ways the error disappears

What seems stranger to me is what makes the error disappear:

  1. removing the trait by redefining Num and Distraction as generic type parameters to the function itself (see fixed playground 1), or
  2. swapping the order of the trait bounds on lines 5, 6 (see fixed playground 2).

If it weren't for #2, I'd be OK with "the compiler just does this, it's expected". Curious if anyone has run into this before, or has any insight to share.
Thanks! :slight_smile:

1 Like
  1. compile on nightly

I think it's a shortcoming of the stable compiler. I'm not sure what's been updated on nightly that allows it to work there, perhaps Chalk is further along on nightly? Maybe someone else will be able to speculate when this improvement might hit stable.

The trait resolver had some implicit reliance on the ordering of the bounds, but there was a recent change in trait resolution that makes this compile in nightly now.

2 Likes

I believe the fix was https://github.com/rust-lang/rust/pull/73905, which fixed a lot of similar issues like https://github.com/rust-lang/rust/issues/72582

3 Likes

Thanks for the info everyone! I appreciate the links.

Good to know this is a known issue that is fixed in nightly. Just a matter of time until it hits stable, I guess.