about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs33
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs91
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs123
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs94
5 files changed, 225 insertions, 145 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 3f4891efaa7..e744ed2dcc5 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2777,35 +2777,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
             if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
                 // Our own parameters are the resolved lifetimes.
-                if let GenericParamDefKind::Lifetime = param.kind {
-                    if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
-                        self.ast_region_to_region(lifetime, None).into()
-                    } else {
-                        bug!()
-                    }
-                } else {
-                    bug!()
-                }
+                let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
+                let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
+                self.ast_region_to_region(lifetime, None).into()
             } else {
-                match param.kind {
-                    // For RPIT (return position impl trait), only lifetimes
-                    // mentioned in the impl Trait predicate are captured by
-                    // the opaque type, so the lifetime parameters from the
-                    // parent item need to be replaced with `'static`.
-                    //
-                    // For `impl Trait` in the types of statics, constants,
-                    // locals and type aliases. These capture all parent
-                    // lifetimes, so they can use their identity subst.
-                    GenericParamDefKind::Lifetime
-                        if matches!(
-                            origin,
-                            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..)
-                        ) =>
-                    {
-                        tcx.lifetimes.re_static.into()
-                    }
-                    _ => tcx.mk_param_from_def(param),
-                }
+                tcx.mk_param_from_def(param)
             }
         });
         debug!("impl_trait_ty_to_ty: substs={:?}", substs);
@@ -2982,6 +2958,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
     }
 
+    #[instrument(level = "trace", skip(self, generate_err))]
     fn validate_late_bound_regions(
         &self,
         constrained_regions: FxHashSet<ty::BoundRegionKind>,
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b4805de9618..33b9c61993a 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -10,6 +10,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ItemKind, Node, PathSegment};
+use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
@@ -229,7 +230,9 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
     let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
     let span = tcx.def_span(item.owner_id.def_id);
 
-    check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+    if !tcx.features().impl_trait_projections {
+        check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+    }
     if tcx.type_of(item.owner_id.def_id).references_error() {
         return;
     }
@@ -238,6 +241,7 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
     }
     check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
 }
+
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
 /// in "inheriting lifetimes".
 #[instrument(level = "debug", skip(tcx, span))]
@@ -249,39 +253,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
     let item = tcx.hir().expect_item(def_id);
     debug!(?item, ?span);
 
-    struct FoundParentLifetime;
-    struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
-    impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
-        type BreakTy = FoundParentLifetime;
-
-        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-            debug!("FindParentLifetimeVisitor: r={:?}", r);
-            if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
-                if index < self.0.parent_count as u32 {
-                    return ControlFlow::Break(FoundParentLifetime);
-                } else {
-                    return ControlFlow::CONTINUE;
-                }
-            }
-
-            r.super_visit_with(self)
-        }
-
-        fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-            if let ty::ConstKind::Unevaluated(..) = c.kind() {
-                // FIXME(#72219) We currently don't detect lifetimes within substs
-                // which would violate this check. Even though the particular substitution is not used
-                // within the const, this should still be fixed.
-                return ControlFlow::CONTINUE;
-            }
-            c.super_visit_with(self)
-        }
-    }
-
     struct ProhibitOpaqueVisitor<'tcx> {
         tcx: TyCtxt<'tcx>,
         opaque_identity_ty: Ty<'tcx>,
-        generics: &'tcx ty::Generics,
+        parent_count: u32,
+        references_parent_regions: bool,
         selftys: Vec<(Span, Option<String>)>,
     }
 
@@ -289,12 +265,25 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
         type BreakTy = Ty<'tcx>;
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-            debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
+            debug!(?t, "root_visit_ty");
             if t == self.opaque_identity_ty {
                 ControlFlow::CONTINUE
             } else {
-                t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
-                    .map_break(|FoundParentLifetime| t)
+                t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+                    tcx: self.tcx,
+                    op: |region| {
+                        if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *region
+                            && index < self.parent_count
+                        {
+                            self.references_parent_regions= true;
+                        }
+                    },
+                });
+                if self.references_parent_regions {
+                    ControlFlow::Break(t)
+                } else {
+                    ControlFlow::CONTINUE
+                }
             }
         }
     }
@@ -327,15 +316,20 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
 
     if let ItemKind::OpaqueTy(hir::OpaqueTy {
         origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+        in_trait,
         ..
     }) = item.kind
     {
+        let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+        let opaque_identity_ty = if in_trait {
+            tcx.mk_projection(def_id.to_def_id(), substs)
+        } else {
+            tcx.mk_opaque(def_id.to_def_id(), substs)
+        };
         let mut visitor = ProhibitOpaqueVisitor {
-            opaque_identity_ty: tcx.mk_opaque(
-                def_id.to_def_id(),
-                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
-            ),
-            generics: tcx.generics_of(def_id),
+            opaque_identity_ty,
+            parent_count: tcx.generics_of(def_id).parent_count as u32,
+            references_parent_regions: false,
             tcx,
             selftys: vec![],
         };
@@ -343,10 +337,6 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
             .explicit_item_bounds(def_id)
             .iter()
             .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
-        debug!(
-            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
-            prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
-        );
 
         if let Some(ty) = prohibit_opaque.break_value() {
             visitor.visit_item(&item);
@@ -357,15 +347,16 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
                 _ => unreachable!(),
             };
 
-            let mut err = struct_span_err!(
-                tcx.sess,
+            let mut err = feature_err(
+                &tcx.sess.parse_sess,
+                sym::impl_trait_projections,
                 span,
-                E0760,
-                "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
-                 a parent scope",
-                if is_async { "async fn" } else { "impl Trait" },
+                &format!(
+                    "`{}` return type cannot contain a projection or `Self` that references \
+                    lifetimes from a parent scope",
+                    if is_async { "async fn" } else { "impl Trait" },
+                ),
             );
-
             for (span, name) in visitor.selftys {
                 err.span_suggestion(
                     span,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 1d7ceda725a..b81f9d7a6d2 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1539,7 +1539,6 @@ fn check_fn_or_method<'tcx>(
 
     check_return_position_impl_trait_in_trait_bounds(
         tcx,
-        wfcx,
         def_id,
         sig.output(),
         hir_decl.output.span(),
@@ -1575,9 +1574,9 @@ fn check_fn_or_method<'tcx>(
 
 /// Basically `check_associated_type_bounds`, but separated for now and should be
 /// deduplicated when RPITITs get lowered into real associated items.
+#[tracing::instrument(level = "trace", skip(tcx))]
 fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    wfcx: &WfCheckingCtxt<'_, 'tcx>,
     fn_def_id: LocalDefId,
     fn_output: Ty<'tcx>,
     span: Span,
@@ -1591,18 +1590,22 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
                 && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
                 && tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
             {
-                let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
-                let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
-                    let normalized_bound = wfcx.normalize(span, None, bound);
-                    traits::wf::predicate_obligations(
-                        wfcx.infcx,
-                        wfcx.param_env,
-                        wfcx.body_id,
-                        normalized_bound,
-                        bound_span,
-                    )
+                // Create a new context, since we want the opaque's ParamEnv and not the parent's.
+                let span = tcx.def_span(proj.item_def_id);
+                enter_wf_checking_ctxt(tcx, span, proj.item_def_id.expect_local(), |wfcx| {
+                    let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
+                    let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
+                        let normalized_bound = wfcx.normalize(span, None, bound);
+                        traits::wf::predicate_obligations(
+                            wfcx.infcx,
+                            wfcx.param_env,
+                            wfcx.body_id,
+                            normalized_bound,
+                            bound_span,
+                        )
+                    });
+                    wfcx.register_obligations(wf_obligations);
                 });
-                wfcx.register_obligations(wf_obligations);
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index e2da580de0c..c3f1bb457f7 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -84,60 +84,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
         Node::ImplItem(item) => item.generics,
 
-        Node::Item(item) => {
-            match item.kind {
-                ItemKind::Impl(ref impl_) => {
-                    if impl_.defaultness.is_default() {
-                        is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
-                    }
-                    &impl_.generics
+        Node::Item(item) => match item.kind {
+            ItemKind::Impl(ref impl_) => {
+                if impl_.defaultness.is_default() {
+                    is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
                 }
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::TyAlias(_, ref generics)
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => *generics,
-
-                ItemKind::Trait(_, _, ref generics, ..) => {
-                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    *generics
-                }
-                ItemKind::TraitAlias(ref generics, _) => {
-                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    *generics
-                }
-                ItemKind::OpaqueTy(OpaqueTy {
-                    origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
-                    ..
-                }) => {
-                    // return-position impl trait
-                    //
-                    // We don't inherit predicates from the parent here:
-                    // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
-                    // then the return type is `f::<'static, T>::{{opaque}}`.
-                    //
-                    // If we inherited the predicates of `f` then we would
-                    // require that `T: 'static` to show that the return
-                    // type is well-formed.
-                    //
-                    // The only way to have something with this opaque type
-                    // is from the return type of the containing function,
-                    // which will ensure that the function's predicates
-                    // hold.
-                    return ty::GenericPredicates { parent: None, predicates: &[] };
-                }
-                ItemKind::OpaqueTy(OpaqueTy {
-                    ref generics,
-                    origin: hir::OpaqueTyOrigin::TyAlias,
-                    ..
-                }) => {
-                    // type-alias impl trait
-                    generics
-                }
-
-                _ => NO_GENERICS,
+                &impl_.generics
             }
-        }
+            ItemKind::Fn(.., ref generics, _)
+            | ItemKind::TyAlias(_, ref generics)
+            | ItemKind::Enum(_, ref generics)
+            | ItemKind::Struct(_, ref generics)
+            | ItemKind::Union(_, ref generics) => *generics,
+
+            ItemKind::Trait(_, _, ref generics, ..) => {
+                is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+                *generics
+            }
+            ItemKind::TraitAlias(ref generics, _) => {
+                is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+                *generics
+            }
+            ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) => generics,
+            _ => NO_GENERICS,
+        },
 
         Node::ForeignItem(item) => match item.kind {
             ForeignItemKind::Static(..) => NO_GENERICS,
@@ -181,6 +151,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
     trace!(?predicates);
     trace!(?ast_generics);
+    trace!(?generics);
 
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`).
@@ -299,6 +270,54 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         );
     }
 
+    // Opaque types duplicate some of their generic parameters.
+    // We create bi-directional Outlives predicates between the original
+    // and the duplicated parameter, to ensure that they do not get out of sync.
+    if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
+        let opaque_ty_id = tcx.hir().get_parent_node(hir_id);
+        let opaque_ty_node = tcx.hir().get(opaque_ty_id);
+        let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
+            bug!("unexpected {opaque_ty_node:?}")
+        };
+        debug!(?lifetimes);
+        for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
+            let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
+            let orig_region = <dyn AstConv<'_>>::ast_region_to_region(&icx, &arg, None);
+            if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
+                // Only early-bound regions can point to the original generic parameter.
+                continue;
+            }
+
+            let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
+            let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id();
+
+            let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() };
+
+            let dup_region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+                def_id: dup_def,
+                index: dup_index,
+                name: duplicate.name.ident().name,
+            }));
+            predicates.push((
+                ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+                    orig_region,
+                    dup_region,
+                )))
+                .to_predicate(icx.tcx),
+                duplicate.span,
+            ));
+            predicates.push((
+                ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+                    dup_region,
+                    orig_region,
+                )))
+                .to_predicate(icx.tcx),
+                duplicate.span,
+            ));
+        }
+        debug!(?predicates);
+    }
+
     ty::GenericPredicates {
         parent: generics.parent,
         predicates: tcx.arena.alloc_from_iter(predicates),
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 82103c5a03b..b6137f89cad 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -5,9 +5,10 @@
 
 use rustc_arena::DroplessArena;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt};
+use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable};
+use std::ops::ControlFlow;
 
 /// Defines the `TermsContext` basically houses an arena where we can
 /// allocate terms.
@@ -50,6 +51,9 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
         | DefKind::Union
         | DefKind::Variant
         | DefKind::Ctor(..) => {}
+        DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => {
+            return variance_of_opaque(tcx, item_def_id.expect_local());
+        }
         _ => {
             // Variance not relevant.
             span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item")
@@ -61,3 +65,89 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
     let crate_map = tcx.crate_variances(());
     crate_map.variances.get(&item_def_id).copied().unwrap_or(&[])
 }
+
+#[instrument(level = "trace", skip(tcx), ret)]
+fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
+    let generics = tcx.generics_of(item_def_id);
+
+    // Opaque types may only use regions that are bound. So for
+    // ```rust
+    // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
+    // ```
+    // we may not use `'c` in the hidden type.
+    struct OpaqueTypeLifetimeCollector {
+        variances: Vec<ty::Variance>,
+    }
+
+    impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector {
+        #[instrument(level = "trace", skip(self), ret)]
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+            if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
+                self.variances[ebr.index as usize] = ty::Invariant;
+            }
+            r.super_visit_with(self)
+        }
+    }
+
+    // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
+    // lifetime generics.
+    let mut variances: Vec<_> = std::iter::repeat(ty::Invariant).take(generics.count()).collect();
+
+    // Mark all lifetimes from parent generics as unused (Bivariant).
+    // This will be overridden later if required.
+    {
+        let mut generics = generics;
+        while let Some(def_id) = generics.parent {
+            generics = tcx.generics_of(def_id);
+            for param in &generics.params {
+                match param.kind {
+                    ty::GenericParamDefKind::Lifetime => {
+                        variances[param.index as usize] = ty::Bivariant;
+                    }
+                    ty::GenericParamDefKind::Type { .. }
+                    | ty::GenericParamDefKind::Const { .. } => {}
+                }
+            }
+        }
+    }
+
+    let mut collector = OpaqueTypeLifetimeCollector { variances };
+    let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
+    for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
+        let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
+        debug!(?pred);
+
+        // We only ignore opaque type substs if the opaque type is the outermost type.
+        // The opaque type may be nested within itself via recursion in e.g.
+        // type Foo<'a> = impl PartialEq<Foo<'a>>;
+        // which thus mentions `'a` and should thus accept hidden types that borrow 'a
+        // instead of requiring an additional `+ 'a`.
+        match pred.kind().skip_binder() {
+            ty::PredicateKind::Trait(ty::TraitPredicate {
+                trait_ref: ty::TraitRef { def_id: _, substs },
+                constness: _,
+                polarity: _,
+            }) => {
+                for subst in &substs[1..] {
+                    subst.visit_with(&mut collector);
+                }
+            }
+            ty::PredicateKind::Projection(ty::ProjectionPredicate {
+                projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
+                term,
+            }) => {
+                for subst in &substs[1..] {
+                    subst.visit_with(&mut collector);
+                }
+                term.visit_with(&mut collector);
+            }
+            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, region)) => {
+                region.visit_with(&mut collector);
+            }
+            _ => {
+                pred.visit_with(&mut collector);
+            }
+        }
+    }
+    tcx.arena.alloc_from_iter(collector.variances.into_iter())
+}