trait Target {}
trait Base { type Target<T>; }
trait Derived1: Base<Target<u32> = u32, Target<u64> = u64> {}
// error[E0719]: the value of the associated type
// `Target` in trait `Base` is already specified
trait Derived2: Base<Target<u32>: Target, Target<u64>: Target> {}
// error[E0719] as well
However, without such a feature, equivalents like Derived1would be impossible(see the reply below), while users requiring equivalents like Derived2 would write a bunch of where clauses that are needed at every reference site alongside the trait itself:
trait Target {}
trait Base { type Target<T>; }
trait Derived2: Base
where
Self::Target<u32>: Target,
Self::Target<u64>: Target,
{}
fn test<T: Derived2>(_: T)
where
T::Target<u32>: Target, // Removing those where clauses
T::Target<u64>: Target, // would result in a compile error.
{}
IMHO, besides the obvious verbosity, it could be viewed as a kind of unintended abstraction leakage (for example, library implementors would want to hide a private Target & Base trait with a public Derived2 trait).
Supporting multiple GAT constraints with different generics on trait bounds can eliminate all the issues mentioned above and enable users with a more powerful type system.
As a sort of workaround that may or may not be applicable in your use case, you can add a dummy type variable to the subtraits to parameterize over Base::Target<_>:
Those universal bounds should (I think) be strictly equivalent to the OP bounds special cased for u32 and u64, as long as we don't have specialization of GATs, anyway. The dummy type variables wouldn't be needed if we had HRTBs for types ie. for<T> Target<T> = T.