trait Bar {}
trait Foo {
fn func(self) -> Self
where Self: Bar;
..other items..
}
Right now, there is no way to implement Foo for a type that doesn't implement Bar without refining fn func to not have the bound, defeating its entire purpose. There are sometimes some work arounds, like you could do this:
struct SomeType<T> {...}
/// # Safety
/// just don't
unsafe trait NoImpl {}
impl<T: NoImpl > Bar for SomeType<T> {}
impl Foo for SomeType {
fn func(self) -> Self
where Self: Bar {
unimplemented!();
}
..other items..
}
(or implementing it for an empty enum/!)
but this requires a generic and Bar not to be something like Send or Sync which can often defeat the whole purpose, especially when using traits a impl blocks on foreign types. This also makes it appear that there may be some way to access fn func on SomeType even when its entirely inaccessible.
Removing the requirement to include the function would fix this problem. Done universally, this would cause a issue where new trait impl are now breaking changes, so instead it needs to have the following restraint: The trait in the where bound that is unsatisfiable must be defined in the same crate and doesn't have any auto-impl that could be satisfied for the type by the type gaining new foreign trait impls.
Simply having the type being local isn't enough because if the trait got a new auto-impl or loosened the restrictions on its auto-impl, it would be a breaking change.
You might be interested to learn that actually one can add the bound: For some reason, rustc doesnāt care so much anymore about āimpossibleā bounds if you add some higher-ranked lifetime to it. So e.g. while
impl Foo for SomeType {
fn func(self) -> Self
where
Self: Bar,
{
unreachable!()
}
}
is rejected, doing this instead is actually accepted:
impl Foo for SomeType {
fn func(self) -> Self
where
for<'a> Self: Bar,
{
unreachable!()
}
}
(equivalently: Self: for<'a> Bar. Also I somethimes would write this using for<'__> Self: Bar marking the name of the lifetime more clearly āirrelevantā, arguably.)
Also for Self: Sized as a bound, you are allowed to skip the method. This seems like deliberate design, so itās probably possible to find prior discussion somewhere, giving a clue on why that particular case is supported but more cases seem not to.
Refinement tracking issue, so you could write a method without the bounds when they aren't met, and actually make use of it
Trivial bounds tracking issue, so you could write a method with the trivially unmet bounds present without a compiler error
That has an issue, but is also a workaround for the lack of stable trivial bounds. (As is writing a method without bounds, but you can't currently call it.)