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 args for
impl2
so that the implemented trait and self-type match those forimpl1
. - Check for any direct use of
'static
in the args ofimpl2
. - Check that all of the generic parameters of
impl1
occur at most once in the unconstrained args forimpl2
. A parameter is constrained if its value is completely determined by an associated type projection predicate. - Check that all predicates on
impl1
either exist onimpl2
(after matching args), 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
- Check that
impl1
is a sound specialization - Check that the specializing impl
impl1
is at least as const as the base implimpl2
- Check that parameters of the derived impl don’t occur more than once in the equated args of the base impl.
- Check whether predicates on the specializing impl (
impl1
) are allowed. - Check that
'static
lifetimes are not introduced by the specializing impl. - Given a specializing impl
impl1
, and the base implimpl2
, returns two substitutions(S1, S2)
that equate their trait references. The returned types are expressed in terms of the generics ofimpl1
. - Checks if some predicate on the specializing impl (
predicate1
) is the same as some predicate on the base impl (predicate2
). - Returns a list of all of the unconstrained subst of the given impl.