Description
References, raw pointers, arrays etc. have distinct syntactic forms and as a consequence 1) traits can be implemented for them and 2) coherence checker knows things like "references are not arrays"
impl<'a, T> Tr for &'a T {}
impl<T> Tr for *const T {}
impl<T> Tr for [T] {}
On the other side, trait objects, non-references, non-pointers, unique function types, tuples of any size and other sets of types don't have distinct syntactic forms and that's the only (?) reason why they cannot be used with traits.
Assume for a second that non-references have their own syntax - (╯°□°)╯︵ &
- then we could likely write
impl<'a, T> Tr for &'a T { /*one implementation*/ }
impl Tr for (╯°□°)╯︵ & { /*another implementation*/ }
and coherence checker would know that "references are not non-references". And it wouldn't require any new complex machinery - negative bounds, specialization - beyond the existing one.
Conclusion: We should invent a way to write impls for built-in (fixed, not defined by traits), but syntactically inexpressible sets of types.