Expand description
Minimal Specialization
This module contains the checks for sound specialization used when the
min_specialization feature is enabled. This requires that the impl is
always applicable.
If impl1 specializes impl2 then impl1 is always applicable if we know
that all the bounds of impl2 are satisfied, and all of the bounds of
impl1 are satisfied for some choice of lifetimes then we know that
impl1 applies for any choice of lifetimes.
Basic approach
To enforce this requirement on specializations we take the following approach:
- Match up the substs for
impl2so that the implemented trait and self-type match those forimpl1. - Check for any direct use of
'staticin the substs ofimpl2. - Check that all of the generic parameters of
impl1occur at most once in the unconstrained substs forimpl2. A parameter is constrained if its value is completely determined by an associated type projection predicate. - Check that all predicates on
impl1either exist onimpl2(after matching substs), or are well-formed predicates for the trait’s type arguments.
Example
Suppose we have the following always applicable impl:
impl<T> SpecExtend<T> for std::vec::IntoIter<T> { /* specialized impl */ }
impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ }We get that the subst for impl2 are [T, std::vec::IntoIter<T>]. T is
constrained to be <I as Iterator>::Item, so we check only
std::vec::IntoIter<T> for repeated parameters, which it doesn’t have. The
predicates of impl1 are only T: Sized, which is also a predicate of
impl2. So this specialization is sound.
Extensions
Unfortunately not all specializations in the standard library are allowed by this. So there are two extensions to these rules that allow specializing on some traits: that is, using them as bounds on the specializing impl, even when they don’t occur in the base impl.
rustc_specialization_trait
If a trait is always applicable, then it’s sound to specialize on it. We
check trait is always applicable in the same way as impls, except that step
4 is now “all predicates on impl1 are always applicable”. We require that
specialization or min_specialization is enabled to implement these
traits.
rustc_unsafe_specialization_marker
There are also some specialization on traits with no methods, including the
stable FusedIterator trait. We allow marking marker traits with an
unstable attribute that means we ignore them in point 3 of the checks
above. This is unsound, in the sense that the specialized impl may be used
when it doesn’t apply, but we allow it in the short term since it can’t
cause use after frees with purely safe code in the same way as specializing
on traits with methods can.
Functions
impl1 is a sound specializationimpl1 is at least as const as the base
impl impl2impl1) are allowed.'static lifetimes are not introduced by the specializing impl.impl1, and the base impl impl2, returns two
substitutions (S1, S2) that equate their trait references. The returned
types are expressed in terms of the generics of impl1.predicate1) is the same
as some predicate on the base impl (predicate2).