Repository: rust
Issue:  Associated Type Equality Constraints Drop Trait Bounds
Labels: A-trait-system,T-compiler,C-bug

Apologies if this has been covered elsewhere, I wasn't able to find any issues or anything in the RFCs that addresses this specifically.

## Issue

Given a trait with an associated type that has some trait bounds:
```rust
trait Foo<T> {
    type X: Clone;
}

// An implementation, as an example:
impl<T: Clone> Foo<T> for () { type X = T; }
```

We can use this trait's associated type `X` (without constraining `X` to a particular type or adding bounds to it) while relying on `X: Clone`:
```rust
fn example4<A, Witness: Foo<A>>(a: &<Witness as Foo<A>>::X) -> <Witness as Foo<A>>::X {
    a.clone()
}
```

However if we are to bound `X` to a particular type (i.e. `Foo<_, X = A>`) we are no longer able to rely on `X: Clone`:
```rust
fn example1<A, Witness: Foo<A, X = A>>(a: &A) -> A {
    a.clone() // errors
}

// Note that the issue is not that `rustc` cannot unify `A` with
// `<Witness as Foo<A, X = A>>::X`; the following fail in the same way (and the
// error messages in all of these name `A` specifically):
//
// (this also be verified using something like `fn same_ty<A>(_: &A, _: &A) {}`,
// bounding both types with `Default` and passing `&<_ as Default>::default()`
// in, etc.)
fn example2<A, Witness: Foo<A, X = A>>(a: &<Witness as Foo<A>>::X) -> A {
    a.clone() // errors
}

fn example3<A, Witness: Foo<A, X = A>>(a: &<Witness as Foo<A>>::X) -> <Witness as Foo<A>>::X {
    a.clone() // errors
}
// Note that the only difference between ^ and `example4` is that ^ has `X = A`
// in its bound on `Witness`.
```

Note that for all of the above, `A` is required to be `Clone` (when `Witness = ()`) in order for _uses_ of the functions (or of `(): Foo<A, X = A>`) to typecheck:
```rust
// All of these fail to compile as you'd expect:
let _ = example1::<NotClone, ()>;
let _ = example2::<NotClone, ()>;
let _ = example3::<NotClone, ()>;
```

([playground link](https://play.integer32.com/?version=stable&mode=debug&edition=2021&gist=a86ee6bbad38affaab221c616d8d230c))

---

(this particular example is minified from something less contrived; as written this _is_ fairly nonsensical since there's not much reason to ask for `Witness: Foo<X = T>` instead of just bounding `T` directly)

## Misc

Prior to Rust 1.49 (I have not bisected to verify but I think the change traces back to #72788 and #73905), functions like `example{1,2,3}` were required to bound `A: Clone` themselves so that `Foo<A, X = A>` would be well-formed ([godbolt link](https://rust4.godbolt.org/z/s1MEsefa3)). In 1.49 and up this check seems to be deferred to usages of the function.

This also observable in other ways; for example:
```rust
struct NotClone;

// is the concrete type we specify for the associated type checked for the
// bounds on `X`?
fn example5<W: Foo<NotClone, X = NotClone>>() { }
// it seems not! (in 1.49 and up; in 1.48 and below this does error)
```

I'm not sure if the intent of the change was merely to shift requirements for associated types to callers of functions and to _still_ require authors of such functions to have to spell out bounds like `A: Clone` explicitly _OR_ if the intent actually was to have `A: Clone` be implied.

I was expecting (or really, hoping for) the latter in which case I'd expect to be able to rely on `A: Clone` within the function bodies above.

In either case I think `example3` is particularly surprising; if this really is intended behavior I think it'd be nice to have the compiler communicate why things like `<Witness as Foo<A>>::X` don't have their trait bounds from `Witness` available when `A` is a ty param on a function (or maybe just for this to be documented?).

---

Edit: IIUC [this comment](https://github.com/rust-lang/rust/issues/78893#issuecomment-1199362452) suggests that this is intended behavior. It does still seem unintuitive/suboptimal that as a consequence, the bound (`A: Clone`) is required for these functions to typecheck but that the bound is _not_ available for the function body to rely on.

This issue is might just a duplicate of #78893 (the traits/`impl Trait` made me initially believe it wasn't but that's a bit of a red herring I think).