Description
Background
The #[rustc_reservation_impl]
attribute was added as part of the effort to stabilize !
. Its goal is to make it possible to add a impl<T> From<!> for T
impl in the future by disallowing downstream crates to do negative reasoning that might conflict with that.
Warning: the effect of this attribute is quite subtle, and it should be used with caution! In particular, adding a "reservation impl" alone does not guarantee that one can add the impl in the future, as described below.
History
- Initial implementation in reserve
impl<T> From<!> for T
#62661
Current blockers before this attribute can be used to affect end-users
- How should "reserved" impls show up in rustdoc? (How to handle reservation impls in rustdoc / error messages #64633)
- What should its error message be? (How to handle reservation impls in rustdoc / error messages #64633)
Usage
You can use the #[rustc_reservation_impl]
attribute as follows:
#[rustc_reservation_impl]
impl<T> From<!> for T { .. }
For the most part, rustc will act as though this impl does not exist. For example, users can add overlapping impls if they prefer:
struct LocalType1<T>(T);
impl<T> From<!> for LocalType1<T> { }
struct LocalType2<T>(T);
impl<T> From<T> for LocalType2<T> { }
Note that this implies that the #[rustc_reservation_impl]
attribute alone does not guarantee that you can add the reservation impl in a future compatible way. Adding the reserved impl in the future may still cause coherence overlap (e.g., the impl for LocalType<T>
for the impl for all T
would overlap here). This will typically result in errors.
In order to add the impl, you must be able to ensure that coherence will allow the overlapping impls. This can be done in two ways, both of which are presently unstable:
- Specialization: but be careful! e.g., the current specialization rules do not suffice in the
LocalType2
example above, since neither impl is a subset of one another. - Marker traits: we have a notion of marker traits that are allowed to overlap. Marker traits currently must have no items, which excludes e.g.
From
, but we could grow this definition.
What does the attribute do?
The attribute prevents negative reasoning. In particular, it forbids impls like this:
trait LocalTrait;
struct LocalType3;
impl<T> LocalTrait for T where T: From<!> { }
impl<T> LocalTrait for LocalType3 { }
Without the reservation impl, this would be legal, because the crate may assume that LocalType: From<!>
does not hold (since LocalType
is local to the crate). With the reservation impl, however, code like this will get an error.