about summary refs log tree commit diff
path: root/compiler/rustc_middle/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src')
-rw-r--r--compiler/rustc_middle/src/error.rs4
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs3
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs53
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs8
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs1
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs2
-rw-r--r--compiler/rustc_middle/src/mir/traversal.rs37
-rw-r--r--compiler/rustc_middle/src/query/keys.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs33
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs2
-rw-r--r--compiler/rustc_middle/src/thir.rs47
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs20
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs69
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs10
-rw-r--r--compiler/rustc_middle/src/ty/error.rs10
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs10
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs4
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs10
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs5
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/pattern.rs36
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs34
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs131
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs20
-rw-r--r--compiler/rustc_middle/src/ty/significant_drop_order.rs172
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs3
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs6
-rw-r--r--compiler/rustc_middle/src/ty/util.rs66
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs6
35 files changed, 543 insertions, 293 deletions
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index be8a3403ba9..bd315577efb 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -47,10 +47,10 @@ pub struct UnsupportedUnion {
 // FIXME(autodiff): I should get used somewhere
 #[derive(Diagnostic)]
 #[diag(middle_autodiff_unsafe_inner_const_ref)]
-pub struct AutodiffUnsafeInnerConstRef {
+pub struct AutodiffUnsafeInnerConstRef<'tcx> {
     #[primary_span]
     pub span: Span,
-    pub ty: String,
+    pub ty: Ty<'tcx>,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 171542d1279..d0dbf64dc59 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -1,8 +1,9 @@
+use std::sync::OnceLock;
+
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph;
 use rustc_data_structures::graph::dominators::{Dominators, dominators};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::OnceLock;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 95bc9b71fe0..ba65a711815 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -222,7 +222,7 @@ impl AllocError {
 }
 
 /// The information that makes up a memory access: offset and size.
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone)]
 pub struct AllocRange {
     pub start: Size,
     pub size: Size,
@@ -470,7 +470,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
             // Find the provenance.
             let (offset, _prov) = self
                 .provenance
-                .range_get_ptrs(range, cx)
+                .range_ptrs_get(range, cx)
                 .first()
                 .copied()
                 .expect("there must be provenance somewhere here");
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index 2f13f963578..c9525df1f79 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -2,6 +2,7 @@
 //! representation for the common case where PTR_SIZE consecutive bytes have the same provenance.
 
 use std::cmp;
+use std::ops::Range;
 
 use rustc_abi::{HasDataLayout, Size};
 use rustc_data_structures::sorted_map::SortedMap;
@@ -66,24 +67,33 @@ impl ProvenanceMap {
 }
 
 impl<Prov: Provenance> ProvenanceMap<Prov> {
+    fn adjusted_range_ptrs(range: AllocRange, cx: &impl HasDataLayout) -> Range<Size> {
+        // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
+        // the beginning of this range.
+        let adjusted_start = Size::from_bytes(
+            range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1),
+        );
+        adjusted_start..range.end()
+    }
+
     /// Returns all ptr-sized provenance in the given range.
     /// If the range has length 0, returns provenance that crosses the edge between `start-1` and
     /// `start`.
-    pub(super) fn range_get_ptrs(
+    pub(super) fn range_ptrs_get(
         &self,
         range: AllocRange,
         cx: &impl HasDataLayout,
     ) -> &[(Size, Prov)] {
-        // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
-        // the beginning of this range.
-        let adjusted_start = Size::from_bytes(
-            range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1),
-        );
-        self.ptrs.range(adjusted_start..range.end())
+        self.ptrs.range(Self::adjusted_range_ptrs(range, cx))
+    }
+
+    /// `pm.range_ptrs_is_empty(r, cx)` == `pm.range_ptrs_get(r, cx).is_empty()`, but is faster.
+    pub(super) fn range_ptrs_is_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool {
+        self.ptrs.range_is_empty(Self::adjusted_range_ptrs(range, cx))
     }
 
     /// Returns all byte-wise provenance in the given range.
-    fn range_get_bytes(&self, range: AllocRange) -> &[(Size, Prov)] {
+    fn range_bytes_get(&self, range: AllocRange) -> &[(Size, Prov)] {
         if let Some(bytes) = self.bytes.as_ref() {
             bytes.range(range.start..range.end())
         } else {
@@ -91,9 +101,14 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         }
     }
 
+    /// Same as `range_bytes_get(range).is_empty()`, but faster.
+    fn range_bytes_is_empty(&self, range: AllocRange) -> bool {
+        self.bytes.as_ref().is_none_or(|bytes| bytes.range_is_empty(range.start..range.end()))
+    }
+
     /// Get the provenance of a single byte.
     pub fn get(&self, offset: Size, cx: &impl HasDataLayout) -> Option<Prov> {
-        let prov = self.range_get_ptrs(alloc_range(offset, Size::from_bytes(1)), cx);
+        let prov = self.range_ptrs_get(alloc_range(offset, Size::from_bytes(1)), cx);
         debug_assert!(prov.len() <= 1);
         if let Some(entry) = prov.first() {
             // If it overlaps with this byte, it is on this byte.
@@ -117,7 +132,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
     /// limit access to provenance outside of the `Allocation` abstraction.
     ///
     pub fn range_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool {
-        self.range_get_ptrs(range, cx).is_empty() && self.range_get_bytes(range).is_empty()
+        self.range_ptrs_is_empty(range, cx) && self.range_bytes_is_empty(range)
     }
 
     /// Yields all the provenances stored in this map.
@@ -149,12 +164,14 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         // provenance that overlaps with the given range.
         let (first, last) = {
             // Find all provenance overlapping the given range.
-            let provenance = self.range_get_ptrs(range, cx);
-            if provenance.is_empty() {
-                // No provenance in this range, we are done.
+            if self.range_ptrs_is_empty(range, cx) {
+                // No provenance in this range, we are done. This is the common case.
                 return Ok(());
             }
 
+            // This redoes some of the work of `range_get_ptrs_is_empty`, but this path is much
+            // colder than the early return above, so it's worth it.
+            let provenance = self.range_ptrs_get(range, cx);
             (
                 provenance.first().unwrap().0,
                 provenance.last().unwrap().0 + cx.data_layout().pointer_size,
@@ -267,8 +284,8 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         // This includes the existing bytewise provenance in the range, and ptr provenance
         // that overlaps with the begin/end of the range.
         let mut dest_bytes_box = None;
-        let begin_overlap = self.range_get_ptrs(alloc_range(src.start, Size::ZERO), cx).first();
-        let end_overlap = self.range_get_ptrs(alloc_range(src.end(), Size::ZERO), cx).first();
+        let begin_overlap = self.range_ptrs_get(alloc_range(src.start, Size::ZERO), cx).first();
+        let end_overlap = self.range_ptrs_get(alloc_range(src.end(), Size::ZERO), cx).first();
         if !Prov::OFFSET_IS_ADDR {
             // There can't be any bytewise provenance, and we cannot split up the begin/end overlap.
             if let Some(entry) = begin_overlap {
@@ -291,10 +308,10 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
             } else {
                 trace!("no start overlapping entry");
             }
+
             // Then the main part, bytewise provenance from `self.bytes`.
-            if let Some(all_bytes) = self.bytes.as_ref() {
-                bytes.extend(all_bytes.range(src.start..src.end()));
-            }
+            bytes.extend(self.range_bytes_get(src));
+
             // And finally possibly parts of a pointer at the end.
             if let Some(entry) = end_overlap {
                 trace!("end overlapping entry: {entry:?}");
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 743812e3a20..890756a17ca 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -248,7 +248,7 @@ pub enum InvalidMetaKind {
 }
 
 impl IntoDiagArg for InvalidMetaKind {
-    fn into_diag_arg(self) -> DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
         DiagArgValue::Str(Cow::Borrowed(match self {
             InvalidMetaKind::SliceTooBig => "slice_too_big",
             InvalidMetaKind::TooBig => "too_big",
@@ -282,7 +282,7 @@ pub struct Misalignment {
 macro_rules! impl_into_diag_arg_through_debug {
     ($($ty:ty),*$(,)?) => {$(
         impl IntoDiagArg for $ty {
-            fn into_diag_arg(self) -> DiagArgValue {
+            fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
                 DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
             }
         }
@@ -401,7 +401,7 @@ pub enum PointerKind {
 }
 
 impl IntoDiagArg for PointerKind {
-    fn into_diag_arg(self) -> DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
         DiagArgValue::Str(
             match self {
                 Self::Ref(_) => "ref",
@@ -666,7 +666,7 @@ macro_rules! err_ub_custom {
                 msg: || $msg,
                 add_args: Box::new(move |mut set_arg| {
                     $($(
-                        set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name));
+                        set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name, &mut None));
                     )*)?
                 })
             }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 875f5282bf2..f880b1364c2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -319,6 +319,7 @@ pub fn write_mir_pretty<'tcx>(
 
     writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
     writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;
+    writeln!(w, "// HINT: See also -Z dump-mir for MIR at specific points during compilation.")?;
 
     let mut first = true;
     for def_id in dump_mir_def_ids(tcx, single) {
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index b887370fd69..bc77f22af67 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -357,7 +357,7 @@ impl<O> AssertKind<O> {
 
         macro_rules! add {
             ($name: expr, $value: expr) => {
-                adder($name.into(), $value.into_diag_arg());
+                adder($name.into(), $value.into_diag_arg(&mut None));
             };
         }
 
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index 5950ac295af..9308570d89d 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -23,19 +23,13 @@ pub struct Preorder<'a, 'tcx> {
     body: &'a Body<'tcx>,
     visited: DenseBitSet<BasicBlock>,
     worklist: Vec<BasicBlock>,
-    root_is_start_block: bool,
 }
 
 impl<'a, 'tcx> Preorder<'a, 'tcx> {
     pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> {
         let worklist = vec![root];
 
-        Preorder {
-            body,
-            visited: DenseBitSet::new_empty(body.basic_blocks.len()),
-            worklist,
-            root_is_start_block: root == START_BLOCK,
-        }
+        Preorder { body, visited: DenseBitSet::new_empty(body.basic_blocks.len()), worklist }
     }
 }
 
@@ -71,15 +65,11 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        // All the blocks, minus the number of blocks we've visited.
-        let upper = self.body.basic_blocks.len() - self.visited.count();
+        // The worklist might be only things already visited.
+        let lower = 0;
 
-        let lower = if self.root_is_start_block {
-            // We will visit all remaining blocks exactly once.
-            upper
-        } else {
-            self.worklist.len()
-        };
+        // This is extremely loose, but it's not worth a popcnt loop to do better.
+        let upper = self.body.basic_blocks.len();
 
         (lower, Some(upper))
     }
@@ -108,7 +98,6 @@ pub struct Postorder<'a, 'tcx> {
     basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
     visited: DenseBitSet<BasicBlock>,
     visit_stack: Vec<(BasicBlock, Successors<'a>)>,
-    root_is_start_block: bool,
     /// A non-empty `extra` allows for a precise calculation of the successors.
     extra: Option<(TyCtxt<'tcx>, Instance<'tcx>)>,
 }
@@ -123,7 +112,6 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
             basic_blocks,
             visited: DenseBitSet::new_empty(basic_blocks.len()),
             visit_stack: Vec::new(),
-            root_is_start_block: root == START_BLOCK,
             extra,
         };
 
@@ -211,16 +199,13 @@ impl<'tcx> Iterator for Postorder<'_, 'tcx> {
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        // All the blocks, minus the number of blocks we've visited.
-        let upper = self.basic_blocks.len() - self.visited.count();
-
-        let lower = if self.root_is_start_block {
-            // We will visit all remaining blocks exactly once.
-            upper
-        } else {
-            self.visit_stack.len()
-        };
+        // These bounds are not at all tight, but that's fine.
+        // It's not worth a popcnt loop in `DenseBitSet` to improve the upper,
+        // and in mono-reachable we can't be precise anyway.
+        // Leaning on amortized growth is fine.
 
+        let lower = self.visit_stack.len();
+        let upper = self.basic_blocks.len();
         (lower, Some(upper))
     }
 }
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 1489d57aba6..98314b5abfd 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -508,6 +508,14 @@ impl<'tcx, T: Clone> Key for CanonicalQueryInput<'tcx, T> {
     }
 }
 
+impl<'tcx, T: Clone> Key for (CanonicalQueryInput<'tcx, T>, bool) {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl Key for (Symbol, u32, u32) {
     type Cache<V> = DefaultCache<Self, V>;
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 7c4ea06a746..4ad4427594c 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -143,11 +143,11 @@ rustc_queries! {
 
     /// Represents crate as a whole (as distinct from the top-level crate module).
     ///
-    /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`),
+    /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir_crate()`),
     /// we will have to assume that any change means that you need to be recompiled.
     /// This is because the `hir_crate` query gives you access to all other items.
-    /// To avoid this fate, do not call `tcx.hir().krate()`; instead,
-    /// prefer wrappers like `tcx.visit_all_items_in_krate()`.
+    /// To avoid this fate, do not call `tcx.hir_crate()`; instead,
+    /// prefer wrappers like [`TyCtxt::hir_visit_all_item_likes_in_crate`].
     query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
         arena_cache
         eval_always
@@ -748,6 +748,15 @@ rustc_queries! {
         }
     }
 
+    /// Compute the conditions that need to hold for a conditionally-const item to be const.
+    /// That is, compute the set of `~const` where clauses for a given item.
+    ///
+    /// This can be thought of as the `~const` equivalent of `predicates_of`. These are the
+    /// predicates that need to be proven at usage sites, and can be assumed at definition.
+    ///
+    /// This query also computes the `~const` where clauses for associated types, which are
+    /// not "const", but which have item bounds which may be `~const`. These must hold for
+    /// the `~const` item bound to hold.
     query const_conditions(
         key: DefId
     ) -> ty::ConstConditions<'tcx> {
@@ -757,6 +766,11 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    /// Compute the const bounds that are implied for a conditionally-const item.
+    ///
+    /// This can be though of as the `~const` equivalent of `explicit_item_bounds`. These
+    /// are the predicates that need to proven at definition sites, and can be assumed at
+    /// usage sites.
     query explicit_implied_const_bounds(
         key: DefId
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
@@ -2248,22 +2262,13 @@ rustc_queries! {
         desc { "normalizing `{}`", goal.value }
     }
 
-    query implied_outlives_bounds_compat(
-        goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>
-    ) -> Result<
-        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
-        NoSolution,
-    > {
-        desc { "computing implied outlives bounds for `{}`", goal.canonical.value.value.ty }
-    }
-
     query implied_outlives_bounds(
-        goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>
+        key: (CanonicalImpliedOutlivesBoundsGoal<'tcx>, bool)
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
         NoSolution,
     > {
-        desc { "computing implied outlives bounds v2 for `{}`", goal.canonical.value.value.ty }
+        desc { "computing implied outlives bounds for `{}` (hack disabled = {:?})", key.0.canonical.value.value.ty, key.1 }
     }
 
     /// Do not call this query directly:
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 690b8128b1a..66a9e5fed4c 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -258,7 +258,7 @@ macro_rules! query_if_arena {
     };
 }
 
-/// If `separate_provide_if_extern`, then the key can be projected to its
+/// If `separate_provide_extern`, then the key can be projected to its
 /// local key via `<$K as AsLocalKey>::LocalKey`.
 macro_rules! local_key_if_separate_extern {
     ([] $($K:tt)*) => {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index e5592de81cd..72f31cec008 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -19,7 +19,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
 use rustc_index::{IndexVec, newtype_index};
-use rustc_macros::{HashStable, TypeVisitable};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -49,10 +49,13 @@ macro_rules! thir_with_elements {
             }
         )*
 
+        // Note: Making `Thir` implement `Clone` is useful for external tools that need access to
+        // THIR bodies even after the `Steal` query result has been stolen.
+        // One such tool is https://github.com/rust-corpus/qrates/.
         /// A container for a THIR body.
         ///
         /// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
-        #[derive(Debug, HashStable)]
+        #[derive(Debug, HashStable, Clone)]
         pub struct Thir<'tcx> {
             pub body_type: BodyTy<'tcx>,
             $(
@@ -90,7 +93,7 @@ thir_with_elements! {
     params: ParamId => Param<'tcx> => "p{}",
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Debug, HashStable, Clone)]
 pub enum BodyTy<'tcx> {
     Const(Ty<'tcx>),
     Fn(FnSig<'tcx>),
@@ -98,7 +101,7 @@ pub enum BodyTy<'tcx> {
 }
 
 /// Description of a type-checked function parameter.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Param<'tcx> {
     /// The pattern that appears in the parameter list, or None for implicit parameters.
     pub pat: Option<Box<Pat<'tcx>>>,
@@ -118,7 +121,7 @@ pub enum LintLevel {
     Explicit(HirId),
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Block {
     /// Whether the block itself has a label. Used by `label: {}`
     /// and `try` blocks.
@@ -138,7 +141,7 @@ pub struct Block {
 
 type UserTy<'tcx> = Option<Box<CanonicalUserType<'tcx>>>;
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct AdtExpr<'tcx> {
     /// The ADT we're constructing.
     pub adt_def: AdtDef<'tcx>,
@@ -155,7 +158,7 @@ pub struct AdtExpr<'tcx> {
     pub base: AdtExprBase<'tcx>,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum AdtExprBase<'tcx> {
     /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`.
     None,
@@ -168,7 +171,7 @@ pub enum AdtExprBase<'tcx> {
     DefaultFields(Box<[Ty<'tcx>]>),
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct ClosureExpr<'tcx> {
     pub closure_id: LocalDefId,
     pub args: UpvarArgs<'tcx>,
@@ -177,7 +180,7 @@ pub struct ClosureExpr<'tcx> {
     pub fake_reads: Vec<(ExprId, FakeReadCause, HirId)>,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct InlineAsmExpr<'tcx> {
     pub asm_macro: AsmMacro,
     pub template: &'tcx [InlineAsmTemplatePiece],
@@ -195,12 +198,12 @@ pub enum BlockSafety {
     ExplicitUnsafe(HirId),
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Stmt<'tcx> {
     pub kind: StmtKind<'tcx>,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum StmtKind<'tcx> {
     /// An expression with a trailing semicolon.
     Expr {
@@ -240,11 +243,11 @@ pub enum StmtKind<'tcx> {
     },
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
 pub struct LocalVarId(pub HirId);
 
 /// A THIR expression.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Expr<'tcx> {
     /// kind of expression
     pub kind: ExprKind<'tcx>,
@@ -271,7 +274,7 @@ pub struct TempLifetime {
     pub backwards_incompatible: Option<region::Scope>,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum ExprKind<'tcx> {
     /// `Scope`s are used to explicitly mark destruction scopes,
     /// and to track the `HirId` of the expressions within the scope.
@@ -548,20 +551,20 @@ pub enum ExprKind<'tcx> {
 /// Represents the association of a field identifier and an expression.
 ///
 /// This is used in struct constructors.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct FieldExpr {
     pub name: FieldIdx,
     pub expr: ExprId,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct FruInfo<'tcx> {
     pub base: ExprId,
     pub field_types: Box<[Ty<'tcx>]>,
 }
 
 /// A `match` arm.
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Arm<'tcx> {
     pub pattern: Box<Pat<'tcx>>,
     pub guard: Option<ExprId>,
@@ -579,7 +582,7 @@ pub enum LogicalOp {
     Or,
 }
 
-#[derive(Debug, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -616,13 +619,13 @@ pub enum InlineAsmOperand<'tcx> {
     },
 }
 
-#[derive(Debug, HashStable, TypeVisitable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct FieldPat<'tcx> {
     pub field: FieldIdx,
     pub pattern: Pat<'tcx>,
 }
 
-#[derive(Debug, HashStable, TypeVisitable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct Pat<'tcx> {
     pub ty: Ty<'tcx>,
     pub span: Span,
@@ -729,7 +732,7 @@ impl<'tcx> Pat<'tcx> {
     }
 }
 
-#[derive(Debug, HashStable, TypeVisitable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct Ascription<'tcx> {
     pub annotation: CanonicalUserTypeAnnotation<'tcx>,
     /// Variance to use when relating the `user_ty` to the **type of the value being
@@ -753,7 +756,7 @@ pub struct Ascription<'tcx> {
     pub variance: ty::Variance,
 }
 
-#[derive(Debug, HashStable, TypeVisitable)]
+#[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub enum PatKind<'tcx> {
     /// A wildcard pattern: `_`.
     Wild,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index d033ecc75db..53f233f20eb 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -266,7 +266,7 @@ pub enum ObligationCauseCode<'tcx> {
     },
 
     /// Constant expressions must be sized.
-    ConstSized,
+    SizedConstOrStatic,
 
     /// `static` items must have `Sync` type.
     SharedStatic,
@@ -397,9 +397,9 @@ pub enum ObligationCauseCode<'tcx> {
 
     RustCall,
 
-    /// Obligations to prove that a `std::ops::Drop` impl is not stronger than
+    /// Obligations to prove that a `Drop` or negative auto trait impl is not stronger than
     /// the ADT it's being implemented for.
-    DropImpl,
+    AlwaysApplicableImpl,
 
     /// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy`
     ConstParam(Ty<'tcx>),
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 6309dd2e490..ce4c08aa485 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_macros::{Decodable, Encodable, HashStable};
-use rustc_span::{Ident, Symbol};
+use rustc_span::{Ident, Symbol, sym};
 
 use super::{TyCtxt, Visibility};
 use crate::ty;
@@ -108,6 +108,24 @@ impl AssocItem {
     pub fn is_impl_trait_in_trait(&self) -> bool {
         self.opt_rpitit_info.is_some()
     }
+
+    /// Returns true if:
+    /// - This trait associated item has the `#[type_const]` attribute,
+    /// - If it is in a trait impl, the item from the original trait has this attribute, or
+    /// - It is an inherent assoc const.
+    pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
+        if self.kind != ty::AssocKind::Const {
+            return false;
+        }
+
+        let def_id = match (self.container, self.trait_item_def_id) {
+            (AssocItemContainer::Trait, _) => self.def_id,
+            (AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did,
+            // Inherent impl but this attr is only applied to trait assoc items.
+            (AssocItemContainer::Impl, None) => return true,
+        };
+        tcx.has_attr(def_id, sym::type_const)
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 41958949836..fe42a224d9f 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -224,7 +224,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Ty<'tcx> {
             })
         } else {
             let tcx = decoder.interner();
-            tcx.mk_ty_from_kind(rustc_type_ir::TyKind::decode(decoder))
+            tcx.mk_ty_from_kind(ty::TyKind::decode(decoder))
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index b72edc1c532..7c9280fae16 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -118,7 +118,7 @@ impl std::fmt::Debug for ConstInt {
 impl IntoDiagArg for ConstInt {
     // FIXME this simply uses the Debug impl, but we could probably do better by converting both
     // to an inherent method that returns `Cow`.
-    fn into_diag_arg(self) -> DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
         DiagArgValue::Str(format!("{self:?}").into())
     }
 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 62a384af12f..4013f7b2c85 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -324,11 +324,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.features()
     }
 
-    fn bound_coroutine_hidden_types(
+    fn coroutine_hidden_types(
         self,
         def_id: DefId,
-    ) -> impl IntoIterator<Item = ty::EarlyBinder<'tcx, ty::Binder<'tcx, Ty<'tcx>>>> {
-        self.bound_coroutine_hidden_types(def_id)
+    ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>> {
+        self.coroutine_hidden_types(def_id)
     }
 
     fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
@@ -594,6 +594,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.trait_is_auto(trait_def_id)
     }
 
+    fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
+        self.trait_is_coinductive(trait_def_id)
+    }
+
     fn trait_is_alias(self, trait_def_id: DefId) -> bool {
         self.trait_is_alias(trait_def_id)
     }
@@ -812,32 +816,38 @@ pub struct CtxtInterners<'tcx> {
 
 impl<'tcx> CtxtInterners<'tcx> {
     fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
+        // Default interner size - this value has been chosen empirically, and may need to be adjusted
+        // as the compiler evolves.
+        const N: usize = 2048;
         CtxtInterners {
             arena,
-            type_: Default::default(),
-            const_lists: Default::default(),
-            args: Default::default(),
-            type_lists: Default::default(),
-            region: Default::default(),
-            poly_existential_predicates: Default::default(),
-            canonical_var_infos: Default::default(),
-            predicate: Default::default(),
-            clauses: Default::default(),
-            projs: Default::default(),
-            place_elems: Default::default(),
-            const_: Default::default(),
-            pat: Default::default(),
-            const_allocation: Default::default(),
-            bound_variable_kinds: Default::default(),
-            layout: Default::default(),
-            adt_def: Default::default(),
-            external_constraints: Default::default(),
-            predefined_opaques_in_body: Default::default(),
-            fields: Default::default(),
-            local_def_ids: Default::default(),
-            captures: Default::default(),
-            offset_of: Default::default(),
-            valtree: Default::default(),
+            // The factors have been chosen by @FractalFir based on observed interner sizes, and local perf runs.
+            // To get the interner sizes, insert `eprintln` printing the size of the interner in functions like `intern_ty`.
+            // Bigger benchmarks tend to give more accurate ratios, so use something like `x perf eprintln --includes cargo`.
+            type_: InternedSet::with_capacity(N * 16),
+            const_lists: InternedSet::with_capacity(N * 4),
+            args: InternedSet::with_capacity(N * 4),
+            type_lists: InternedSet::with_capacity(N * 4),
+            region: InternedSet::with_capacity(N * 4),
+            poly_existential_predicates: InternedSet::with_capacity(N / 4),
+            canonical_var_infos: InternedSet::with_capacity(N / 2),
+            predicate: InternedSet::with_capacity(N),
+            clauses: InternedSet::with_capacity(N),
+            projs: InternedSet::with_capacity(N * 4),
+            place_elems: InternedSet::with_capacity(N * 2),
+            const_: InternedSet::with_capacity(N * 2),
+            pat: InternedSet::with_capacity(N),
+            const_allocation: InternedSet::with_capacity(N),
+            bound_variable_kinds: InternedSet::with_capacity(N * 2),
+            layout: InternedSet::with_capacity(N),
+            adt_def: InternedSet::with_capacity(N),
+            external_constraints: InternedSet::with_capacity(N),
+            predefined_opaques_in_body: InternedSet::with_capacity(N),
+            fields: InternedSet::with_capacity(N * 4),
+            local_def_ids: InternedSet::with_capacity(N),
+            captures: InternedSet::with_capacity(N),
+            offset_of: InternedSet::with_capacity(N),
+            valtree: InternedSet::with_capacity(N),
         }
     }
 
@@ -1317,6 +1327,11 @@ pub struct TyCtxt<'tcx> {
     gcx: &'tcx GlobalCtxt<'tcx>,
 }
 
+// Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its
+// field are asserted to implement these traits below, so this is trivially safe, and it greatly
+// speeds-up compilation of this crate and its dependents.
+unsafe impl DynSend for TyCtxt<'_> {}
+unsafe impl DynSync for TyCtxt<'_> {}
 fn _assert_tcx_fields() {
     sync::assert_dyn_sync::<&'_ GlobalCtxt<'_>>();
     sync::assert_dyn_send::<&'_ GlobalCtxt<'_>>();
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index cb218a27e62..881381a5ee6 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -19,8 +19,16 @@ use crate::ty::{
     TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 
+impl IntoDiagArg for Ty<'_> {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
+        ty::tls::with(|tcx| {
+            let ty = tcx.short_string(self, path);
+            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(ty))
+        })
+    }
+}
+
 into_diag_arg_using_display! {
-    Ty<'_>,
     ty::Region<'_>,
 }
 
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 8c1991ddb36..a0e67929c52 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -213,10 +213,9 @@ impl<'tcx> Ty<'tcx> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String
+    pub fn string_with_limit<T>(self, p: T, length_limit: usize) -> String
     where
-        T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy,
-        <T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
+        T: Copy + for<'a, 'b> Lift<TyCtxt<'b>, Lifted: Print<'b, FmtPrinter<'a, 'b>>>,
     {
         let mut type_limit = 50;
         let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
@@ -253,10 +252,9 @@ impl<'tcx> TyCtxt<'tcx> {
     /// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps
     /// the existence of a "long type" anywhere in the diagnostic, so the note telling the user
     /// where we wrote the file to is only printed once.
-    pub fn short_string<'a, T>(self, p: T, path: &mut Option<PathBuf>) -> String
+    pub fn short_string<T>(self, p: T, path: &mut Option<PathBuf>) -> String
     where
-        T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy + Hash,
-        <T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
+        T: Copy + Hash + for<'a, 'b> Lift<TyCtxt<'b>, Lifted: Print<'b, FmtPrinter<'a, 'b>>>,
     {
         let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
             self.lift(p).expect("could not lift for printing").print(cx)
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index ec0498b168c..0b8f0e8cd41 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -220,13 +220,9 @@ impl FlagComputation {
             &ty::Pat(ty, pat) => {
                 self.add_ty(ty);
                 match *pat {
-                    ty::PatternKind::Range { start, end, include_end: _ } => {
-                        if let Some(start) = start {
-                            self.add_const(start)
-                        }
-                        if let Some(end) = end {
-                            self.add_const(end)
-                        }
+                    ty::PatternKind::Range { start, end } => {
+                        self.add_const(start);
+                        self.add_const(end);
                     }
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index ed0b3059d75..27576a2ec4a 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -159,8 +159,8 @@ unsafe impl<'tcx> Sync for GenericArg<'tcx> where
 }
 
 impl<'tcx> IntoDiagArg for GenericArg<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.to_string().into_diag_arg()
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self.to_string().into_diag_arg(&mut None)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
index 505c7278176..953ad62be0a 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -236,6 +236,11 @@ impl<'tcx> InhabitedPredicate<'tcx> {
         self.instantiate_opt(tcx, args).unwrap_or(self)
     }
 
+    /// Same as [`Self::instantiate`], but if there is no generics to
+    /// instantiate, returns `None`. This is useful because it lets us avoid
+    /// allocating a recursive copy of everything when the result is unchanged.
+    ///
+    /// Only used to implement `instantiate` itself.
     fn instantiate_opt(self, tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> Option<Self> {
         match self {
             Self::ConstIsZero(c) => {
@@ -260,7 +265,10 @@ impl<'tcx> InhabitedPredicate<'tcx> {
                 Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True),
                 Some(a) => Some(a.or(tcx, b.instantiate_opt(tcx, args).unwrap_or(b))),
             },
-            _ => None,
+            Self::True | Self::False | Self::NotInModule(_) => None,
+            Self::OpaqueType(_) => {
+                bug!("unexpected OpaqueType in InhabitedPredicate");
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index e9c19331e4a..98ca71b86be 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -111,8 +111,9 @@ pub enum InstanceKind<'tcx> {
 
     /// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
     ///
-    /// This `InstanceKind` does not have callable MIR. Calls to `Virtual` instances must be
-    /// codegen'd as virtual calls through the vtable.
+    /// This `InstanceKind` may have a callable MIR as the default implementation.
+    /// Calls to `Virtual` instances must be codegen'd as virtual calls through the vtable.
+    /// *This means we might not know exactly what is being called.*
     ///
     /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more
     /// details on that).
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index eb14ed20fba..272bb0cc915 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -315,8 +315,8 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
 }
 
 impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.to_string().into_diag_arg()
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self.to_string().into_diag_arg(&mut None)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index eb70a35d370..527509af05f 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -122,6 +122,7 @@ pub mod normalize_erasing_regions;
 pub mod pattern;
 pub mod print;
 pub mod relate;
+pub mod significant_drop_order;
 pub mod trait_def;
 pub mod util;
 pub mod visit;
@@ -991,12 +992,6 @@ impl<'tcx> ParamEnv<'tcx> {
         ParamEnv { caller_bounds }
     }
 
-    /// Returns this same environment but with no caller bounds.
-    #[inline]
-    pub fn without_caller_bounds(self) -> Self {
-        Self::new(ListWithCachedTypeInfo::empty())
-    }
-
     /// Creates a pair of param-env and value for use in queries.
     pub fn and<T: TypeVisitable<TyCtxt<'tcx>>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
         ParamEnvAnd { param_env: self, value }
diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs
index e604aedd05e..4cad1ab2099 100644
--- a/compiler/rustc_middle/src/ty/pattern.rs
+++ b/compiler/rustc_middle/src/ty/pattern.rs
@@ -26,18 +26,30 @@ impl<'tcx> fmt::Debug for Pattern<'tcx> {
 impl<'tcx> fmt::Debug for PatternKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            PatternKind::Range { start, end, include_end } => {
-                if let Some(start) = start {
-                    write!(f, "{start}")?;
+            PatternKind::Range { start, end } => {
+                write!(f, "{start}")?;
+
+                if let Some(c) = end.try_to_value() {
+                    let end = c.valtree.unwrap_leaf();
+                    let size = end.size();
+                    let max = match c.ty.kind() {
+                        ty::Int(_) => {
+                            Some(ty::ScalarInt::truncate_from_int(size.signed_int_max(), size))
+                        }
+                        ty::Uint(_) => {
+                            Some(ty::ScalarInt::truncate_from_uint(size.unsigned_int_max(), size))
+                        }
+                        ty::Char => Some(ty::ScalarInt::truncate_from_uint(char::MAX, size)),
+                        _ => None,
+                    };
+                    if let Some((max, _)) = max
+                        && end == max
+                    {
+                        return write!(f, "..");
+                    }
                 }
-                write!(f, "..")?;
-                if include_end {
-                    write!(f, "=")?;
-                }
-                if let Some(end) = end {
-                    write!(f, "{end}")?;
-                }
-                Ok(())
+
+                write!(f, "..={end}")
             }
         }
     }
@@ -46,5 +58,5 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> {
 #[derive(Clone, PartialEq, Eq, Hash)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
 pub enum PatternKind<'tcx> {
-    Range { start: Option<ty::Const<'tcx>>, end: Option<ty::Const<'tcx>>, include_end: bool },
+    Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> },
 }
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 553de83dfcb..1674ca4cfc5 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -4,7 +4,6 @@ use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, extension};
 use rustc_type_ir as ir;
-use tracing::instrument;
 
 use crate::ty::{
     self, DebruijnIndex, EarlyBinder, PredicatePolarity, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom,
@@ -51,10 +50,6 @@ impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx>
         self.as_clause()
     }
 
-    fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool {
-        self.is_coinductive(interner)
-    }
-
     fn allow_normalization(self) -> bool {
         self.allow_normalization()
     }
@@ -119,17 +114,6 @@ impl<'tcx> Predicate<'tcx> {
         Some(tcx.mk_predicate(kind))
     }
 
-    #[instrument(level = "debug", skip(tcx), ret)]
-    pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool {
-        match self.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
-                tcx.trait_is_coinductive(data.def_id())
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true,
-            _ => false,
-        }
-    }
-
     /// Whether this projection can be soundly normalized.
     ///
     /// Wf predicates must not be normalized, as normalization
@@ -158,15 +142,21 @@ impl<'tcx> Predicate<'tcx> {
     }
 }
 
-impl rustc_errors::IntoDiagArg for Predicate<'_> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
+impl<'tcx> rustc_errors::IntoDiagArg for Predicate<'tcx> {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
+        ty::tls::with(|tcx| {
+            let pred = tcx.short_string(self, path);
+            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(pred))
+        })
     }
 }
 
-impl rustc_errors::IntoDiagArg for Clause<'_> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
+impl<'tcx> rustc_errors::IntoDiagArg for Clause<'tcx> {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
+        ty::tls::with(|tcx| {
+            let clause = tcx.short_string(self, path);
+            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(clause))
+        })
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ed0839f47e6..34d85534d0a 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -133,6 +133,20 @@ pub macro with_no_queries($e:expr) {{
     ))
 }}
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum WrapBinderMode {
+    ForAll,
+    Unsafe,
+}
+impl WrapBinderMode {
+    pub fn start_str(self) -> &'static str {
+        match self {
+            WrapBinderMode::ForAll => "for<",
+            WrapBinderMode::Unsafe => "unsafe<",
+        }
+    }
+}
+
 /// The "region highlights" are used to control region printing during
 /// specific error messages. When a "region highlight" is enabled, it
 /// gives an alternate way to print specific regions. For now, we
@@ -219,7 +233,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         self.print_def_path(def_id, args)
     }
 
-    fn in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
+    fn print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
     where
         T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
     {
@@ -229,6 +243,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
     fn wrap_binder<T, F: FnOnce(&T, &mut Self) -> Result<(), fmt::Error>>(
         &mut self,
         value: &ty::Binder<'tcx, T>,
+        _mode: WrapBinderMode,
         f: F,
     ) -> Result<(), PrintError>
     where
@@ -703,8 +718,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             }
             ty::FnPtr(ref sig_tys, hdr) => p!(print(sig_tys.with(hdr))),
             ty::UnsafeBinder(ref bound_ty) => {
-                // FIXME(unsafe_binders): Make this print `unsafe<>` rather than `for<>`.
-                self.wrap_binder(bound_ty, |ty, cx| cx.pretty_print_type(*ty))?;
+                self.wrap_binder(bound_ty, WrapBinderMode::Unsafe, |ty, cx| {
+                    cx.pretty_print_type(*ty)
+                })?;
             }
             ty::Infer(infer_ty) => {
                 if self.should_print_verbose() {
@@ -1067,29 +1083,33 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             };
 
             if let Some(return_ty) = entry.return_ty {
-                self.wrap_binder(&bound_args_and_self_ty, |(args, _), cx| {
-                    define_scoped_cx!(cx);
-                    p!(write("{}", tcx.item_name(trait_def_id)));
-                    p!("(");
-
-                    for (idx, ty) in args.iter().enumerate() {
-                        if idx > 0 {
-                            p!(", ");
+                self.wrap_binder(
+                    &bound_args_and_self_ty,
+                    WrapBinderMode::ForAll,
+                    |(args, _), cx| {
+                        define_scoped_cx!(cx);
+                        p!(write("{}", tcx.item_name(trait_def_id)));
+                        p!("(");
+
+                        for (idx, ty) in args.iter().enumerate() {
+                            if idx > 0 {
+                                p!(", ");
+                            }
+                            p!(print(ty));
                         }
-                        p!(print(ty));
-                    }
 
-                    p!(")");
-                    if let Some(ty) = return_ty.skip_binder().as_type() {
-                        if !ty.is_unit() {
-                            p!(" -> ", print(return_ty));
+                        p!(")");
+                        if let Some(ty) = return_ty.skip_binder().as_type() {
+                            if !ty.is_unit() {
+                                p!(" -> ", print(return_ty));
+                            }
                         }
-                    }
-                    p!(write("{}", if paren_needed { ")" } else { "" }));
+                        p!(write("{}", if paren_needed { ")" } else { "" }));
 
-                    first = false;
-                    Ok(())
-                })?;
+                        first = false;
+                        Ok(())
+                    },
+                )?;
             } else {
                 // Otherwise, render this like a regular trait.
                 traits.insert(
@@ -1110,7 +1130,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         for (trait_pred, assoc_items) in traits {
             write!(self, "{}", if first { "" } else { " + " })?;
 
-            self.wrap_binder(&trait_pred, |trait_pred, cx| {
+            self.wrap_binder(&trait_pred, WrapBinderMode::ForAll, |trait_pred, cx| {
                 define_scoped_cx!(cx);
 
                 if trait_pred.polarity == ty::PredicatePolarity::Negative {
@@ -1302,7 +1322,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         let mut first = true;
 
         if let Some(bound_principal) = predicates.principal() {
-            self.wrap_binder(&bound_principal, |principal, cx| {
+            self.wrap_binder(&bound_principal, WrapBinderMode::ForAll, |principal, cx| {
                 define_scoped_cx!(cx);
                 p!(print_def_path(principal.def_id, &[]));
 
@@ -1516,10 +1536,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::ExprKind::Binop(op) => {
                 let (_, _, c1, c2) = expr.binop_args();
 
-                let precedence = |binop: crate::mir::BinOp| {
-                    use rustc_ast::util::parser::AssocOp;
-                    AssocOp::from_ast_binop(binop.to_hir_binop()).precedence()
-                };
+                let precedence = |binop: crate::mir::BinOp| binop.to_hir_binop().precedence();
                 let op_precedence = precedence(op);
                 let formatted_op = op.to_hir_binop().as_str();
                 let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) {
@@ -1930,7 +1947,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn);
 
         write!(self, "impl ")?;
-        self.wrap_binder(&sig, |sig, cx| {
+        self.wrap_binder(&sig, WrapBinderMode::ForAll, |sig, cx| {
             define_scoped_cx!(cx);
 
             p!(write("{kind}("));
@@ -2370,22 +2387,23 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         Ok(())
     }
 
-    fn in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
+    fn print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
     where
         T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
     {
-        self.pretty_in_binder(value)
+        self.pretty_print_in_binder(value)
     }
 
     fn wrap_binder<T, C: FnOnce(&T, &mut Self) -> Result<(), PrintError>>(
         &mut self,
         value: &ty::Binder<'tcx, T>,
+        mode: WrapBinderMode,
         f: C,
     ) -> Result<(), PrintError>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        self.pretty_wrap_binder(value, f)
+        self.pretty_wrap_binder(value, mode, f)
     }
 
     fn typed_value(
@@ -2635,6 +2653,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
     pub fn name_all_regions<T>(
         &mut self,
         value: &ty::Binder<'tcx, T>,
+        mode: WrapBinderMode,
     ) -> Result<(T, UnordMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -2708,9 +2727,13 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
         // anyways.
         let (new_value, map) = if self.should_print_verbose() {
             for var in value.bound_vars().iter() {
-                start_or_continue(self, "for<", ", ");
+                start_or_continue(self, mode.start_str(), ", ");
                 write!(self, "{var:?}")?;
             }
+            // Unconditionally render `unsafe<>`.
+            if value.bound_vars().is_empty() && mode == WrapBinderMode::Unsafe {
+                start_or_continue(self, mode.start_str(), "");
+            }
             start_or_continue(self, "", "> ");
             (value.clone().skip_binder(), UnordMap::default())
         } else {
@@ -2775,8 +2798,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
                     }
                 };
 
-                if !trim_path {
-                    start_or_continue(self, "for<", ", ");
+                // Unconditionally render `unsafe<>`.
+                if !trim_path || mode == WrapBinderMode::Unsafe {
+                    start_or_continue(self, mode.start_str(), ", ");
                     do_continue(self, name);
                 }
                 ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind })
@@ -2789,9 +2813,12 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             };
             let new_value = value.clone().skip_binder().fold_with(&mut folder);
             let region_map = folder.region_map;
-            if !trim_path {
-                start_or_continue(self, "", "> ");
+
+            if mode == WrapBinderMode::Unsafe && region_map.is_empty() {
+                start_or_continue(self, mode.start_str(), "");
             }
+            start_or_continue(self, "", "> ");
+
             (new_value, region_map)
         };
 
@@ -2800,12 +2827,15 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
         Ok((new_value, map))
     }
 
-    pub fn pretty_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), fmt::Error>
+    pub fn pretty_print_in_binder<T>(
+        &mut self,
+        value: &ty::Binder<'tcx, T>,
+    ) -> Result<(), fmt::Error>
     where
         T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
     {
         let old_region_index = self.region_index;
-        let (new_value, _) = self.name_all_regions(value)?;
+        let (new_value, _) = self.name_all_regions(value, WrapBinderMode::ForAll)?;
         new_value.print(self)?;
         self.region_index = old_region_index;
         self.binder_depth -= 1;
@@ -2815,13 +2845,14 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
     pub fn pretty_wrap_binder<T, C: FnOnce(&T, &mut Self) -> Result<(), fmt::Error>>(
         &mut self,
         value: &ty::Binder<'tcx, T>,
+        mode: WrapBinderMode,
         f: C,
     ) -> Result<(), fmt::Error>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         let old_region_index = self.region_index;
-        let (new_value, _) = self.name_all_regions(value)?;
+        let (new_value, _) = self.name_all_regions(value, mode)?;
         f(&new_value, self)?;
         self.region_index = old_region_index;
         self.binder_depth -= 1;
@@ -2880,7 +2911,7 @@ where
     T: Print<'tcx, P> + TypeFoldable<TyCtxt<'tcx>>,
 {
     fn print(&self, cx: &mut P) -> Result<(), PrintError> {
-        cx.in_binder(self)
+        cx.print_in_binder(self)
     }
 }
 
@@ -2898,12 +2929,15 @@ where
 /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
 /// the trait path. That is, it will print `Trait<U>` instead of
 /// `<T as Trait<U>>`.
-#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
 pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
 
 impl<'tcx> rustc_errors::IntoDiagArg for TraitRefPrintOnlyTraitPath<'tcx> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        self.to_string().into_diag_arg()
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
+        ty::tls::with(|tcx| {
+            let trait_ref = tcx.short_string(self, path);
+            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(trait_ref))
+        })
     }
 }
 
@@ -2915,12 +2949,15 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
 
 /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
 /// the trait path, and additionally tries to "sugar" `Fn(...)` trait bounds.
-#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
 pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>);
 
 impl<'tcx> rustc_errors::IntoDiagArg for TraitRefPrintSugared<'tcx> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        self.to_string().into_diag_arg()
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
+        ty::tls::with(|tcx| {
+            let trait_ref = tcx.short_string(self, path);
+            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(trait_ref))
+        })
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 839c1c346a4..b1dfcb80bde 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -51,22 +51,12 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> {
     ) -> RelateResult<'tcx, Self> {
         match (&*a, &*b) {
             (
-                &ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a },
-                &ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b },
+                &ty::PatternKind::Range { start: start_a, end: end_a },
+                &ty::PatternKind::Range { start: start_b, end: end_b },
             ) => {
-                // FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`).
-                let mut relate_opt_const = |a, b| match (a, b) {
-                    (None, None) => Ok(None),
-                    (Some(a), Some(b)) => relation.relate(a, b).map(Some),
-                    // FIXME(pattern_types): report a better error
-                    _ => Err(TypeError::Mismatch),
-                };
-                let start = relate_opt_const(start_a, start_b)?;
-                let end = relate_opt_const(end_a, end_b)?;
-                if inc_a != inc_b {
-                    todo!()
-                }
-                Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a }))
+                let start = relation.relate(start_a, start_b)?;
+                let end = relation.relate(end_a, end_b)?;
+                Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end }))
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs
new file mode 100644
index 00000000000..7f0d82d89fe
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs
@@ -0,0 +1,172 @@
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::unord::UnordSet;
+use rustc_hir::def_id::DefId;
+use rustc_span::Span;
+use smallvec::{SmallVec, smallvec};
+use tracing::{debug, instrument};
+
+use crate::ty::{self, Ty, TyCtxt};
+
+/// An additional filter to exclude well-known types from the ecosystem
+/// because their drops are trivial.
+/// This returns additional types to check if the drops are delegated to those.
+/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`.
+fn true_significant_drop_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
+    if let ty::Adt(def, args) = ty.kind() {
+        let mut did = def.did();
+        let mut name_rev = vec![];
+        loop {
+            let key = tcx.def_key(did);
+
+            match key.disambiguated_data.data {
+                rustc_hir::definitions::DefPathData::CrateRoot => {
+                    name_rev.push(tcx.crate_name(did.krate))
+                }
+                rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol),
+                _ => return None,
+            }
+            if let Some(parent) = key.parent {
+                did = DefId { krate: did.krate, index: parent };
+            } else {
+                break;
+            }
+        }
+        let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
+        debug!(?name_str);
+        match name_str[..] {
+            // These are the types from Rust core ecosystem
+            ["syn" | "proc_macro2", ..]
+            | ["core" | "std", "task", "LocalWaker" | "Waker"]
+            | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]),
+            // These are important types from Rust ecosystem
+            ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]),
+            ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
+                if let [ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            ["hashbrown", "raw", "RawDrain"] => {
+                if let [_, ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+/// Returns the list of types with a "potentially sigificant" that may be dropped
+/// by dropping a value of type `ty`.
+#[instrument(level = "trace", skip(tcx, typing_env))]
+pub fn extract_component_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    ty: Ty<'tcx>,
+    ty_seen: &mut UnordSet<Ty<'tcx>>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    // Droppiness does not depend on regions, so let us erase them.
+    let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+
+    let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty));
+    debug!(?ty, "components");
+    let mut out_tys = smallvec![];
+    for ty in tys {
+        if let Some(tys) = true_significant_drop_ty(tcx, ty) {
+            // Some types can be further opened up because the drop is simply delegated
+            for ty in tys {
+                if ty_seen.insert(ty) {
+                    out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen));
+                }
+            }
+        } else {
+            if ty_seen.insert(ty) {
+                out_tys.push(ty);
+            }
+        }
+    }
+    out_tys
+}
+
+#[instrument(level = "trace", skip(tcx, typing_env))]
+pub fn extract_component_with_significant_dtor<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default());
+    let mut deduplicate = FxHashSet::default();
+    tys.retain(|oty| deduplicate.insert(*oty));
+    tys.into_iter().collect()
+}
+
+/// Extract the span of the custom destructor of a type
+/// especially the span of the `impl Drop` header or its entire block
+/// when we are working with current local crate.
+#[instrument(level = "trace", skip(tcx))]
+pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
+    match ty.kind() {
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Error(_)
+        | ty::Str
+        | ty::Never
+        | ty::RawPtr(_, _)
+        | ty::Ref(_, _, _)
+        | ty::FnPtr(_, _)
+        | ty::Tuple(_)
+        | ty::Dynamic(_, _, _)
+        | ty::Alias(_, _)
+        | ty::Bound(_, _)
+        | ty::Pat(_, _)
+        | ty::Placeholder(_)
+        | ty::Infer(_)
+        | ty::Slice(_)
+        | ty::Array(_, _)
+        | ty::UnsafeBinder(_) => None,
+
+        ty::Adt(adt_def, _) => {
+            let did = adt_def.did();
+            let try_local_did_span = |did: DefId| {
+                if let Some(local) = did.as_local() {
+                    tcx.source_span(local)
+                } else {
+                    tcx.def_span(did)
+                }
+            };
+            let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
+                dtor.did
+            } else if let Some(dtor) = tcx.adt_async_destructor(did) {
+                dtor.future
+            } else {
+                return Some(try_local_did_span(did));
+            };
+            let def_key = tcx.def_key(dtor);
+            let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
+            let parent_did = DefId { index: parent_index, krate: dtor.krate };
+            Some(try_local_did_span(parent_did))
+        }
+        ty::Coroutine(did, _)
+        | ty::CoroutineWitness(did, _)
+        | ty::CoroutineClosure(did, _)
+        | ty::Closure(did, _)
+        | ty::FnDef(did, _)
+        | ty::Foreign(did) => Some(tcx.def_span(did)),
+        ty::Param(_) => None,
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index db9e9fbc643..6c62c04f42e 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -284,6 +284,7 @@ TrivialTypeTraversalImpls! {
     rustc_hir::def_id::LocalDefId,
     rustc_hir::HirId,
     rustc_hir::MatchSource,
+    rustc_hir::RangeEnd,
     rustc_span::Ident,
     rustc_span::Span,
     rustc_span::Symbol,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index d5617adf26b..ce563c59251 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -342,6 +342,7 @@ impl ParamConst {
         ParamConst::new(def.index, def.name)
     }
 
+    #[instrument(level = "debug")]
     pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
         let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
             // `ConstArgHasType` are never desugared to be higher ranked.
@@ -461,7 +462,7 @@ impl<'tcx> Ty<'tcx> {
 
     #[inline]
     pub fn new_param(tcx: TyCtxt<'tcx>, index: u32, name: Symbol) -> Ty<'tcx> {
-        tcx.mk_ty_from_kind(Param(ParamTy { index, name }))
+        Ty::new(tcx, Param(ParamTy { index, name }))
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index d4484a16fea..7d9c23c05f9 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -394,8 +394,10 @@ impl<'tcx> TypeckResults<'tcx> {
         matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
     }
 
-    pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
-        self.pat_binding_modes().get(id).copied().or_else(|| {
+    /// Returns the computed binding mode for a `PatKind::Binding` pattern
+    /// (after match ergonomics adjustments).
+    pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> BindingMode {
+        self.pat_binding_modes().get(id).copied().unwrap_or_else(|| {
             s.dcx().span_bug(sp, "missing binding mode");
         })
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4d917963cd6..237aa66f486 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -740,51 +740,37 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Return the set of types that should be taken into account when checking
-    /// trait bounds on a coroutine's internal state.
-    // FIXME(compiler-errors): We should remove this when the old solver goes away;
-    // and all other usages of this function should go through `bound_coroutine_hidden_types`
-    // instead.
-    pub fn coroutine_hidden_types(
-        self,
-        def_id: DefId,
-    ) -> impl Iterator<Item = ty::EarlyBinder<'tcx, Ty<'tcx>>> {
-        let coroutine_layout = self.mir_coroutine_witnesses(def_id);
-        coroutine_layout
-            .as_ref()
-            .map_or_else(|| [].iter(), |l| l.field_tys.iter())
-            .filter(|decl| !decl.ignore_for_traits)
-            .map(|decl| ty::EarlyBinder::bind(decl.ty))
-    }
-
-    /// Return the set of types that should be taken into account when checking
     /// trait bounds on a coroutine's internal state. This properly replaces
     /// `ReErased` with new existential bound lifetimes.
-    pub fn bound_coroutine_hidden_types(
+    pub fn coroutine_hidden_types(
         self,
         def_id: DefId,
-    ) -> impl Iterator<Item = ty::EarlyBinder<'tcx, ty::Binder<'tcx, Ty<'tcx>>>> {
+    ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>> {
         let coroutine_layout = self.mir_coroutine_witnesses(def_id);
-        coroutine_layout
-            .as_ref()
-            .map_or_else(|| [].iter(), |l| l.field_tys.iter())
-            .filter(|decl| !decl.ignore_for_traits)
-            .map(move |decl| {
-                let mut vars = vec![];
-                let ty = fold_regions(self, decl.ty, |re, debruijn| {
-                    assert_eq!(re, self.lifetimes.re_erased);
-                    let var = ty::BoundVar::from_usize(vars.len());
-                    vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
-                    ty::Region::new_bound(
-                        self,
-                        debruijn,
-                        ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
-                    )
-                });
-                ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
-                    ty,
-                    self.mk_bound_variable_kinds(&vars),
-                ))
-            })
+        let mut vars = vec![];
+        let bound_tys = self.mk_type_list_from_iter(
+            coroutine_layout
+                .as_ref()
+                .map_or_else(|| [].iter(), |l| l.field_tys.iter())
+                .filter(|decl| !decl.ignore_for_traits)
+                .map(|decl| {
+                    let ty = fold_regions(self, decl.ty, |re, debruijn| {
+                        assert_eq!(re, self.lifetimes.re_erased);
+                        let var = ty::BoundVar::from_usize(vars.len());
+                        vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
+                        ty::Region::new_bound(
+                            self,
+                            debruijn,
+                            ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
+                        )
+                    });
+                    ty
+                }),
+        );
+        ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
+            bound_tys,
+            self.mk_bound_variable_kinds(&vars),
+        ))
     }
 
     /// Expands the given impl trait type, stopping if the type is recursive.
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 3e8a3d1a289..a23316ae6fc 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -137,9 +137,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
 
             ty::Pat(ty, pat) => {
                 match *pat {
-                    ty::PatternKind::Range { start, end, include_end: _ } => {
-                        stack.extend(end.map(Into::into));
-                        stack.extend(start.map(Into::into));
+                    ty::PatternKind::Range { start, end } => {
+                        stack.push(end.into());
+                        stack.push(start.into());
                     }
                 }
                 stack.push(ty.into());