Repository: rust
Issue: Fulfilling trait bound with blanket impl can cause associated type mismatch
Labels: A-associated-items,C-bug,T-types,fixed-by-next-solver

Hello,
I have two traits, one that is to be manually implemented by the user and the other, if the first was implemented in a valid way, is automatically blanket implemented on the same type.

If I bound that the first trait must also implement the second, so the compiler points out invalid implementations of it, certain situations can cause associated types to mismatches when they are actually the same.

Minimal code to replicate:
```rs
trait Foo: Bar {
    type X;
    fn take_x(x: Self::X);
}

trait Bar {
    type Y;
    fn take_y(y: Self::Y);
}

impl<T> Bar for T
where
    T: Foo, /*and other bounds to validate Foo impl*/
{
    type Y = T::X;
    fn take_y(y: Self::Y) {
        T::take_x(y);
    }
}
```
Causes this error:

```
Compiling playground v0.0.1 (/playground)
error[[E0308]](https://doc.rust-lang.org/stable/error_codes/E0308.html): mismatched types
  --> src/lib.rs:17:19
   |
17 |         T::take_x(y);
   |         --------- ^ expected `Foo::X`, found `Bar::Y`
   |         |
   |         arguments to this function are incorrect
   |
   = note: expected associated type `<T as Foo>::X`
              found associated type `<T as Bar>::Y`
   = note: an associated type was expected, but a different one was found
note: associated function defined here
  --> src/lib.rs:3:8
   |
3  |     fn take_x(x: Self::X);
   |        ^^^^^^
```

[On the Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b19a9623a2dba94ec7439da221026924), while the result is the same on Nightly as well.

<hr>

### Workaround 1: Bound at caller site instead

<details>

One fix is to not bound `Bar` on `Foo`.

```rs
trait Foo/*: Bar*/ {
    type X;
    fn take_x(x: Self::X);
}
```

[On the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=94e5833b02ab2407b8a3338650ce8118). 

That has the downside that the compiler cannot point out invalid implementations of `Foo` before one attempts to use the type somewhere, where now the additional bound with `+ Bar` has to be enforced. 
</details>

<hr>

### Workaround 2: Impl detail to trait bound

<details>

Another is to bound the types to match in the `Foo` bound already:

```rs
trait Foo: Bar<Y = Self::X> {
    type X;
    fn take_x(x: Self::X);
}

//...
```

[On the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c9915619380677c650a1cc3577358c9a).
This compiles and might be a solution for some, depending how the actual bounds look like.
This also limits users who want to manually implement `Bar` for their type where the associated types are not equal.
</details>

<hr>

### Failing workaround 1: Another generic in the impl

<details>

One could attempt to bring in another generic into the implementation, but this makes the compiler complain as well and also suggest a solution that is not valid Rust:

```rs
//...

impl<T, U> Bar for T
where
    T: Foo<X = U>, /*and other bounds to validate Foo impl*/
{
    type Y = U;
    fn take_y(y: Self::Y) {
        T::take_x(y);
    }
}
```
```
Compiling playground v0.0.1 (/playground)
error[[E0308]](https://doc.rust-lang.org/stable/error_codes/E0308.html): mismatched types
  --> src/lib.rs:17:19
   |
11 | impl<T, U> Bar for T
   |         - this type parameter
...
17 |         T::take_x(y);
   |         --------- ^ expected type parameter `U`, found associated type
   |         |
   |         arguments to this function are incorrect
   |
   = note: expected type parameter `U`
             found associated type `<T as Bar>::Y`
note: associated function defined here
  --> src/lib.rs:3:8
   |
3  |     fn take_x(x: Self::X);
   |        ^^^^^^
help: consider further restricting this bound
   |
13 |     T: Foo<X = U> + <Y = U>, /*and other bounds to validate Foo impl*/
   |                   +++++++++
```
[On the Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=37869bd7c6227c1117e6570e42cfed46) and [here with the invalid suggestion](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ec51b53856b67bfeadf2557ca97be183). The behavior is again the same on Nightly here.
</details>

<hr>

### Failing workaround 2: Supertrait

<details>

Another attempt is using a super trait, but bounding `Foo` causes a cyclic recursion again, and bounding only `Bar` results in the super trait to be basically an alias of the top code with the same error.

```rs
pub trait FooAndBar: Foo + Bar {}
impl<T> FooAndBar for T where T: Foo + Bar {}

trait Foo: FooAndBar {
    type X;
    fn take_x(x: Self::X);
}

//...
```

If one moves the bounds of the super trait to the impl, it compiles, but lacks the ability to access the implementations of `Foo` and `Bar` now. One would have to mirror both traits in here and [this will cause the initial problem again](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7a896311fb43d8887352b12fb93f4bda), now in this third trait.
</details>

<hr>

My assumption is that the compiler within the blanket impl assumes that the trait is already implemented and calling `T::take_x(y);` considers an unspecific implementation where the types might not match.