Any crate can define an implementation of any trait for its own types (up to things like sealing). But the crate that defines a trait effectively gains a superpower that it can implement its own traits on external types, too. This is generally useful, but can lead to Rust disallowing otherwise-legal blanket impls because an upstream crate is allowed to define other implementations.
For example, imagine the following upstream crate:
pub trait Foo { .. }
pub struct FooImpl { .. }
impl Foo for FooImpl { .. }
A downstream crate might want to do something like this:
trait Bar { .. }
impl Bar for u32 { .. }
impl<T: Foo> Bar for T { .. }
Right now, that makes an error because the upstream crate could add an impl Foo for u32
and break the downstream crate. And the only way to fix the error while keeping all the same types implementing Bar
would be to move the crates around such that Foo
knows about Bar
.
To get around this, we could add an attribute #[orphan_rule(no_superpowers)]
(feel free to bikeshed the name) that turns off the ability for the defining crate to implement this trait on external types, which means that any types in stdlib and any types upsteam of the defining crate can't ever implement the trait (and the attribute is a semver promise, such that removing it is a breaking change).
So in the above example, we could add the attribute to the trait to allow the downstream crate to work:
#[orphan_rule(no_superpowers)]
pub trait Foo { .. }
(this exact example can also be solved by specialization, but it's easy to construct examples where one impl isn't more specialized than the other)
What do y'all think? Would anyone else find this attribute to be useful? I also don't know how the compiler handles this check internally, so I don't know how easy this would be to implement.