This touches on a lot of deep areas of bounds and coherence that are hard to summarize, so largely this will be a collection of links to pursue if you are interested. The TL;DR is -- that's been considered many times, and it is desired, but we're not there yet -- probably not close.
Re: negative_impls
,
- It's the leading edge for disjoint blanket implementations, but
- Currently they are quite limited and do not influence coherence, however
- There is an MCP and now an initiative to integrate them into coherence
- Which you would need for your example
- However-however, if things haven't changed since the MCP, even this doesn't allow
!Trait
in awhere
clause yet. So that is still quite a ways out.
A more general term for basing coherence on what isn't implemented is "negative reasoning". The Rust teams are usually careful about allowing this as it is quite brittle.
- It's limited by the orphan rules today
- There is occasional grumbling to deprecate this too, once a general negative bound is available
- Lots of discussion in this closed negative bounds RFC
- More in this blog post
A main motivator for having negative trait bounds is mutually exclusive traits. It's been proposed before, and indeed, you can read about the roots of negative_impls
in the discussions.
- Mutually exclusive traits RFC (closed)
- Complementary traits RFC (closed)
- This somewhat blanket issue
In some of these issues, the ability to say where T != U
specifically has come up, to which Niko notes:
we haven't implemented support for equality bounds yet, and for good reasons, so I wouldn't want to officially support inequality bounds. They also have interactions with inference (which is currently driven by unification). (That said, just like region bounds, I suspect we could eventually support these as a kind of "after-the-fact" check, rather than having them inform inference in any way.)
But there is one place where equality bounds are supported today -- in associated type bounds.
fn f<I: Iterator<Item=i32>>(iter: I) { /* ... */ }
So how about incorporating some negative reasoning around those bounds? Two implementations bound on explicit, distinct associated types certainly can't overlap. That has been considered as well:
- Disjointness based on associated types
- ...can be used to implement mutually exclusive traits
- Subsequently postponed for the same reasons as the above RFCs
- You can sometimes work around this by using a new trait to hoist the associated type into a type parameter