about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs3
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs17
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs4
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs144
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs109
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs10
-rw-r--r--compiler/rustc_infer/src/traits/util.rs12
-rw-r--r--compiler/rustc_middle/src/traits/query.rs4
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs3
-rw-r--r--compiler/rustc_typeck/src/mem_categorization.rs12
-rw-r--r--compiler/rustc_typeck/src/outlives/utils.rs17
12 files changed, 215 insertions, 125 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index f1b1c33a105..e0140e281ee 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -362,6 +362,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                     self.region_bound_pairs
                         .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
                 }
+
+                OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+                    self.region_bound_pairs
+                        .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+                }
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 0208c364e43..99469d1e1e7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2481,6 +2481,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let labeled_user_string = match bound_kind {
             GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
             GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
+            GenericKind::Opaque(def_id, substs) => {
+                format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
+            }
         };
 
         if let Some(SubregionOrigin::CompareImplItemObligation {
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index b2d7f4a663a..14ee9f05190 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -3,8 +3,9 @@
 // RFC for reference.
 
 use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
 use smallvec::{smallvec, SmallVec};
 
 #[derive(Debug)]
@@ -45,6 +46,8 @@ pub enum Component<'tcx> {
     // them. This gives us room to improve the regionck reasoning in
     // the future without breaking backwards compat.
     EscapingProjection(Vec<Component<'tcx>>),
+
+    Opaque(DefId, SubstsRef<'tcx>),
 }
 
 /// Push onto `out` all the things that must outlive `'a` for the condition
@@ -120,6 +123,17 @@ fn compute_components<'tcx>(
                 out.push(Component::Param(p));
             }
 
+            // Ignore lifetimes found in opaque types. Opaque types can
+            // have lifetimes in their substs which their hidden type doesn't
+            // actually use. If we inferred that an opaque type is outlived by
+            // its parameter lifetimes, then we could prove that any lifetime
+            // outlives any other lifetime, which is unsound.
+            // See https://github.com/rust-lang/rust/issues/84305 for
+            // more details.
+            ty::Opaque(def_id, substs) => {
+                out.push(Component::Opaque(def_id, substs));
+            },
+
             // For projections, we prefer to generate an obligation like
             // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
             // regionck more ways to prove that it holds. However,
@@ -168,7 +182,6 @@ fn compute_components<'tcx>(
             ty::Float(..) |       // OutlivesScalar
             ty::Never |           // ...
             ty::Adt(..) |         // OutlivesNominalType
-            ty::Opaque(..) |      // OutlivesNominalType (ish)
             ty::Foreign(..) |     // OutlivesNominalType
             ty::Str |             // OutlivesScalar (ish)
             ty::Slice(..) |       // ...
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 9922b156ebf..113d4f09066 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -142,6 +142,10 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
                     self.region_bound_pairs
                         .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
                 }
+                OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+                    self.region_bound_pairs
+                        .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+                }
                 OutlivesBound::RegionSubRegion(r_a, r_b) => {
                     if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
                         infcx
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 5bd1774f6b1..229b69b92e6 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,10 +68,11 @@ use crate::infer::{
 };
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
 use smallvec::smallvec;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
@@ -283,6 +284,9 @@ where
                 Component::Param(param_ty) => {
                     self.param_ty_must_outlive(origin, region, *param_ty);
                 }
+                Component::Opaque(def_id, substs) => {
+                    self.opaque_must_outlive(*def_id, substs, origin, region)
+                }
                 Component::Projection(projection_ty) => {
                     self.projection_must_outlive(origin, region, *projection_ty);
                 }
@@ -314,17 +318,69 @@ where
         );
 
         let generic = GenericKind::Param(param_ty);
-        let verify_bound = self.verify_bound.generic_bound(generic);
+        let verify_bound = self.verify_bound.param_bound(param_ty);
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
 
     #[instrument(level = "debug", skip(self))]
+    fn opaque_must_outlive(
+        &mut self,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        origin: infer::SubregionOrigin<'tcx>,
+        region: ty::Region<'tcx>,
+    ) {
+        self.generic_must_outlive(
+            origin,
+            region,
+            GenericKind::Opaque(def_id, substs),
+            def_id,
+            substs,
+            true,
+            |ty| match *ty.kind() {
+                ty::Opaque(def_id, substs) => (def_id, substs),
+                _ => bug!("expected only projection types from env, not {:?}", ty),
+            },
+        );
+    }
+
+    #[instrument(level = "debug", skip(self))]
     fn projection_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         region: ty::Region<'tcx>,
         projection_ty: ty::ProjectionTy<'tcx>,
     ) {
+        self.generic_must_outlive(
+            origin,
+            region,
+            GenericKind::Projection(projection_ty),
+            projection_ty.item_def_id,
+            projection_ty.substs,
+            false,
+            |ty| match ty.kind() {
+                ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
+                _ => bug!("expected only projection types from env, not {:?}", ty),
+            },
+        );
+    }
+
+    #[instrument(level = "debug", skip(self, filter))]
+    fn generic_must_outlive(
+        &mut self,
+        origin: infer::SubregionOrigin<'tcx>,
+        region: ty::Region<'tcx>,
+        generic: GenericKind<'tcx>,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        is_opaque: bool,
+        filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+    ) {
+        // An optimization for a common case with opaque types.
+        if substs.is_empty() {
+            return;
+        }
+
         // This case is thorny for inference. The fundamental problem is
         // that there are many cases where we have choice, and inference
         // doesn't like choice (the current region inference in
@@ -343,16 +399,15 @@ where
         // These are guaranteed to apply, no matter the inference
         // results.
         let trait_bounds: Vec<_> =
-            self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
+            self.verify_bound.declared_region_bounds(def_id, substs).collect();
 
         debug!(?trait_bounds);
 
         // Compute the bounds we can derive from the environment. This
         // is an "approximate" match -- in some cases, these bounds
         // may not apply.
-        let mut approx_env_bounds =
-            self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
-        debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
+        let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+        debug!(?approx_env_bounds);
 
         // Remove outlives bounds that we get from the environment but
         // which are also deducible from the trait. This arises (cc
@@ -366,14 +421,8 @@ where
             // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
             // will be invoked with `['b => ^1]` and so we will get `^1` returned.
             let bound = bound_outlives.skip_binder();
-            match *bound.0.kind() {
-                ty::Projection(projection_ty) => self
-                    .verify_bound
-                    .projection_declared_bounds_from_trait(projection_ty)
-                    .all(|r| r != bound.1),
-
-                _ => panic!("expected only projection types from env, not {:?}", bound.0),
-            }
+            let (def_id, substs) = filter(bound.0);
+            self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
         });
 
         // If declared bounds list is empty, the only applicable rule is
@@ -390,29 +439,11 @@ where
         // the problem is to add `T: 'r`, which isn't true. So, if there are no
         // inference variables, we use a verify constraint instead of adding
         // edges, which winds up enforcing the same condition.
-        let needs_infer = projection_ty.needs_infer();
-        if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
-            debug!("projection_must_outlive: no declared bounds");
-
-            let constraint = origin.to_constraint_category();
-            for k in projection_ty.substs {
-                match k.unpack() {
-                    GenericArgKind::Lifetime(lt) => {
-                        self.delegate.push_sub_region_constraint(
-                            origin.clone(),
-                            region,
-                            lt,
-                            constraint,
-                        );
-                    }
-                    GenericArgKind::Type(ty) => {
-                        self.type_must_outlive(origin.clone(), ty, region, constraint);
-                    }
-                    GenericArgKind::Const(_) => {
-                        // Const parameters don't impose constraints.
-                    }
-                }
-            }
+        let needs_infer = substs.needs_infer();
+        if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+            debug!("no declared bounds");
+
+            self.substs_must_outlive(substs, origin, region);
 
             return;
         }
@@ -442,8 +473,8 @@ where
                 .all(|b| b == Some(trait_bounds[0]))
         {
             let unique_bound = trait_bounds[0];
-            debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
-            debug!("projection_must_outlive: unique declared bound appears in trait ref");
+            debug!(?unique_bound);
+            debug!("unique declared bound appears in trait ref");
             let category = origin.to_constraint_category();
             self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
             return;
@@ -454,11 +485,42 @@ where
         // projection outlive; in some cases, this may add insufficient
         // edges into the inference graph, leading to inference failures
         // even though a satisfactory solution exists.
-        let generic = GenericKind::Projection(projection_ty);
-        let verify_bound = self.verify_bound.generic_bound(generic);
+        let verify_bound = self.verify_bound.projection_opaque_bounds(
+            generic,
+            def_id,
+            substs,
+            &mut Default::default(),
+        );
         debug!("projection_must_outlive: pushing {:?}", verify_bound);
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
+
+    fn substs_must_outlive(
+        &mut self,
+        substs: SubstsRef<'tcx>,
+        origin: infer::SubregionOrigin<'tcx>,
+        region: ty::Region<'tcx>,
+    ) {
+        let constraint = origin.to_constraint_category();
+        for k in substs {
+            match k.unpack() {
+                GenericArgKind::Lifetime(lt) => {
+                    self.delegate.push_sub_region_constraint(
+                        origin.clone(),
+                        region,
+                        lt,
+                        constraint,
+                    );
+                }
+                GenericArgKind::Type(ty) => {
+                    self.type_must_outlive(origin.clone(), ty, region, constraint);
+                }
+                GenericArgKind::Const(_) => {
+                    // Const parameters don't impose constraints.
+                }
+            }
+        }
+    }
 }
 
 impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index e344e192a76..f470b2eb8c1 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -2,11 +2,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::region_constraints::VerifyIfEq;
 use crate::infer::{GenericKind, VerifyBound};
-use rustc_data_structures::captures::Captures;
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
 
 use smallvec::smallvec;
 
@@ -38,20 +37,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
     }
 
-    /// Returns a "verify bound" that encodes what we know about
-    /// `generic` and the regions it outlives.
-    pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
-        let mut visited = SsoHashSet::new();
-        match generic {
-            GenericKind::Param(param_ty) => self.param_bound(param_ty),
-            GenericKind::Projection(projection_ty) => {
-                self.projection_bound(projection_ty, &mut visited)
-            }
-        }
-    }
-
     #[instrument(level = "debug", skip(self))]
-    fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
+    pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
         // Start with anything like `T: 'a` we can scrape from the
         // environment. If the environment contains something like
         // `for<'a> T: 'a`, then we know that `T` outlives everything.
@@ -105,41 +92,31 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     /// the clause from the environment only applies if `'0 = 'a`,
     /// which we don't know yet. But we would still include `'b` in
     /// this list.
-    pub fn projection_approx_declared_bounds_from_env(
+    pub fn approx_declared_bounds_from_env(
         &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
+        generic: GenericKind<'tcx>,
     ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
-        let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
+        let projection_ty = generic.to_ty(self.tcx);
         let erased_projection_ty = self.tcx.erase_regions(projection_ty);
         self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
     }
 
-    /// Searches the where-clauses in scope for regions that
-    /// `projection_ty` is known to outlive. Currently requires an
-    /// exact match.
-    pub fn projection_declared_bounds_from_trait(
+    #[instrument(level = "debug", skip(self, visited))]
+    pub fn projection_opaque_bounds(
         &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
-        self.declared_projection_bounds_from_trait(projection_ty)
-    }
-
-    pub fn projection_bound(
-        &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
+        generic: GenericKind<'tcx>,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
         visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> VerifyBound<'tcx> {
-        debug!("projection_bound(projection_ty={:?})", projection_ty);
-
-        let projection_ty_as_ty =
-            self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
+        let generic_ty = generic.to_ty(self.tcx);
 
         // Search the env for where clauses like `P: 'a`.
-        let env_bounds = self
-            .projection_approx_declared_bounds_from_env(projection_ty)
+        let projection_opaque_bounds = self
+            .approx_declared_bounds_from_env(generic)
             .into_iter()
             .map(|binder| {
-                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
+                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
                     // Micro-optimize if this is an exact match (this
                     // occurs often when there are no region variables
                     // involved).
@@ -149,21 +126,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
                     VerifyBound::IfEq(verify_if_eq_b)
                 }
             });
-
         // Extend with bounds that we can find from the trait.
-        let trait_bounds = self
-            .projection_declared_bounds_from_trait(projection_ty)
-            .map(|r| VerifyBound::OutlivedBy(r));
+        let trait_bounds =
+            self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
 
         // see the extensive comment in projection_must_outlive
         let recursive_bound = {
             let mut components = smallvec![];
-            let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
-            compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
+            compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
             self.bound_from_components(&components, visited)
         };
 
-        VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
+        VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
+            .or(recursive_bound)
     }
 
     fn bound_from_components(
@@ -195,7 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         match *component {
             Component::Region(lt) => VerifyBound::OutlivedBy(lt),
             Component::Param(param_ty) => self.param_bound(param_ty),
-            Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
+            Component::Opaque(did, substs) => self.projection_opaque_bounds(
+                GenericKind::Opaque(did, substs),
+                did,
+                substs,
+                visited,
+            ),
+            Component::Projection(projection_ty) => self.projection_opaque_bounds(
+                GenericKind::Projection(projection_ty),
+                projection_ty.item_def_id,
+                projection_ty.substs,
+                visited,
+            ),
             Component::EscapingProjection(ref components) => {
                 self.bound_from_components(components, visited)
             }
@@ -293,30 +279,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     /// }
     /// ```
     ///
-    /// then this function would return `'x`. This is subject to the
-    /// limitations around higher-ranked bounds described in
-    /// `region_bounds_declared_on_associated_item`.
-    fn declared_projection_bounds_from_trait(
-        &self,
-        projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
-        debug!("projection_bounds(projection_ty={:?})", projection_ty);
-        let tcx = self.tcx;
-        self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
-            .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
-    }
-
-    /// Given the `DefId` of an associated item, returns any region
-    /// bounds attached to that associated item from the trait definition.
-    ///
-    /// For example:
-    ///
-    /// ```rust
-    /// trait Foo<'a> {
-    ///     type Bar: 'a;
-    /// }
-    /// ```
-    ///
     /// If we were given the `DefId` of `Foo::Bar`, we would return
     /// `'a`. You could then apply the substitutions from the
     /// projection to convert this into your namespace. This also
@@ -336,17 +298,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     ///
     /// This is for simplicity, and because we are not really smart
     /// enough to cope with such bounds anywhere.
-    fn region_bounds_declared_on_associated_item(
+    pub fn declared_region_bounds(
         &self,
-        assoc_item_def_id: DefId,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.item_bounds(assoc_item_def_id);
+        let bounds = tcx.item_bounds(def_id);
+        trace!("{:#?}", bounds);
         bounds
             .into_iter()
             .filter_map(|p| p.to_opt_type_outlives())
             .filter_map(|p| p.no_bound_vars())
             .map(|b| b.1)
+            .map(move |r| EarlyBinder(r).subst(tcx, substs))
     }
 
     /// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index e43d28ee56e..67b3da68720 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -12,8 +12,10 @@ use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
+use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ReStatic;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReLateBound, ReVar};
@@ -168,6 +170,7 @@ pub struct Verify<'tcx> {
 pub enum GenericKind<'tcx> {
     Param(ty::ParamTy),
     Projection(ty::ProjectionTy<'tcx>),
+    Opaque(DefId, SubstsRef<'tcx>),
 }
 
 /// Describes the things that some `GenericKind` value `G` is known to
@@ -747,6 +750,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
         match *self {
             GenericKind::Param(ref p) => write!(f, "{:?}", p),
             GenericKind::Projection(ref p) => write!(f, "{:?}", p),
+            GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+                write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+            }),
         }
     }
 }
@@ -756,6 +762,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
         match *self {
             GenericKind::Param(ref p) => write!(f, "{}", p),
             GenericKind::Projection(ref p) => write!(f, "{}", p),
+            GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+                write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+            }),
         }
     }
 }
@@ -765,6 +774,7 @@ impl<'tcx> GenericKind<'tcx> {
         match *self {
             GenericKind::Param(ref p) => p.to_ty(tcx),
             GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
+            GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index f5a1edf6d81..e12c069dcc1 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -246,6 +246,13 @@ impl<'tcx> Elaborator<'tcx> {
 
                             Component::UnresolvedInferenceVariable(_) => None,
 
+                            Component::Opaque(def_id, substs) => {
+                                let ty = tcx.mk_opaque(def_id, substs);
+                                Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+                                    ty, r_min,
+                                )))
+                            }
+
                             Component::Projection(projection) => {
                                 // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
                                 // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
@@ -262,8 +269,9 @@ impl<'tcx> Elaborator<'tcx> {
                                 None
                             }
                         })
-                        .map(ty::Binder::dummy)
-                        .map(|predicate_kind| predicate_kind.to_predicate(tcx))
+                        .map(|predicate_kind| {
+                            bound_predicate.rebind(predicate_kind).to_predicate(tcx)
+                        })
                         .filter(|&predicate| visited.insert(predicate))
                         .map(|predicate| {
                             predicate_obligation(
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 0e6cacb9fd0..fb152b63f63 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -8,8 +8,9 @@
 use crate::error::DropCheckOverflow;
 use crate::infer::canonical::{Canonical, QueryResponse};
 use crate::ty::error::TypeError;
-use crate::ty::subst::GenericArg;
+use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt};
+use rustc_hir::def_id::DefId;
 use rustc_span::source_map::Span;
 use std::iter::FromIterator;
 
@@ -219,4 +220,5 @@ pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
     RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
+    RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>),
 }
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 691b79f1053..32aca4a8a3f 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -156,6 +156,9 @@ fn implied_bounds_from_components<'tcx>(
                 Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
                 Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
                 Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
+                Component::Opaque(def_id, substs) => {
+                    Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs))
+                }
                 Component::EscapingProjection(_) =>
                 // If the projection has escaping regions, don't
                 // try to infer any implied bounds even for its
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index ced919f66db..39610e3ae38 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -265,6 +265,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
     }
 
+    #[instrument(level = "debug", skip(self, previous))]
     fn cat_expr_adjusted_with<F>(
         &self,
         expr: &hir::Expr<'_>,
@@ -274,7 +275,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     where
         F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
     {
-        debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
         let target = self.resolve_vars_if_possible(adjustment.target);
         match adjustment.kind {
             adjustment::Adjust::Deref(overloaded) => {
@@ -299,6 +299,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn cat_expr_unadjusted(
         &self,
         expr: &hir::Expr<'_>,
@@ -387,6 +388,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self, span))]
     pub(crate) fn cat_res(
         &self,
         hir_id: hir::HirId,
@@ -394,8 +396,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         expr_ty: Ty<'tcx>,
         res: Res,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
-
         match res {
             Res::Def(
                 DefKind::Ctor(..)
@@ -475,13 +475,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         ret
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn cat_overloaded_place(
         &self,
         expr: &hir::Expr<'_>,
         base: &hir::Expr<'_>,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
-
         // Reconstruct the output assuming it's a reference with the
         // same region and mutability as the receiver. This holds for
         // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
@@ -497,13 +496,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         self.cat_deref(expr, base)
     }
 
+    #[instrument(level = "debug", skip(self, node))]
     fn cat_deref(
         &self,
         node: &impl HirNode,
         base_place: PlaceWithHirId<'tcx>,
     ) -> McResult<PlaceWithHirId<'tcx>> {
-        debug!("cat_deref: base_place={:?}", base_place);
-
         let base_curr_ty = base_place.place.ty();
         let deref_ty = match base_curr_ty.builtin_deref(true) {
             Some(mt) => mt.ty,
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs
index 3e8d023fb55..0409c7081dc 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_typeck/src/outlives/utils.rs
@@ -96,6 +96,23 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
                             .or_insert(span);
                     }
 
+                    Component::Opaque(def_id, substs) => {
+                        // This would arise from something like:
+                        //
+                        // ```rust
+                        // type Opaque<T> = impl Sized;
+                        // fn defining<T>() -> Opaque<T> {}
+                        // struct Ss<'a, T>(&'a Opaque<T>);
+                        // ```
+                        //
+                        // Here we want to have an implied bound `Opaque<T>: 'a`
+
+                        let ty = tcx.mk_opaque(def_id, substs);
+                        required_predicates
+                            .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
+                            .or_insert(span);
+                    }
+
                     Component::EscapingProjection(_) => {
                         // As above, but the projection involves
                         // late-bound regions.  Therefore, the WF