about summary refs log tree commit diff
path: root/compiler/rustc_borrowck/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src')
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs2
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs15
-rw-r--r--compiler/rustc_borrowck/src/def_use.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs11
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs104
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs26
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs58
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs179
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs44
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs39
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs52
-rw-r--r--compiler/rustc_borrowck/src/lib.rs90
-rw-r--r--compiler/rustc_borrowck/src/member_constraints.rs6
-rw-r--r--compiler/rustc_borrowck/src/nll.rs2
-rw-r--r--compiler/rustc_borrowck/src/path_utils.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/dump_mir.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs48
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs18
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs15
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs14
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs86
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs65
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs132
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs4
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs126
32 files changed, 693 insertions, 488 deletions
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 952e18c1e57..4a9904891ec 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -84,7 +84,7 @@ pub enum LocalsStateAtExit {
 }
 
 impl LocalsStateAtExit {
-    fn build(
+    fn build<'tcx>(
         locals_are_invalidated_at_exit: bool,
         body: &Body<'tcx>,
         move_data: &MoveData<'tcx>,
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 98378a98684..d41143ee763 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -72,7 +72,7 @@ impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct OutlivesConstraint<'tcx> {
     // NB. The ordering here is not significant for correctness, but
     // it is for convenience. Before we dump the constraints in the
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 7db8d4520d4..f0036f09c38 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -5,10 +5,9 @@ use rustc_middle::ty::RegionVid;
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
 use rustc_mir_dataflow::ResultsVisitable;
-use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
+use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
 use rustc_mir_dataflow::{Analysis, Direction, Results};
 use std::fmt;
-use std::iter;
 
 use crate::{
     places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
@@ -385,14 +384,6 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
                 self.kill_borrows_on_place(trans, Place::from(local));
             }
 
-            mir::StatementKind::LlvmInlineAsm(ref asm) => {
-                for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
-                    if !kind.is_indirect && !kind.is_rw {
-                        self.kill_borrows_on_place(trans, *output);
-                    }
-                }
-            }
-
             mir::StatementKind::FakeRead(..)
             | mir::StatementKind::SetDiscriminant { .. }
             | mir::StatementKind::StorageLive(..)
@@ -434,9 +425,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
         &self,
         _trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _dest_place: mir::Place<'tcx>,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
     }
 }
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index 689ec249a2f..eec994f88b9 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -16,9 +16,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
 
         PlaceContext::MutatingUse(MutatingUseContext::Store) |
 
-        // This is potentially both a def and a use...
-        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
-
         // We let Call define the result in both the success and
         // unwind cases. This is not really correct, however it
         // does not seem to be observable due to the way that we
@@ -26,6 +23,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
         // the def in call only to the input from the success
         // path and not the unwind path. -nmatsakis
         PlaceContext::MutatingUse(MutatingUseContext::Call) |
+        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
         PlaceContext::MutatingUse(MutatingUseContext::Yield) |
 
         // Storage live and storage dead aren't proper defines, but we can ignore
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 15309ccd8df..96326ef2d5a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -31,7 +31,7 @@ enum UniverseInfoInner<'tcx> {
     Other,
 }
 
-impl UniverseInfo<'tcx> {
+impl<'tcx> UniverseInfo<'tcx> {
     crate fn other() -> UniverseInfo<'tcx> {
         UniverseInfo(UniverseInfoInner::Other)
     }
@@ -191,7 +191,7 @@ struct PredicateQuery<'tcx> {
     base_universe: ty::UniverseIndex,
 }
 
-impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
+impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
     fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
         err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
@@ -231,7 +231,7 @@ struct NormalizeQuery<'tcx, T> {
     base_universe: ty::UniverseIndex,
 }
 
-impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
+impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
 where
     T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
 {
@@ -291,7 +291,7 @@ struct AscribeUserTypeQuery<'tcx> {
     base_universe: ty::UniverseIndex,
 }
 
-impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
+impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
     fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
         // and is only the fallback when the nice error fails. Consider improving this some more.
@@ -339,7 +339,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
     // We generally shouldn't have errors here because the query was
     // already run, but there's no point using `delay_span_bug`
     // when we're going to emit an error here anyway.
-    let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
+    let _errors = fulfill_cx.select_all_or_error(infcx);
 
     let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
         debug!("{:#?}", region_constraints);
@@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
                 error_region,
                 cause.clone(),
                 placeholder_region,
+                vec![],
             ),
         ),
         (Some(error_region), _) => NiceRegionError::new(
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 439c728798d..ba111d394ec 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -15,16 +15,18 @@ use rustc_span::symbol::sym;
 use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt;
 
+use crate::borrow_set::TwoPhaseActivation;
 use crate::borrowck_errors;
 
+use crate::diagnostics::find_all_local_uses;
 use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
     InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
 };
 
 use super::{
-    explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
-    RegionNameSource, UseSpans,
+    explain_borrow::{BorrowExplanation, LaterUseKind},
+    FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
 };
 
 #[derive(Debug)]
@@ -407,14 +409,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     let generics = tcx.generics_of(self.mir_def_id());
                     let param = generics.type_param(&param_ty, tcx);
                     if let Some(generics) = tcx
-                        .hir()
-                        .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
+                        .typeck_root_def_id(self.mir_def_id().to_def_id())
+                        .as_local()
+                        .and_then(|def_id| tcx.hir().get_generics(def_id))
                     {
                         suggest_constraining_type_param(
                             tcx,
                             generics,
                             &mut err,
-                            &param.name.as_str(),
+                            param.name.as_str(),
                             "Copy",
                             None,
                         );
@@ -768,9 +771,92 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             Some((issued_span, span)),
         );
 
+        self.suggest_using_local_if_applicable(
+            &mut err,
+            location,
+            (place, span),
+            gen_borrow_kind,
+            issued_borrow,
+            explanation,
+        );
+
         err
     }
 
+    #[instrument(level = "debug", skip(self, err))]
+    fn suggest_using_local_if_applicable(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        location: Location,
+        (place, span): (Place<'tcx>, Span),
+        gen_borrow_kind: BorrowKind,
+        issued_borrow: &BorrowData<'tcx>,
+        explanation: BorrowExplanation,
+    ) {
+        let used_in_call =
+            matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _));
+        if !used_in_call {
+            debug!("not later used in call");
+            return;
+        }
+
+        let outer_call_loc =
+            if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
+                loc
+            } else {
+                issued_borrow.reserve_location
+            };
+        let outer_call_stmt = self.body.stmt_at(outer_call_loc);
+
+        let inner_param_location = location;
+        let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else {
+            debug!("`inner_param_location` {:?} is not for a statement", inner_param_location);
+            return;
+        };
+        let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else {
+            debug!(
+                "`inner_param_location` {:?} is not for an assignment: {:?}",
+                inner_param_location, inner_param_stmt
+            );
+            return;
+        };
+        let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
+        let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
+            let Either::Right(term) = self.body.stmt_at(loc) else {
+                debug!("{:?} is a statement, so it can't be a call", loc);
+                return None;
+            };
+            let TerminatorKind::Call { args, .. } = &term.kind else {
+                debug!("not a call: {:?}", term);
+                return None;
+            };
+            debug!("checking call args for uses of inner_param: {:?}", args);
+            if args.contains(&Operand::Move(inner_param)) {
+                Some((loc,term))
+            } else {
+                None
+            }
+        }) else {
+            debug!("no uses of inner_param found as a by-move call arg");
+            return;
+        };
+        debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
+
+        let inner_call_span = inner_call_term.source_info.span;
+        let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span;
+        if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
+            // FIXME: This stops the suggestion in some cases where it should be emitted.
+            //        Fix the spans for those cases so it's emitted correctly.
+            debug!(
+                "outer span {:?} does not strictly contain inner span {:?}",
+                outer_call_span, inner_call_span
+            );
+            return;
+        }
+        err.span_help(inner_call_span, "try adding a local storing this argument...");
+        err.span_help(outer_call_span, "...and then using that local as the argument to this call");
+    }
+
     fn suggest_split_at_mut_if_applicable(
         &self,
         err: &mut DiagnosticBuilder<'_>,
@@ -977,9 +1063,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 Some(ref name),
                 BorrowExplanation::MustBeValidFor {
                     category:
-                        category
-                        @
-                        (ConstraintCategory::Return(_)
+                        category @ (ConstraintCategory::Return(_)
                         | ConstraintCategory::CallArgument
                         | ConstraintCategory::OpaqueType),
                     from_closure: false,
@@ -1515,8 +1599,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         location: Location,
         mpi: MovePathIndex,
     ) -> (Vec<MoveSite>, Vec<Location>) {
-        fn predecessor_locations(
-            body: &'a mir::Body<'tcx>,
+        fn predecessor_locations<'a>(
+            body: &'a mir::Body<'_>,
             location: Location,
         ) -> impl Iterator<Item = Location> + 'a {
             if location.statement_index == 0 {
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 79973ab170c..db8268c8e2e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::{self, RegionVid, TyCtxt};
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{sym, DesugaringKind, Span};
 
 use crate::region_infer::BlameConstraint;
 use crate::{
@@ -135,7 +135,16 @@ impl BorrowExplanation {
                 should_note_order,
             } => {
                 let local_decl = &body.local_decls[dropped_local];
-                let (dtor_desc, type_desc) = match local_decl.ty.kind() {
+                let mut ty = local_decl.ty;
+                if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
+                    if let ty::Adt(adt, substs) = local_decl.ty.kind() {
+                        if tcx.is_diagnostic_item(sym::Option, adt.did) {
+                            // in for loop desugaring, only look at the `Some(..)` inner type
+                            ty = substs.type_at(0);
+                        }
+                    }
+                }
+                let (dtor_desc, type_desc) = match ty.kind() {
                     // If type is an ADT that implements Drop, then
                     // simplify output by reporting just the ADT name.
                     ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
new file mode 100644
index 00000000000..49d9caae711
--- /dev/null
+++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
@@ -0,0 +1,26 @@
+use std::collections::BTreeSet;
+
+use rustc_middle::mir::visit::{PlaceContext, Visitor};
+use rustc_middle::mir::{Body, Local, Location};
+
+/// Find all uses of (including assignments to) a [`Local`].
+///
+/// Uses `BTreeSet` so output is deterministic.
+pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet<Location> {
+    let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() };
+    visitor.visit_body(body);
+    visitor.uses
+}
+
+struct AllLocalUsesVisitor {
+    for_local: Local,
+    uses: BTreeSet<Location>,
+}
+
+impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor {
+    fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) {
+        if *local == self.for_local {
+            self.uses.insert(location);
+        }
+    }
+}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index a4df277a7b0..84acfbf941d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,16 +13,13 @@ use rustc_middle::mir::{
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{
-    hygiene::{DesugaringKind, ForLoopLoc},
-    symbol::sym,
-    Span,
-};
+use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
 use rustc_target::abi::VariantIdx;
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
 
+mod find_all_local_uses;
 mod find_use;
 mod outlives_suggestion;
 mod region_name;
@@ -209,7 +206,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             {
                 let local_info = &self.body.local_decls[local].local_info;
                 if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
-                    buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
+                    buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
                 } else {
                     unreachable!();
                 }
@@ -321,7 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let decl = &self.body.local_decls[local];
         match self.local_names[local] {
             Some(name) if !decl.from_compiler_desugaring() => {
-                buf.push_str(&name.as_str());
+                buf.push_str(name.as_str());
                 Ok(())
             }
             _ => Err(()),
@@ -375,7 +372,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     } else {
                         def.non_enum_variant()
                     };
-                    variant.fields[field.index()].ident.to_string()
+                    variant.fields[field.index()].name.to_string()
                 }
                 ty::Tuple(_) => field.index().to_string(),
                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
@@ -412,7 +409,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Add a note that a type does not implement `Copy`
     pub(super) fn note_type_does_not_implement_copy(
         &self,
-        err: &mut DiagnosticBuilder<'a>,
+        err: &mut DiagnosticBuilder<'_>,
         place_desc: &str,
         ty: Ty<'tcx>,
         span: Option<Span>,
@@ -736,21 +733,19 @@ pub(super) enum BorrowedContentSource<'tcx> {
     OverloadedIndex(Ty<'tcx>),
 }
 
-impl BorrowedContentSource<'tcx> {
+impl<'tcx> BorrowedContentSource<'tcx> {
     pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
         match *self {
             BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
             BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
             BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
-            BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
-                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
-                    "an `Rc`".to_string()
-                }
-                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
-                    "an `Arc`".to_string()
-                }
-                _ => format!("dereference of `{}`", ty),
-            },
+            BorrowedContentSource::OverloadedDeref(ty) => ty
+                .ty_adt_def()
+                .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+                    _ => None,
+                })
+                .unwrap_or_else(|| format!("dereference of `{}`", ty)),
             BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
         }
     }
@@ -774,15 +769,13 @@ impl BorrowedContentSource<'tcx> {
             BorrowedContentSource::DerefMutableRef => {
                 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
             }
-            BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
-                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
-                    "an `Rc`".to_string()
-                }
-                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
-                    "an `Arc`".to_string()
-                }
-                _ => format!("a dereference of `{}`", ty),
-            },
+            BorrowedContentSource::OverloadedDeref(ty) => ty
+                .ty_adt_def()
+                .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+                    _ => None,
+                })
+                .unwrap_or_else(|| format!("dereference of `{}`", ty)),
             BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
         }
     }
@@ -955,10 +948,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let kind = kind.unwrap_or_else(|| {
                 // This isn't a 'special' use of `self`
                 debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
-                let implicit_into_iter = matches!(
-                    fn_call_span.desugaring_kind(),
-                    Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
-                );
+                let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
+                    && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
                 let parent_self_ty = parent
                     .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
                     .and_then(|did| match tcx.type_of(did).kind() {
@@ -966,8 +957,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         _ => None,
                     });
                 let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
-                    tcx.is_diagnostic_item(sym::Option, def_id)
-                        || tcx.is_diagnostic_item(sym::Result, def_id)
+                    matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
                 });
                 FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
             });
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index d5ff4c6766f..8ed50075ecb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -165,10 +165,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             PlaceRef {
                 local: _,
                 projection:
-                    [.., ProjectionElem::Index(_)
-                    | ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. }
-                    | ProjectionElem::Downcast(..)],
+                    [
+                        ..,
+                        ProjectionElem::Index(_)
+                        | ProjectionElem::ConstantIndex { .. }
+                        | ProjectionElem::Subslice { .. }
+                        | ProjectionElem::Downcast(..),
+                    ],
             } => bug!("Unexpected immutable place."),
         }
 
@@ -217,19 +220,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             PlaceRef {
                 local,
                 projection:
-                    [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref],
+                    [
+                        proj_base @ ..,
+                        ProjectionElem::Deref,
+                        ProjectionElem::Field(field, _),
+                        ProjectionElem::Deref,
+                    ],
             } => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
-                if let Some((span, message)) = annotate_struct_field(
+                if let Some(span) = get_mut_span_in_struct_field(
                     self.infcx.tcx,
                     Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty,
                     field,
                 ) {
-                    err.span_suggestion(
+                    err.span_suggestion_verbose(
                         span,
                         "consider changing this to be mutable",
-                        message,
+                        " mut ".into(),
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -445,15 +453,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 },
                             ))) => {
                                 // check if the RHS is from desugaring
-                                let locations = self.body.find_assignments(local);
-                                let opt_assignment_rhs_span = locations
-                                    .first()
-                                    .map(|&location| self.body.source_info(location).span);
-                                let opt_desugaring_kind =
-                                    opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
-                                match opt_desugaring_kind {
+                                let opt_assignment_rhs_span =
+                                    self.body.find_assignments(local).first().map(|&location| {
+                                        if let Some(mir::Statement {
+                                            source_info: _,
+                                            kind:
+                                                mir::StatementKind::Assign(box (
+                                                    _,
+                                                    mir::Rvalue::Use(mir::Operand::Copy(place)),
+                                                )),
+                                        }) = self.body[location.block]
+                                            .statements
+                                            .get(location.statement_index)
+                                        {
+                                            self.body.local_decls[place.local].source_info.span
+                                        } else {
+                                            self.body.source_info(location).span
+                                        }
+                                    });
+                                match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
                                     // on for loops, RHS points to the iterator part
-                                    Some(DesugaringKind::ForLoop(_)) => {
+                                    Some(DesugaringKind::ForLoop) => {
                                         self.suggest_similar_mut_method_for_for_loop(&mut err);
                                         Some((
                                             false,
@@ -608,42 +628,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         };
         (
             true,
-            td.as_local().and_then(|tld| {
-                let h = hir_map.local_def_id_to_hir_id(tld);
-                match hir_map.find(h) {
-                    Some(Node::Item(hir::Item {
-                        kind: hir::ItemKind::Trait(_, _, _, _, items),
-                        ..
-                    })) => {
-                        let mut f_in_trait_opt = None;
-                        for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
-                            let hi = fi.hir_id();
-                            if !matches!(k, hir::AssocItemKind::Fn { .. }) {
-                                continue;
-                            }
-                            if hir_map.name(hi) != hir_map.name(my_hir) {
-                                continue;
-                            }
-                            f_in_trait_opt = Some(hi);
-                            break;
+            td.as_local().and_then(|tld| match hir_map.find_by_def_id(tld) {
+                Some(Node::Item(hir::Item {
+                    kind: hir::ItemKind::Trait(_, _, _, _, items),
+                    ..
+                })) => {
+                    let mut f_in_trait_opt = None;
+                    for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
+                        let hi = fi.hir_id();
+                        if !matches!(k, hir::AssocItemKind::Fn { .. }) {
+                            continue;
                         }
-                        f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
-                            Some(Node::TraitItem(hir::TraitItem {
-                                kind:
-                                    hir::TraitItemKind::Fn(
-                                        hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
-                                        _,
-                                    ),
-                                ..
-                            })) => {
-                                let hir::Ty { span, .. } = inputs[local.index() - 1];
-                                Some(span)
-                            }
-                            _ => None,
-                        })
+                        if hir_map.name(hi) != hir_map.name(my_hir) {
+                            continue;
+                        }
+                        f_in_trait_opt = Some(hi);
+                        break;
                     }
-                    _ => None,
+                    f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
+                        Some(Node::TraitItem(hir::TraitItem {
+                            kind:
+                                hir::TraitItemKind::Fn(
+                                    hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
+                                    _,
+                                ),
+                            ..
+                        })) => {
+                            let hir::Ty { span, .. } = inputs[local.index() - 1];
+                            Some(span)
+                        }
+                        _ => None,
+                    })
                 }
+                _ => None,
             }),
         )
     }
@@ -686,13 +703,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         &origin_projection,
                     ) {
                         match captured_place.info.capture_kind {
-                            ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                                kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
-                                ..
-                            }) => {
+                            ty::UpvarCapture::ByRef(
+                                ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+                            ) => {
                                 capture_reason = format!("mutable borrow of `{}`", upvar);
                             }
-                            ty::UpvarCapture::ByValue(_) => {
+                            ty::UpvarCapture::ByValue => {
                                 capture_reason = format!("possible mutation of `{}`", upvar);
                             }
                             _ => bug!("upvar `{}` borrowed, but not mutably", upvar),
@@ -727,7 +743,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             HirId, ImplItem, ImplItemKind, Item, ItemKind,
         };
 
-        fn maybe_body_id_of_fn(hir_map: &Map<'tcx>, id: HirId) -> Option<BodyId> {
+        fn maybe_body_id_of_fn(hir_map: &Map<'_>, id: HirId) -> Option<BodyId> {
             match hir_map.find(id) {
                 Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. }))
                 | Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => {
@@ -751,11 +767,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                                 kind:
                                                     Call(
                                                         _,
-                                                        [Expr {
-                                                            kind: MethodCall(path_segment, ..),
-                                                            hir_id,
-                                                            ..
-                                                        }, ..],
+                                                        [
+                                                            Expr {
+                                                                kind: MethodCall(path_segment, ..),
+                                                                hir_id,
+                                                                ..
+                                                            },
+                                                            ..,
+                                                        ],
                                                     ),
                                                 ..
                                             },
@@ -779,7 +798,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     .map(|assoc_items| {
                         assoc_items
                             .in_definition_order()
-                            .map(|assoc_item_def| assoc_item_def.ident)
+                            .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
                             .filter(|&ident| {
                                 let original_method_ident = path_segment.ident;
                                 original_method_ident != ident
@@ -874,7 +893,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         if look_at_return && hir.get_return_block(closure_id).is_some() {
             // ...otherwise we are probably in the tail expression of the function, point at the
             // return type.
-            match hir.get(hir.get_parent_item(fn_call_id)) {
+            match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) {
                 hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
                 | hir::Node::TraitItem(hir::TraitItem {
                     ident,
@@ -1036,47 +1055,31 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool {
     ty.is_closure() || ty.is_generator()
 }
 
-/// Adds a suggestion to a struct definition given a field access to a local.
-/// This function expects the local to be a reference to a struct in order to produce a suggestion.
+/// Given a field that needs to be mutable, returns a span where the " mut " could go.
+/// This function expects the local to be a reference to a struct in order to produce a span.
 ///
 /// ```text
-/// LL |     s: &'a String
-///    |        ---------- use `&'a mut String` here to make mutable
+/// LL |     s: &'a   String
+///    |           ^^^ returns a span taking up the space here
 /// ```
-fn annotate_struct_field(
+fn get_mut_span_in_struct_field<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     field: &mir::Field,
-) -> Option<(Span, String)> {
+) -> Option<Span> {
     // Expect our local to be a reference to a struct of some kind.
     if let ty::Ref(_, ty, _) = ty.kind() {
         if let ty::Adt(def, _) = ty.kind() {
             let field = def.all_fields().nth(field.index())?;
             // Use the HIR types to construct the diagnostic message.
-            let hir_id = tcx.hir().local_def_id_to_hir_id(field.did.as_local()?);
-            let node = tcx.hir().find(hir_id)?;
+            let node = tcx.hir().find_by_def_id(field.did.as_local()?)?;
             // Now we're dealing with the actual struct that we're going to suggest a change to,
             // we can expect a field that is an immutable reference to a type.
             if let hir::Node::Field(field) = node {
-                if let hir::TyKind::Rptr(
-                    lifetime,
-                    hir::MutTy { mutbl: hir::Mutability::Not, ref ty },
-                ) = field.ty.kind
+                if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::Not, ty }) =
+                    field.ty.kind
                 {
-                    // Get the snippets in two parts - the named lifetime (if there is one) and
-                    // type being referenced, that way we can reconstruct the snippet without loss
-                    // of detail.
-                    let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
-                    let lifetime_snippet = if !lifetime.is_elided() {
-                        format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
-                    } else {
-                        String::new()
-                    };
-
-                    return Some((
-                        field.ty.span,
-                        format!("&{}mut {}", lifetime_snippet, &*type_snippet,),
-                    ));
+                    return Some(lifetime.span.between(ty.span));
                 }
             }
         }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 11cdbe84acc..df23eaf24bc 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -6,7 +6,7 @@ use rustc_infer::infer::{
     error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
 };
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
@@ -334,13 +334,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
         match variance_info {
             ty::VarianceDiagInfo::None => {}
-            ty::VarianceDiagInfo::Mut { kind, ty } => {
-                let kind_name = match kind {
-                    ty::VarianceDiagMutKind::Ref => "reference",
-                    ty::VarianceDiagMutKind::RawPtr => "pointer",
+            ty::VarianceDiagInfo::Invariant { ty, param_index } => {
+                let (desc, note) = match ty.kind() {
+                    ty::RawPtr(ty_mut) => {
+                        assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut);
+                        (
+                            format!("a mutable pointer to {}", ty_mut.ty),
+                            "mutable pointers are invariant over their type parameter".to_string(),
+                        )
+                    }
+                    ty::Ref(_, inner_ty, mutbl) => {
+                        assert_eq!(*mutbl, rustc_hir::Mutability::Mut);
+                        (
+                            format!("a mutable reference to {}", inner_ty),
+                            "mutable references are invariant over their type parameter"
+                                .to_string(),
+                        )
+                    }
+                    ty::Adt(adt, substs) => {
+                        let generic_arg = substs[param_index as usize];
+                        let identity_substs =
+                            InternalSubsts::identity_for_item(self.infcx.tcx, adt.did);
+                        let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs);
+                        let base_generic_arg = identity_substs[param_index as usize];
+                        let adt_desc = adt.descr();
+
+                        let desc = format!(
+                            "the type {ty}, which makes the generic argument {generic_arg} invariant"
+                        );
+                        let note = format!(
+                            "the {adt_desc} {base_ty} is invariant over the parameter {base_generic_arg}"
+                        );
+                        (desc, note)
+                    }
+                    _ => panic!("Unexpected type {:?}", ty),
                 };
-                diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",));
-                diag.note(&format!("mutable {kind_name}s are invariant over their type parameter"));
+                diag.note(&format!("requirement occurs because of {desc}",));
+                diag.note(&note);
                 diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
             }
         }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 5edb52b0b65..01cc72121c7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -584,7 +584,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
-            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
                 // In this case, the user left off the lifetime; so
                 // they wrote something like:
                 //
@@ -704,7 +704,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         hir::AsyncGeneratorKind::Block => " of async block",
                         hir::AsyncGeneratorKind::Closure => " of async closure",
                         hir::AsyncGeneratorKind::Fn => {
-                            let parent_item = hir.get(hir.get_parent_item(mir_hir_id));
+                            let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id));
                             let output = &parent_item
                                 .fn_decl()
                                 .expect("generator lowered from async fn should be in fn")
@@ -769,20 +769,27 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             let opaque_ty = hir.item(id);
             if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                 bounds:
-                    [hir::GenericBound::LangItemTrait(
-                        hir::LangItem::Future,
-                        _,
-                        _,
-                        hir::GenericArgs {
-                            bindings:
-                                [hir::TypeBinding {
-                                    ident: Ident { name: sym::Output, .. },
-                                    kind: hir::TypeBindingKind::Equality { ty },
-                                    ..
-                                }],
-                            ..
-                        },
-                    )],
+                    [
+                        hir::GenericBound::LangItemTrait(
+                            hir::LangItem::Future,
+                            _,
+                            _,
+                            hir::GenericArgs {
+                                bindings:
+                                    [
+                                        hir::TypeBinding {
+                                            ident: Ident { name: sym::Output, .. },
+                                            kind:
+                                                hir::TypeBindingKind::Equality {
+                                                    term: hir::Term::Ty(ty),
+                                                },
+                                            ..
+                                        },
+                                    ],
+                                ..
+                            },
+                        ),
+                    ],
                 ..
             }) = opaque_ty.kind
             {
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index efd34f4e0a5..73ced63e4d7 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -5,12 +5,11 @@ use rustc_middle::mir::{BorrowKind, Mutability, Operand};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::mir::{Statement, StatementKind};
 use rustc_middle::ty::TyCtxt;
-use std::iter;
 
 use crate::{
     borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
-    Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode,
-    Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
+    Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read, ReadKind,
+    ReadOrWrite, Reservation, Shallow, Write, WriteKind,
 };
 
 pub(super) fn generate_invalidates<'tcx>(
@@ -59,37 +58,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
             StatementKind::Assign(box (lhs, rhs)) => {
                 self.consume_rvalue(location, rhs);
 
-                self.mutate_place(location, *lhs, Shallow(None), JustWrite);
+                self.mutate_place(location, *lhs, Shallow(None));
             }
             StatementKind::FakeRead(box (_, _)) => {
                 // Only relevant for initialized/liveness/safety checks.
             }
             StatementKind::SetDiscriminant { place, variant_index: _ } => {
-                self.mutate_place(location, **place, Shallow(None), JustWrite);
-            }
-            StatementKind::LlvmInlineAsm(asm) => {
-                for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
-                    if o.is_indirect {
-                        // FIXME(eddyb) indirect inline asm outputs should
-                        // be encoded through MIR place derefs instead.
-                        self.access_place(
-                            location,
-                            *output,
-                            (Deep, Read(ReadKind::Copy)),
-                            LocalMutationIsAllowed::No,
-                        );
-                    } else {
-                        self.mutate_place(
-                            location,
-                            *output,
-                            if o.is_rw { Deep } else { Shallow(None) },
-                            if o.is_rw { WriteAndRead } else { JustWrite },
-                        );
-                    }
-                }
-                for (_, input) in asm.inputs.iter() {
-                    self.consume_operand(location, input);
-                }
+                self.mutate_place(location, **place, Shallow(None));
             }
             StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
                 ref src,
@@ -142,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                 target: _,
                 unwind: _,
             } => {
-                self.mutate_place(location, *drop_place, Deep, JustWrite);
+                self.mutate_place(location, *drop_place, Deep);
                 self.consume_operand(location, new_value);
             }
             TerminatorKind::Call {
@@ -158,7 +133,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                     self.consume_operand(location, arg);
                 }
                 if let Some((dest, _ /*bb*/)) = destination {
-                    self.mutate_place(location, *dest, Deep, JustWrite);
+                    self.mutate_place(location, *dest, Deep);
                 }
             }
             TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@@ -181,7 +156,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                     }
                 }
 
-                self.mutate_place(location, *resume_arg, Deep, JustWrite);
+                self.mutate_place(location, *resume_arg, Deep);
             }
             TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
                 // Invalidate all borrows of local places
@@ -199,6 +174,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                 options: _,
                 line_spans: _,
                 destination: _,
+                cleanup: _,
             } => {
                 for op in operands {
                     match *op {
@@ -207,13 +183,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                         }
                         InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
                             if let Some(place) = place {
-                                self.mutate_place(location, place, Shallow(None), JustWrite);
+                                self.mutate_place(location, place, Shallow(None));
                             }
                         }
                         InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
                             self.consume_operand(location, in_value);
                             if let Some(out_place) = out_place {
-                                self.mutate_place(location, out_place, Shallow(None), JustWrite);
+                                self.mutate_place(location, out_place, Shallow(None));
                             }
                         }
                         InlineAsmOperand::Const { value: _ }
@@ -237,13 +213,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
 
 impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
     /// Simulates mutation of a place.
-    fn mutate_place(
-        &mut self,
-        location: Location,
-        place: Place<'tcx>,
-        kind: AccessDepth,
-        _mode: MutateMode,
-    ) {
+    fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) {
         self.access_place(
             location,
             place,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index aca7d3174f6..1e9acb114b7 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -3,9 +3,6 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(stmt_expr_attributes)]
@@ -43,7 +40,6 @@ use either::Either;
 use smallvec::SmallVec;
 use std::cell::RefCell;
 use std::collections::BTreeMap;
-use std::iter;
 use std::mem;
 use std::rc::Rc;
 
@@ -58,7 +54,6 @@ use rustc_mir_dataflow::MoveDataParamEnv;
 use self::diagnostics::{AccessKind, RegionName};
 use self::location::LocationTable;
 use self::prefixes::PrefixSet;
-use self::MutateMode::{JustWrite, WriteAndRead};
 use facts::AllFacts;
 
 use self::path_utils::*;
@@ -189,7 +184,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         .map(|captured_place| {
             let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
-                ty::UpvarCapture::ByValue(_) => false,
+                ty::UpvarCapture::ByValue => false,
                 ty::UpvarCapture::ByRef(..) => true,
             };
             Upvar { place: captured_place.clone(), by_ref }
@@ -633,7 +628,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
             StatementKind::Assign(box (lhs, ref rhs)) => {
                 self.consume_rvalue(location, (rhs, span), flow_state);
 
-                self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
+                self.mutate_place(location, (*lhs, span), Shallow(None), flow_state);
             }
             StatementKind::FakeRead(box (_, ref place)) => {
                 // Read for match doesn't access any memory and is used to
@@ -654,41 +649,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                 );
             }
             StatementKind::SetDiscriminant { place, variant_index: _ } => {
-                self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
+                self.mutate_place(location, (**place, span), Shallow(None), flow_state);
             }
-            StatementKind::LlvmInlineAsm(ref asm) => {
-                for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
-                    if o.is_indirect {
-                        // FIXME(eddyb) indirect inline asm outputs should
-                        // be encoded through MIR place derefs instead.
-                        self.access_place(
-                            location,
-                            (*output, o.span),
-                            (Deep, Read(ReadKind::Copy)),
-                            LocalMutationIsAllowed::No,
-                            flow_state,
-                        );
-                        self.check_if_path_or_subpath_is_moved(
-                            location,
-                            InitializationRequiringAction::Use,
-                            (output.as_ref(), o.span),
-                            flow_state,
-                        );
-                    } else {
-                        self.mutate_place(
-                            location,
-                            (*output, o.span),
-                            if o.is_rw { Deep } else { Shallow(None) },
-                            if o.is_rw { WriteAndRead } else { JustWrite },
-                            flow_state,
-                        );
-                    }
-                }
-                for (_, input) in asm.inputs.iter() {
-                    self.consume_operand(location, (input, span), flow_state);
-                }
-            }
-
             StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
                 ..
             }) => {
@@ -753,7 +715,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                 target: _,
                 unwind: _,
             } => {
-                self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state);
+                self.mutate_place(loc, (drop_place, span), Deep, flow_state);
                 self.consume_operand(loc, (new_value, span), flow_state);
             }
             TerminatorKind::Call {
@@ -769,7 +731,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     self.consume_operand(loc, (arg, span), flow_state);
                 }
                 if let Some((dest, _ /*bb*/)) = *destination {
-                    self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state);
+                    self.mutate_place(loc, (dest, span), Deep, flow_state);
                 }
             }
             TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@@ -783,7 +745,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
 
             TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
                 self.consume_operand(loc, (value, span), flow_state);
-                self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state);
+                self.mutate_place(loc, (resume_arg, span), Deep, flow_state);
             }
 
             TerminatorKind::InlineAsm {
@@ -792,6 +754,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                 options: _,
                 line_spans: _,
                 destination: _,
+                cleanup: _,
             } => {
                 for op in operands {
                     match *op {
@@ -800,13 +763,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                         }
                         InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
                             if let Some(place) = place {
-                                self.mutate_place(
-                                    loc,
-                                    (place, span),
-                                    Shallow(None),
-                                    JustWrite,
-                                    flow_state,
-                                );
+                                self.mutate_place(loc, (place, span), Shallow(None), flow_state);
                             }
                         }
                         InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
@@ -816,7 +773,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                                     loc,
                                     (out_place, span),
                                     Shallow(None),
-                                    JustWrite,
                                     flow_state,
                                 );
                             }
@@ -888,12 +844,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum MutateMode {
-    JustWrite,
-    WriteAndRead,
-}
-
 use self::AccessDepth::{Deep, Shallow};
 use self::ReadOrWrite::{Activation, Read, Reservation, Write};
 
@@ -979,7 +929,6 @@ enum LocalMutationIsAllowed {
 
 #[derive(Copy, Clone, Debug)]
 enum InitializationRequiringAction {
-    Update,
     Borrow,
     MatchOn,
     Use,
@@ -996,7 +945,6 @@ struct RootPlace<'tcx> {
 impl InitializationRequiringAction {
     fn as_noun(self) -> &'static str {
         match self {
-            InitializationRequiringAction::Update => "update",
             InitializationRequiringAction::Borrow => "borrow",
             InitializationRequiringAction::MatchOn => "use", // no good noun
             InitializationRequiringAction::Use => "use",
@@ -1007,7 +955,6 @@ impl InitializationRequiringAction {
 
     fn as_verb_in_past_tense(self) -> &'static str {
         match self {
-            InitializationRequiringAction::Update => "updated",
             InitializationRequiringAction::Borrow => "borrowed",
             InitializationRequiringAction::MatchOn => "matched on",
             InitializationRequiringAction::Use => "used",
@@ -1244,23 +1191,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         location: Location,
         place_span: (Place<'tcx>, Span),
         kind: AccessDepth,
-        mode: MutateMode,
         flow_state: &Flows<'cx, 'tcx>,
     ) {
-        // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
-        match mode {
-            MutateMode::WriteAndRead => {
-                self.check_if_path_or_subpath_is_moved(
-                    location,
-                    InitializationRequiringAction::Update,
-                    (place_span.0.as_ref(), place_span.1),
-                    flow_state,
-                );
-            }
-            MutateMode::JustWrite => {
-                self.check_if_assigned_path_is_moved(location, place_span, flow_state);
-            }
-        }
+        // Write of P[i] or *P requires P init'd.
+        self.check_if_assigned_path_is_moved(location, place_span, flow_state);
 
         // Special case: you can assign an immutable local variable
         // (e.g., `x = ...`) so long as it has never been initialized
@@ -1396,10 +1330,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
             Rvalue::NullaryOp(_op, _ty) => {
                 // nullary ops take no dynamic input; no borrowck effect.
-                //
-                // FIXME: is above actually true? Do we want to track
-                // the fact that uninitialized data can be created via
-                // `NullOp::Box`?
             }
 
             Rvalue::Aggregate(ref aggregate_kind, ref operands) => {
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index f22d355e613..0fe44328fd9 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -53,7 +53,7 @@ rustc_index::newtype_index! {
     }
 }
 
-impl Default for MemberConstraintSet<'tcx, ty::RegionVid> {
+impl Default for MemberConstraintSet<'_, ty::RegionVid> {
     fn default() -> Self {
         Self {
             first_constraints: Default::default(),
@@ -97,7 +97,7 @@ impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> {
     }
 }
 
-impl<R1> MemberConstraintSet<'tcx, R1>
+impl<'tcx, R1> MemberConstraintSet<'tcx, R1>
 where
     R1: Copy + Hash + Eq,
 {
@@ -140,7 +140,7 @@ where
     }
 }
 
-impl<R> MemberConstraintSet<'tcx, R>
+impl<R> MemberConstraintSet<'_, R>
 where
     R: Copy + Hash + Eq,
 {
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index e5924f9d084..6ffab165779 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
     errors_buffer: &mut Vec<Diagnostic>,
 ) {
     let tcx = infcx.tcx;
-    let base_def_id = tcx.closure_base_def_id(body.source.def_id());
+    let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
     if !tcx.has_attr(base_def_id, sym::rustc_regions) {
         return;
     }
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index d5d00b467ee..b2c8dfc82c2 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -141,7 +141,7 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
 /// then returns the index of the field being projected. Note that this closure will always
 /// be `self` in the current MIR, because that is the only time we directly access the fields
 /// of a closure type.
-pub(crate) fn is_upvar_field_projection(
+pub(crate) fn is_upvar_field_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
     upvars: &[Upvar<'tcx>],
     place_ref: PlaceRef<'tcx>,
diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
index cfd3acb6bde..97233b930c3 100644
--- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
+++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
@@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
 
         let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
-        constraints.sort();
+        constraints.sort_by_key(|c| (c.sup, c.sub));
         for constraint in &constraints {
             let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
             let (name, arg) = match locations {
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index f4a5da1fe36..d9120ff2457 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -569,7 +569,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // to store those. Otherwise, we'll pass in `None` to the
         // functions below, which will trigger them to report errors
         // eagerly.
-        let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
+        let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
 
         self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
 
@@ -612,7 +612,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
         debug!("constraints={:#?}", {
             let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
-            constraints.sort();
+            constraints.sort_by_key(|c| (c.sup, c.sub));
             constraints
                 .into_iter()
                 .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub)))
@@ -2229,7 +2229,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
             tcx,
             closure_substs,
             self.num_external_vids,
-            tcx.closure_base_def_id(closure_def_id),
+            tcx.typeck_root_def_id(closure_def_id),
         );
         debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 4eb7be542e7..76b3be7976c 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -173,7 +173,7 @@ fn check_opaque_type_parameter_valid(
         // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
         //
         // which would error here on all of the `'static` args.
-        OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true,
+        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
         // Check these
         OpaqueTyOrigin::TyAlias => {}
     }
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 8819039c752..4a70535c63b 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -1,5 +1,7 @@
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
+use rustc_index::bit_set::SparseBitMatrix;
+use rustc_index::interval::IntervalSet;
+use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::{BasicBlock, Body, Location};
@@ -60,6 +62,11 @@ impl RegionValueElements {
         PointIndex::new(start_index)
     }
 
+    /// Return the PointIndex for the block start of this index.
+    crate fn to_block_start(&self, index: PointIndex) -> PointIndex {
+        PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
+    }
+
     /// Converts a `PointIndex` back to a location. O(1).
     crate fn to_location(&self, index: PointIndex) -> Location {
         assert!(index.index() < self.num_points);
@@ -76,29 +83,6 @@ impl RegionValueElements {
     crate fn point_in_range(&self, index: PointIndex) -> bool {
         index.index() < self.num_points
     }
-
-    /// Pushes all predecessors of `index` onto `stack`.
-    crate fn push_predecessors(
-        &self,
-        body: &Body<'_>,
-        index: PointIndex,
-        stack: &mut Vec<PointIndex>,
-    ) {
-        let Location { block, statement_index } = self.to_location(index);
-        if statement_index == 0 {
-            // If this is a basic block head, then the predecessors are
-            // the terminators of other basic blocks
-            stack.extend(
-                body.predecessors()[block]
-                    .iter()
-                    .map(|&pred_bb| body.terminator_loc(pred_bb))
-                    .map(|pred_loc| self.point_from_location(pred_loc)),
-            );
-        } else {
-            // Otherwise, the pred is just the previous statement
-            stack.push(PointIndex::new(index.index() - 1));
-        }
-    }
 }
 
 rustc_index::newtype_index! {
@@ -128,11 +112,11 @@ crate enum RegionElement {
     PlaceholderRegion(ty::PlaceholderRegion),
 }
 
-/// When we initially compute liveness, we use a bit matrix storing
-/// points for each region-vid.
+/// When we initially compute liveness, we use an interval matrix storing
+/// liveness ranges for each region-vid.
 crate struct LivenessValues<N: Idx> {
     elements: Rc<RegionValueElements>,
-    points: SparseBitMatrix<N, PointIndex>,
+    points: SparseIntervalMatrix<N, PointIndex>,
 }
 
 impl<N: Idx> LivenessValues<N> {
@@ -140,7 +124,7 @@ impl<N: Idx> LivenessValues<N> {
     /// Each of the regions in num_region_variables will be initialized with an
     /// empty set of points and no causal information.
     crate fn new(elements: Rc<RegionValueElements>) -> Self {
-        Self { points: SparseBitMatrix::new(elements.num_points), elements }
+        Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
     }
 
     /// Iterate through each region that has a value in this set.
@@ -158,7 +142,7 @@ impl<N: Idx> LivenessValues<N> {
 
     /// Adds all the elements in the given bit array into the given
     /// region. Returns whether any of them are newly added.
-    crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
+    crate fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
         debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
         self.points.union_row(row, locations)
     }
@@ -171,7 +155,7 @@ impl<N: Idx> LivenessValues<N> {
     /// Returns `true` if the region `r` contains the given element.
     crate fn contains(&self, row: N, location: Location) -> bool {
         let index = self.elements.point_from_location(location);
-        self.points.contains(row, index)
+        self.points.row(row).map_or(false, |r| r.contains(index))
     }
 
     /// Returns an iterator of all the elements contained by the region `r`
@@ -239,7 +223,7 @@ impl PlaceholderIndices {
 crate struct RegionValues<N: Idx> {
     elements: Rc<RegionValueElements>,
     placeholder_indices: Rc<PlaceholderIndices>,
-    points: SparseBitMatrix<N, PointIndex>,
+    points: SparseIntervalMatrix<N, PointIndex>,
     free_regions: SparseBitMatrix<N, RegionVid>,
 
     /// Placeholders represent bound regions -- so something like `'a`
@@ -259,7 +243,7 @@ impl<N: Idx> RegionValues<N> {
         let num_placeholders = placeholder_indices.len();
         Self {
             elements: elements.clone(),
-            points: SparseBitMatrix::new(elements.num_points),
+            points: SparseIntervalMatrix::new(elements.num_points),
             placeholder_indices: placeholder_indices.clone(),
             free_regions: SparseBitMatrix::new(num_universal_regions),
             placeholders: SparseBitMatrix::new(num_placeholders),
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 20567610f65..4b6cab24cdb 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,7 +1,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::mir::visit::{MutVisitor, TyContext};
-use rustc_middle::mir::{Body, Location, PlaceElem, Promoted};
+use rustc_middle::mir::{Body, Location, Promoted};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 
@@ -62,22 +62,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
         debug!(?ty);
     }
 
-    fn process_projection_elem(
-        &mut self,
-        elem: PlaceElem<'tcx>,
-        _: Location,
-    ) -> Option<PlaceElem<'tcx>> {
-        if let PlaceElem::Field(field, ty) = elem {
-            let new_ty = self.renumber_regions(ty);
-
-            if new_ty != ty {
-                return Some(PlaceElem::Field(field, new_ty));
-            }
-        }
-
-        None
-    }
-
     #[instrument(skip(self), level = "debug")]
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
         *substs = self.renumber_regions(*substs);
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index ab1a7461b4b..a3b39591f8d 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -6,6 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::DUMMY_SP;
 
@@ -95,11 +96,23 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
                 self.add_outlives(r1_vid, r2_vid);
             }
 
-            GenericArgKind::Type(t1) => {
+            GenericArgKind::Type(mut t1) => {
                 // we don't actually use this for anything, but
                 // the `TypeOutlives` code needs an origin.
                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
 
+                // Placeholder regions need to be converted now because it may
+                // create new region variables, which can't be done later when
+                // verifying these bounds.
+                if t1.has_placeholders() {
+                    t1 = tcx.fold_regions(&t1, &mut false, |r, _| match *r {
+                        ty::RegionKind::RePlaceholder(placeholder) => {
+                            self.constraints.placeholder_region(self.infcx, placeholder)
+                        }
+                        _ => r,
+                    });
+                }
+
                 TypeOutlives::new(
                     &mut *self,
                     tcx,
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 f71cf09ecf6..fec6bdf314b 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -58,7 +58,7 @@ crate struct CreateResult<'tcx> {
     crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
 }
 
-crate fn create(
+crate fn create<'tcx>(
     infcx: &InferCtxt<'_, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     implicit_region_bound: Option<ty::Region<'tcx>>,
@@ -81,7 +81,7 @@ crate fn create(
     .create()
 }
 
-impl UniversalRegionRelations<'tcx> {
+impl UniversalRegionRelations<'_> {
     /// Records in the `outlives_relation` (and
     /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
     /// builder below.
@@ -110,7 +110,7 @@ impl UniversalRegionRelations<'tcx> {
     /// outlives `fr` and (b) is not local.
     ///
     /// (*) If there are multiple competing choices, we return all of them.
-    crate fn non_local_upper_bounds(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
+    crate fn non_local_upper_bounds<'a>(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
         debug!("non_local_upper_bound(fr={:?})", fr);
         let res = self.non_local_bounds(&self.inverse_outlives, fr);
         assert!(!res.is_empty(), "can't find an upper bound!?");
@@ -232,7 +232,7 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> {
     region_bound_pairs: RegionBoundPairs<'tcx>,
 }
 
-impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
+impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
     crate fn create(mut self) -> CreateResult<'tcx> {
         let unnormalized_input_output_tys = self
             .universal_regions
@@ -256,7 +256,6 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
                 debug!("build: input_or_output={:?}", ty);
                 // We add implied bounds from both the unnormalized and normalized ty
                 // See issue #87748
-                let constraints_implied_1 = self.add_implied_bounds(ty);
                 let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
@@ -284,10 +283,9 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
                 // }
                 // ```
                 // Both &Self::Bar and &() are WF
-                let constraints_implied_2 =
-                    if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
+                let constraints_implied = self.add_implied_bounds(norm_ty);
                 normalized_inputs_and_output.push(norm_ty);
-                constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2)
+                constraints1.into_iter().chain(constraints_implied)
             })
             .collect();
 
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 24332690bec..bc740de5150 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,13 +7,16 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
+use crate::type_check::constraint_conversion::ConstraintConversion;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::mir::*;
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
-use rustc_trait_selection::traits::query::normalize::AtExt;
+use rustc_span::DUMMY_SP;
+use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
+use rustc_trait_selection::traits::query::Fallible;
+use type_op::TypeOpOutput;
 
 use crate::universal_regions::UniversalRegions;
 
@@ -30,6 +33,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let (&normalized_output_ty, normalized_input_tys) =
             normalized_inputs_and_output.split_last().unwrap();
 
+        debug!(?normalized_output_ty);
+        debug!(?normalized_input_tys);
+
         let mir_def_id = body.source.def_id().expect_local();
 
         // If the user explicitly annotated the input types, extract
@@ -75,10 +81,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
                 break;
             }
+
             // In MIR, argument N is stored in local N+1.
             let local = Local::new(argument_index + 1);
 
             let mir_input_ty = body.local_decls[local].ty;
+
             let mir_input_span = body.local_decls[local].source_info.span;
             self.equate_normalized_input_or_output(
                 normalized_input_ty,
@@ -100,6 +108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // If the user explicitly annotated the input types, enforce those.
                 let user_provided_input_ty =
                     self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
+
                 self.equate_normalized_input_or_output(
                     user_provided_input_ty,
                     mir_input_ty,
@@ -108,9 +117,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
         }
 
-        assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
-        if let Some(mir_yield_ty) = body.yield_ty() {
-            let ur_yield_ty = universal_regions.yield_ty.unwrap();
+        debug!(
+            "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
+            body.yield_ty(),
+            universal_regions.yield_ty
+        );
+
+        // We will not have a universal_regions.yield_ty if we yield (by accident)
+        // outside of a generator and return an `impl Trait`, so emit a delay_span_bug
+        // because we don't want to panic in an assert here if we've already got errors.
+        if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
+            self.tcx().sess.delay_span_bug(
+                body.span,
+                &format!(
+                    "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
+                    body.yield_ty(),
+                    universal_regions.yield_ty,
+                ),
+            );
+        }
+
+        if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
+            (body.yield_ty(), universal_regions.yield_ty)
+        {
             let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
             self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
         }
@@ -167,30 +196,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
             // like to normalize *before* inserting into `local_decls`, but
             // doing so ends up causing some other trouble.
-            let b = match self
-                .infcx
-                .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
-                .normalize(b)
-            {
-                Ok(n) => {
-                    debug!("equate_inputs_and_outputs: {:?}", n);
-                    if n.obligations.iter().all(|o| {
-                        matches!(
-                            o.predicate.kind().skip_binder(),
-                            ty::PredicateKind::RegionOutlives(_)
-                                | ty::PredicateKind::TypeOutlives(_)
-                        )
-                    }) {
-                        n.value
-                    } else {
-                        b
-                    }
-                }
+            let b = match self.normalize_and_add_constraints(b) {
+                Ok(n) => n,
                 Err(_) => {
                     debug!("equate_inputs_and_outputs: NoSolution");
                     b
                 }
             };
+
             // Note: if we have to introduce new placeholders during normalization above, then we won't have
             // added those universes to the universe info, which we would want in `relate_tys`.
             if let Err(terr) =
@@ -207,4 +220,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
         }
     }
+
+    pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
+        let TypeOpOutput { output: norm_ty, constraints, .. } =
+            self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
+
+        debug!("{:?} normalized to {:?}", t, norm_ty);
+
+        for data in constraints.into_iter().collect::<Vec<_>>() {
+            ConstraintConversion::new(
+                self.infcx,
+                &self.borrowck_context.universal_regions,
+                &self.region_bound_pairs,
+                Some(self.implicit_region_bound),
+                self.param_env,
+                Locations::All(DUMMY_SP),
+                ConstraintCategory::Internal,
+                &mut self.borrowck_context.constraints,
+            )
+            .convert_all(&*data);
+        }
+
+        Ok(norm_ty)
+    }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index 8b74abd94c0..dd23683fae8 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -152,7 +152,7 @@ impl LocalUseMapBuild<'_> {
     }
 }
 
-impl Visitor<'tcx> for LocalUseMapBuild<'_> {
+impl Visitor<'_> for LocalUseMapBuild<'_> {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
         if self.locals_with_use_data[local] {
             match def_use::categorize(context) {
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index 1e712354d6a..f18fe1f43d4 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -74,7 +74,7 @@ pub(super) fn generate<'mir, 'tcx>(
 // to compute whether a variable `X` is live if that variable contains
 // some region `R` in its type where `R` is not known to outlive a free
 // region (i.e., where `R` may be valid for just a subset of the fn body).
-fn compute_live_locals(
+fn compute_live_locals<'tcx>(
     tcx: TyCtxt<'tcx>,
     free_regions: &FxHashSet<RegionVid>,
     body: &Body<'tcx>,
@@ -104,7 +104,7 @@ fn compute_live_locals(
 /// regions. For these regions, we do not need to compute
 /// liveness, since the outlives constraints will ensure that they
 /// are live over the whole fn body anyhow.
-fn regions_that_outlive_free_regions(
+fn regions_that_outlive_free_regions<'tcx>(
     num_region_vars: usize,
     universal_regions: &UniversalRegions<'tcx>,
     constraint_set: &OutlivesConstraintSet<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index 79ab8b713f9..ee067c4872f 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -53,7 +53,7 @@ impl UseFactsExtractor<'_> {
     }
 }
 
-impl Visitor<'tcx> for UseFactsExtractor<'_> {
+impl Visitor<'_> for UseFactsExtractor<'_> {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
         match def_use::categorize(context) {
             Some(DefUse::Def) => self.insert_def(local, location),
@@ -63,7 +63,7 @@ impl Visitor<'tcx> for UseFactsExtractor<'_> {
         }
     }
 
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
+    fn visit_place(&mut self, place: &Place<'_>, context: PlaceContext, location: Location) {
         self.super_place(place, context, location);
         match context {
             PlaceContext::NonMutatingUse(_) => {
@@ -82,7 +82,7 @@ impl Visitor<'tcx> for UseFactsExtractor<'_> {
     }
 }
 
-pub(super) fn populate_access_facts(
+pub(super) fn populate_access_facts<'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
     location_table: &LocationTable,
@@ -123,7 +123,7 @@ pub(super) fn populate_access_facts(
 
 // For every potentially drop()-touched region `region` in `local`'s type
 // (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
-pub(super) fn add_drop_of_var_derefs_origin(
+pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     local: Local,
     kind: &GenericArg<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 1671c7c627e..169de23facc 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::bit_set::HybridBitSet;
+use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
 use rustc_middle::ty::{Ty, TypeFoldable};
@@ -34,7 +35,7 @@ use crate::{
 /// DROP-LIVE set are to the liveness sets for regions found in the
 /// `dropck_outlives` result of the variable's type (in particular,
 /// this respects `#[may_dangle]` annotations).
-pub(super) fn trace(
+pub(super) fn trace<'mir, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
     elements: &Rc<RegionValueElements>,
@@ -105,12 +106,12 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
 
     /// Points where the current variable is "use live" -- meaning
     /// that there is a future "full use" that may use its value.
-    use_live_at: HybridBitSet<PointIndex>,
+    use_live_at: IntervalSet<PointIndex>,
 
     /// Points where the current variable is "drop live" -- meaning
     /// that there is no future "full use" that may use its value, but
     /// there is a future drop.
-    drop_live_at: HybridBitSet<PointIndex>,
+    drop_live_at: IntervalSet<PointIndex>,
 
     /// Locations where drops may occur.
     drop_locations: Vec<Location>,
@@ -119,14 +120,14 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
     stack: Vec<PointIndex>,
 }
 
-impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
+impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
     fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self {
         let num_points = cx.elements.num_points();
         LivenessResults {
             cx,
             defs: HybridBitSet::new_empty(num_points),
-            use_live_at: HybridBitSet::new_empty(num_points),
-            drop_live_at: HybridBitSet::new_empty(num_points),
+            use_live_at: IntervalSet::new(num_points),
+            drop_live_at: IntervalSet::new(num_points),
             drop_locations: vec![],
             stack: vec![],
         }
@@ -165,12 +166,12 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         drop_used: Vec<(Local, Location)>,
         live_locals: FxHashSet<Local>,
     ) {
-        let locations = HybridBitSet::new_empty(self.cx.elements.num_points());
+        let locations = IntervalSet::new(self.cx.elements.num_points());
 
         for (local, location) in drop_used {
             if !live_locals.contains(&local) {
                 let local_ty = self.cx.body.local_decls[local].ty;
-                if local_ty.has_free_regions(self.cx.typeck.tcx()) {
+                if local_ty.has_free_regions() {
                     self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
                 }
             }
@@ -205,12 +206,42 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
 
         self.stack.extend(self.cx.local_use_map.uses(local));
         while let Some(p) = self.stack.pop() {
-            if self.defs.contains(p) {
+            // We are live in this block from the closest to us of:
+            //
+            //  * Inclusively, the block start
+            //  * Exclusively, the previous definition (if it's in this block)
+            //  * Exclusively, the previous live_at setting (an optimization)
+            let block_start = self.cx.elements.to_block_start(p);
+            let previous_defs = self.defs.last_set_in(block_start..=p);
+            let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
+
+            let exclusive_start = match (previous_defs, previous_live_at) {
+                (Some(a), Some(b)) => Some(std::cmp::max(a, b)),
+                (Some(a), None) | (None, Some(a)) => Some(a),
+                (None, None) => None,
+            };
+
+            if let Some(exclusive) = exclusive_start {
+                self.use_live_at.insert_range(exclusive + 1..=p);
+
+                // If we have a bound after the start of the block, we should
+                // not add the predecessors for this block.
                 continue;
-            }
-
-            if self.use_live_at.insert(p) {
-                self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack)
+            } else {
+                // Add all the elements of this block.
+                self.use_live_at.insert_range(block_start..=p);
+
+                // Then add the predecessors for this block, which are the
+                // terminators of predecessor basic blocks. Push those onto the
+                // stack so that the next iteration(s) will process them.
+
+                let block = self.cx.elements.to_location(block_start).block;
+                self.stack.extend(
+                    self.cx.body.predecessors()[block]
+                        .iter()
+                        .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
+                        .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
+                );
             }
         }
     }
@@ -388,7 +419,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
     }
 }
 
-impl LivenessContext<'_, '_, '_, 'tcx> {
+impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     /// Returns `true` if the local variable (or some part of it) is initialized at the current
     /// cursor position. Callers should call one of the `seek` methods immediately before to point
     /// the cursor to the desired location.
@@ -426,7 +457,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
     fn add_use_live_facts_for(
         &mut self,
         value: impl TypeFoldable<'tcx>,
-        live_at: &HybridBitSet<PointIndex>,
+        live_at: &IntervalSet<PointIndex>,
     ) {
         debug!("add_use_live_facts_for(value={:?})", value);
 
@@ -443,7 +474,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
         dropped_local: Local,
         dropped_ty: Ty<'tcx>,
         drop_locations: &[Location],
-        live_at: &HybridBitSet<PointIndex>,
+        live_at: &IntervalSet<PointIndex>,
     ) {
         debug!(
             "add_drop_live_constraint(\
@@ -491,7 +522,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
         elements: &RegionValueElements,
         typeck: &mut TypeChecker<'_, 'tcx>,
         value: impl TypeFoldable<'tcx>,
-        live_at: &HybridBitSet<PointIndex>,
+        live_at: &IntervalSet<PointIndex>,
     ) {
         debug!("make_all_regions_live(value={:?})", value);
         debug!(
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 7e6a481ca69..73103643e3e 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::{Idx, IndexVec};
@@ -30,7 +31,7 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
 use rustc_middle::ty::{
     self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
-    ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
+    ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
 };
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
@@ -311,6 +312,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
     }
 }
 
+#[track_caller]
 fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) {
     // We sometimes see MIR failures (notably predicate failures) due to
     // the fact that we check rvalue sized predicates here. So use `delay_span_bug`
@@ -424,7 +426,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                         self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
                             constant.literal.ty(),
                             uv.def.did,
-                            UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None },
+                            UserSubsts { substs: uv.substs, user_self_ty: None },
                         )),
                     ) {
                         span_mirbug!(
@@ -655,7 +657,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             // If the region is live at at least one location in the promoted MIR,
             // then add a liveness constraint to the main MIR for this region
             // at the location provided as an argument to this method
-            if let Some(_) = liveness_constraints.get_elements(region).next() {
+            if liveness_constraints.get_elements(region).next().is_some() {
                 self.cx
                     .borrowck_context
                     .constraints
@@ -756,6 +758,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             },
             ProjectionElem::Field(field, fty) => {
                 let fty = self.sanitize_type(place, fty);
+                let fty = self.cx.normalize(fty, location);
                 match self.field_ty(place, base, field, location) {
                     Ok(ty) => {
                         let ty = self.cx.normalize(ty, location);
@@ -892,11 +895,11 @@ struct TypeChecker<'a, 'tcx> {
 }
 
 struct BorrowCheckContext<'a, 'tcx> {
-    universal_regions: &'a UniversalRegions<'tcx>,
+    pub(crate) universal_regions: &'a UniversalRegions<'tcx>,
     location_table: &'a LocationTable,
     all_facts: &'a mut Option<AllFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
-    constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
+    pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     upvars: &'a [Upvar<'tcx>],
 }
 
@@ -944,7 +947,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
     crate type_tests: Vec<TypeTest<'tcx>>,
 }
 
-impl MirTypeckRegionConstraints<'tcx> {
+impl<'tcx> MirTypeckRegionConstraints<'tcx> {
     fn placeholder_region(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -1156,6 +1159,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
     }
 
+    #[instrument(skip(self, category), level = "debug")]
     fn eq_types(
         &mut self,
         expected: Ty<'tcx>,
@@ -1343,13 +1347,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // though.
                 let category = match place.as_local() {
                     Some(RETURN_PLACE) => {
-                        if let BorrowCheckContext {
-                            universal_regions:
-                                UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
-                            ..
-                        } = self.borrowck_context
-                        {
-                            if tcx.is_static(*def_id) {
+                        let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
+                        if defining_ty.is_const() {
+                            if tcx.is_static(defining_ty.def_id()) {
                                 ConstraintCategory::UseAsStatic
                             } else {
                                 ConstraintCategory::UseAsConst
@@ -1479,7 +1479,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             StatementKind::FakeRead(..)
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
-            | StatementKind::LlvmInlineAsm { .. }
             | StatementKind::Retag { .. }
             | StatementKind::Coverage(..)
             | StatementKind::Nop => {}
@@ -1527,6 +1526,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
             TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+                self.check_operand(discr, term_location);
+
                 let discr_ty = discr.ty(body, tcx);
                 if let Err(terr) = self.sub_types(
                     discr_ty,
@@ -1549,6 +1550,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // FIXME: check the values
             }
             TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+                self.check_operand(func, term_location);
+                for arg in args {
+                    self.check_operand(arg, term_location);
+                }
+
                 let func_ty = func.ty(body, tcx);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
                 let sig = match func_ty.kind() {
@@ -1593,6 +1599,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
             }
             TerminatorKind::Assert { ref cond, ref msg, .. } => {
+                self.check_operand(cond, term_location);
+
                 let cond_ty = cond.ty(body, tcx);
                 if cond_ty != tcx.types.bool {
                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
@@ -1608,6 +1616,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
             TerminatorKind::Yield { ref value, .. } => {
+                self.check_operand(value, term_location);
+
                 let value_ty = value.ty(body, tcx);
                 match body.yield_ty() {
                     None => span_mirbug!(self, term, "yield in non-generator"),
@@ -1650,7 +1660,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     Some(RETURN_PLACE) => {
                         if let BorrowCheckContext {
                             universal_regions:
-                                UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
+                                UniversalRegions {
+                                    defining_ty:
+                                        DefiningTy::Const(def_id, _)
+                                        | DefiningTy::InlineConst(def_id, _),
+                                    ..
+                                },
                             ..
                         } = self.borrowck_context
                         {
@@ -1814,10 +1829,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     self.assert_iscleanup(body, block_data, unwind, true);
                 }
             }
-            TerminatorKind::InlineAsm { destination, .. } => {
+            TerminatorKind::InlineAsm { destination, cleanup, .. } => {
                 if let Some(target) = destination {
                     self.assert_iscleanup(body, block_data, target, is_cleanup);
                 }
+                if let Some(cleanup) = cleanup {
+                    if is_cleanup {
+                        span_mirbug!(self, block_data, "cleanup on cleanup block")
+                    }
+                    self.assert_iscleanup(body, block_data, cleanup, true);
+                }
             }
         }
     }
@@ -1896,7 +1917,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let tcx = self.tcx();
 
         match *ak {
-            AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => {
+            AggregateKind::Adt(adt_did, variant_index, substs, _, active_field_index) => {
+                let def = tcx.adt_def(adt_did);
                 let variant = &def.variants[variant_index];
                 let adj_field_index = active_field_index.unwrap_or(field_index);
                 if let Some(field) = variant.fields.get(adj_field_index) {
@@ -1931,15 +1953,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
+    fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+        if let Operand::Constant(constant) = op {
+            let maybe_uneval = match constant.literal {
+                ConstantKind::Ty(ct) => match ct.val {
+                    ty::ConstKind::Unevaluated(uv) => Some(uv),
+                    _ => None,
+                },
+                _ => None,
+            };
+            if let Some(uv) = maybe_uneval {
+                if uv.promoted.is_none() {
+                    let tcx = self.tcx();
+                    let def_id = uv.def.def_id_for_type_of();
+                    if tcx.def_kind(def_id) == DefKind::InlineConst {
+                        let predicates = self.prove_closure_bounds(
+                            tcx,
+                            def_id.expect_local(),
+                            uv.substs,
+                            location,
+                        );
+                        self.normalize_and_prove_instantiated_predicates(
+                            def_id,
+                            predicates,
+                            location.to_locations(),
+                        );
+                    }
+                }
+            }
+        }
+    }
+
     fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
         let tcx = self.tcx();
 
         match rvalue {
             Rvalue::Aggregate(ak, ops) => {
+                for op in ops {
+                    self.check_operand(op, location);
+                }
                 self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
             }
 
             Rvalue::Repeat(operand, len) => {
+                self.check_operand(operand, location);
+
                 // If the length cannot be evaluated we must assume that the length can be larger
                 // than 1.
                 // If the length is larger than 1, the repeat expression will need to copy the
@@ -1990,7 +2048,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
 
-            Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
+            Rvalue::NullaryOp(_, ty) => {
+                let trait_ref = ty::TraitRef {
+                    def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
+                    substs: tcx.mk_substs_trait(ty, &[]),
+                };
+
+                self.prove_trait_ref(
+                    trait_ref,
+                    location.to_locations(),
+                    ConstraintCategory::SizedBound,
+                );
+            }
+
+            Rvalue::ShallowInitBox(operand, ty) => {
+                self.check_operand(operand, location);
+
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
                     substs: tcx.mk_substs_trait(ty, &[]),
@@ -2004,6 +2077,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
 
             Rvalue::Cast(cast_kind, op, ty) => {
+                self.check_operand(op, location);
+
                 match cast_kind {
                     CastKind::Pointer(PointerCast::ReifyFnPointer) => {
                         let fn_sig = op.ty(body, tcx).fn_sig(tcx);
@@ -2250,6 +2325,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
                 box (left, right),
             ) => {
+                self.check_operand(left, location);
+                self.check_operand(right, location);
+
                 let ty_left = left.ty(body, tcx);
                 match ty_left.kind() {
                     // Types with regions are comparable if they have a common super-type.
@@ -2300,13 +2378,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
 
+            Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
+                self.check_operand(operand, location);
+            }
+
+            Rvalue::BinaryOp(_, box (left, right))
+            | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+                self.check_operand(left, location);
+                self.check_operand(right, location);
+            }
+
             Rvalue::AddressOf(..)
             | Rvalue::ThreadLocalRef(..)
-            | Rvalue::Use(..)
             | Rvalue::Len(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..) => {}
         }
     }
@@ -2539,8 +2623,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
 
         let (def_id, instantiated_predicates) = match aggregate_kind {
-            AggregateKind::Adt(def, _, substs, _, _) => {
-                (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs))
+            AggregateKind::Adt(adt_did, _, substs, _, _) => {
+                (*adt_did, tcx.predicates_of(*adt_did).instantiate(tcx, substs))
             }
 
             // For closures, we have some **extra requirements** we
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 415d1abaa8b..cc3fe0a123c 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -51,7 +51,7 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     universe_info: UniverseInfo<'tcx>,
 }
 
-impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
+impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     fn new(
         type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
         locations: Locations,
@@ -62,7 +62,7 @@ impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     }
 }
 
-impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
+impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.type_checker.param_env
     }
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 147e2aead64..16a903d5e59 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
 use std::iter;
 
 use crate::nll::ToRegionVid;
@@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> {
     /// is that it has no inputs and a single return value, which is
     /// the value of the constant.
     Const(DefId, SubstsRef<'tcx>),
+
+    /// The MIR represents an inline const. The signature has no inputs and a
+    /// single return value found via `InlineConstSubsts::ty`.
+    InlineConst(DefId, SubstsRef<'tcx>),
 }
 
 impl<'tcx> DefiningTy<'tcx> {
@@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> {
             DefiningTy::Generator(_, substs, _) => {
                 Either::Right(Either::Left(substs.as_generator().upvar_tys()))
             }
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
+            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
                 Either::Right(Either::Right(iter::empty()))
             }
         }
@@ -133,7 +137,7 @@ impl<'tcx> DefiningTy<'tcx> {
     pub fn implicit_inputs(self) -> usize {
         match self {
             DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
+            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
         }
     }
 
@@ -142,7 +146,7 @@ impl<'tcx> DefiningTy<'tcx> {
     }
 
     pub fn is_const(&self) -> bool {
-        matches!(*self, DefiningTy::Const(..))
+        matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
     }
 
     pub fn def_id(&self) -> DefId {
@@ -150,7 +154,8 @@ impl<'tcx> DefiningTy<'tcx> {
             DefiningTy::Closure(def_id, ..)
             | DefiningTy::Generator(def_id, ..)
             | DefiningTy::FnDef(def_id, ..)
-            | DefiningTy::Const(def_id, ..) => def_id,
+            | DefiningTy::Const(def_id, ..)
+            | DefiningTy::InlineConst(def_id, ..) => def_id,
         }
     }
 }
@@ -175,8 +180,9 @@ pub enum RegionClassification {
     /// anywhere. There is only one, `'static`.
     Global,
 
-    /// An **external** region is only relevant for closures. In that
-    /// case, it refers to regions that are free in the closure type
+    /// An **external** region is only relevant for
+    /// closures, generators, and inline consts. In that
+    /// case, it refers to regions that are free in the type
     /// -- basically, something bound in the surrounding context.
     ///
     /// Consider this example:
@@ -193,8 +199,8 @@ pub enum RegionClassification {
     /// Here, the lifetimes `'a` and `'b` would be **external** to the
     /// closure.
     ///
-    /// If we are not analyzing a closure, there are no external
-    /// lifetimes.
+    /// If we are not analyzing a closure/generator/inline-const,
+    /// there are no external lifetimes.
     External,
 
     /// A **local** lifetime is one about which we know the full set
@@ -242,7 +248,7 @@ impl<'tcx> UniversalRegions<'tcx> {
         tcx: TyCtxt<'tcx>,
         closure_substs: SubstsRef<'tcx>,
         expected_num_vars: usize,
-        closure_base_def_id: DefId,
+        typeck_root_def_id: DefId,
     ) -> IndexVec<RegionVid, ty::Region<'tcx>> {
         let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
         region_mapping.push(tcx.lifetimes.re_static);
@@ -250,7 +256,7 @@ impl<'tcx> UniversalRegions<'tcx> {
             region_mapping.push(fr);
         });
 
-        for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+        for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
             region_mapping.push(r);
         });
 
@@ -344,8 +350,8 @@ impl<'tcx> UniversalRegions<'tcx> {
                 // tests, and the resulting print-outs include def-ids
                 // and other things that are not stable across tests!
                 // So we just include the region-vid. Annoying.
-                let closure_base_def_id = tcx.closure_base_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
                     err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
                 });
             }
@@ -359,8 +365,8 @@ impl<'tcx> UniversalRegions<'tcx> {
                 // FIXME: As above, we'd like to print out the region
                 // `r` but doing so is not stable across architectures
                 // and so forth.
-                let closure_base_def_id = tcx.closure_base_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
                     err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
                 });
             }
@@ -376,6 +382,12 @@ impl<'tcx> UniversalRegions<'tcx> {
                     tcx.def_path_str_with_substs(def_id, substs),
                 ));
             }
+            DefiningTy::InlineConst(def_id, substs) => {
+                err.note(&format!(
+                    "defining inline constant type: {}",
+                    tcx.def_path_str_with_substs(def_id, substs),
+                ));
+            }
         }
     }
 }
@@ -411,24 +423,32 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+        let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
-        // If this is a closure or generator, then the late-bound regions from the enclosing
-        // function are actually external regions to us. For example, here, 'a is not local
-        // to the closure c (although it is local to the fn foo):
-        // fn foo<'a>() {
-        //     let c = || { let x: &'a u32 = ...; }
-        // }
-        if self.mir_def.did.to_def_id() != closure_base_def_id {
+        // If this is is a 'root' body (not a closure/generator/inline const), then
+        // there are no extern regions, so the local regions start at the same
+        // position as the (empty) sub-list of extern regions
+        let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+            first_extern_index
+        } else {
+            // If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing
+            // function are actually external regions to us. For example, here, 'a is not local
+            // to the closure c (although it is local to the fn foo):
+            // fn foo<'a>() {
+            //     let c = || { let x: &'a u32 = ...; }
+            // }
             self.infcx
-                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
-        }
-
-        let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
+            // Any regions created during the execution of `defining_ty` or during the above
+            // late-bound region replacement are all considered 'extern' regions
+            self.infcx.num_region_vars()
+        };
 
         // "Liberate" the late-bound regions. These correspond to
         // "local" free regions.
-        let first_local_index = self.infcx.num_region_vars();
+
+        let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
+
         let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
             FR,
             self.mir_def.did,
@@ -437,7 +457,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def.did.to_def_id() == closure_base_def_id {
+        if self.mir_def.did.to_def_id() == typeck_root_def_id {
             self.infcx
                 .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
         }
@@ -502,12 +522,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
-                    tcx.type_of(closure_base_def_id)
+                let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+                    tcx.type_of(typeck_root_def_id)
                 } else {
                     let tables = tcx.typeck(self.mir_def.did);
                     tables.node_type(self.mir_hir_id)
@@ -534,11 +554,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
-                let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
-                let substs =
-                    self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
-                DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+                let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+                if self.mir_def.did.to_def_id() == typeck_root_def_id {
+                    let substs =
+                        self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
+                    DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+                } else {
+                    let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+                    let substs = InlineConstSubsts::new(
+                        tcx,
+                        InlineConstSubstsParts { parent_substs: identity_substs, ty },
+                    )
+                    .substs;
+                    let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
+                    DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+                }
             }
         }
     }
@@ -553,17 +583,19 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
-        let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+        let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
         let fr_substs = match defining_ty {
-            DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
+            DefiningTy::Closure(_, ref substs)
+            | DefiningTy::Generator(_, ref substs, _)
+            | DefiningTy::InlineConst(_, ref substs) => {
                 // In the case of closures, we rely on the fact that
                 // the first N elements in the ClosureSubsts are
-                // inherited from the `closure_base_def_id`.
+                // inherited from the `typeck_root_def_id`.
                 // Therefore, when we zip together (below) with
                 // `identity_substs`, we will get only those regions
                 // that correspond to early-bound regions declared on
-                // the `closure_base_def_id`.
+                // the `typeck_root_def_id`.
                 assert!(substs.len() >= identity_substs.len());
                 assert_eq!(substs.regions().count(), identity_substs.regions().count());
                 substs
@@ -648,6 +680,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 let ty = indices.fold_to_region_vids(tcx, ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
             }
+
+            DefiningTy::InlineConst(def_id, substs) => {
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
+                let ty = substs.as_inline_const().ty();
+                ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+            }
         }
     }
 }
@@ -736,8 +774,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         indices: &mut UniversalRegionIndices<'tcx>,
     ) {
         debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
-        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
-        for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
+        let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
+        for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
             debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
             if !indices.indices.contains_key(&r) {
                 let region_vid = self.next_nll_region_var(FR);