about summary refs log tree commit diff
path: root/compiler/rustc_middle
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle')
-rw-r--r--compiler/rustc_middle/messages.ftl3
-rw-r--r--compiler/rustc_middle/src/error.rs11
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs4
-rw-r--r--compiler/rustc_middle/src/hooks/mod.rs13
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs11
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs8
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs18
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs3
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs20
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs6
-rw-r--r--compiler/rustc_middle/src/traits/select.rs18
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs12
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs31
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/error.rs9
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs4
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs161
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs203
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs8
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/util.rs45
27 files changed, 237 insertions, 379 deletions
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 52c3212ab80..5dd85978f00 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -73,6 +73,9 @@ middle_drop_check_overflow =
 
 middle_erroneous_constant = erroneous constant encountered
 
+middle_failed_writing_file =
+    failed to write file {$path}: {$error}"
+
 middle_layout_references_error =
     the type has an unknown layout
 
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 5c2aa0005d4..6300d856393 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -1,5 +1,5 @@
-use std::fmt;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
+use std::{fmt, io};
 
 use rustc_errors::codes::*;
 use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage};
@@ -19,6 +19,13 @@ pub struct DropCheckOverflow<'tcx> {
 }
 
 #[derive(Diagnostic)]
+#[diag(middle_failed_writing_file)]
+pub struct FailedWritingFile<'a> {
+    pub path: &'a Path,
+    pub error: io::Error,
+}
+
+#[derive(Diagnostic)]
 #[diag(middle_opaque_hidden_type_mismatch)]
 pub struct OpaqueHiddenTypeMismatch<'tcx> {
     pub self_ty: Ty<'tcx>,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 007e6f46006..4900575c36e 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -947,7 +947,7 @@ impl<'hir> Map<'hir> {
             Node::Infer(i) => i.span,
             Node::LetStmt(local) => local.span,
             Node::Crate(item) => item.spans.inner_span,
-            Node::WhereBoundPredicate(pred) => pred.span,
+            Node::WherePredicate(pred) => pred.span,
             Node::ArrayLenInfer(inf) => inf.span,
             Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span,
             Node::Synthetic => unreachable!(),
@@ -1225,7 +1225,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
             format!("{id} (generic_param {})", path_str(param.def_id))
         }
         Node::Crate(..) => String::from("(root_crate)"),
-        Node::WhereBoundPredicate(_) => node_str("where bound predicate"),
+        Node::WherePredicate(_) => node_str("where predicate"),
         Node::ArrayLenInfer(_) => node_str("array len infer"),
         Node::Synthetic => unreachable!(),
         Node::Err(_) => node_str("error"),
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index 742797fdeef..92fa64b0987 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -108,6 +108,19 @@ declare_hooks! {
     /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
     /// can just link to the upstream crate and therefore don't need a mono item.
     hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
+
+    hook alloc_self_profile_query_strings() -> ();
+
+    /// Saves and writes the DepGraph to the file system.
+    ///
+    /// This function saves both the dep-graph and the query result cache,
+    /// and drops the result cache.
+    ///
+    /// This function should only run after all queries have completed.
+    /// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
+    hook save_dep_graph() -> ();
+
+    hook query_key_hash_verify_all() -> ();
 }
 
 #[cold]
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index b20673fe8da..7a91bfad483 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -68,6 +68,17 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family
+    /// trait, if it is defined.
+    pub fn async_fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> {
+        let items = self.lang_items();
+        match kind {
+            ty::ClosureKind::Fn => items.async_fn_trait(),
+            ty::ClosureKind::FnMut => items.async_fn_mut_trait(),
+            ty::ClosureKind::FnOnce => items.async_fn_once_trait(),
+        }
+    }
+
     /// Returns `true` if `id` is a `DefId` of [`Fn`], [`FnMut`] or [`FnOnce`] traits.
     pub fn is_fn_trait(self, id: DefId) -> bool {
         self.fn_trait_kind_from_def_id(id).is_some()
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index a51370369b8..7983329b0f7 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -105,8 +105,10 @@ impl<'tcx> ConstValue<'tcx> {
         typing_env: ty::TypingEnv<'tcx>,
         ty: Ty<'tcx>,
     ) -> Option<u128> {
-        let size =
-            tcx.layout_of(typing_env.with_reveal_all_normalized(tcx).as_query_input(ty)).ok()?.size;
+        let size = tcx
+            .layout_of(typing_env.with_post_analysis_normalized(tcx).as_query_input(ty))
+            .ok()?
+            .size;
         self.try_to_bits(size)
     }
 
@@ -376,7 +378,7 @@ impl<'tcx> Const<'tcx> {
     ) -> Option<u128> {
         let int = self.try_eval_scalar_int(tcx, typing_env)?;
         let size = tcx
-            .layout_of(typing_env.with_reveal_all_normalized(tcx).as_query_input(self.ty()))
+            .layout_of(typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty()))
             .ok()?
             .size;
         Some(int.to_bits(size))
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 11a4e7f89a7..33f9a2bdca6 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -155,22 +155,6 @@ impl Debug for CoverageKind {
     }
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct SourceRegion {
-    pub start_line: u32,
-    pub start_col: u32,
-    pub end_line: u32,
-    pub end_col: u32,
-}
-
-impl Debug for SourceRegion {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        let &Self { start_line, start_col, end_line, end_col } = self;
-        write!(fmt, "{start_line}:{start_col} - {end_line}:{end_col}")
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
 #[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
 pub enum Op {
@@ -232,7 +216,7 @@ impl MappingKind {
 #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Mapping {
     pub kind: MappingKind,
-    pub source_region: SourceRegion,
+    pub span: Span,
 }
 
 /// Stores per-function coverage information attached to a `mir::Body`,
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 6eeafe18b35..e540f0194ec 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -162,7 +162,7 @@ impl<'tcx> TyCtxt<'tcx> {
         // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
         // improve caching of queries.
         let inputs =
-            self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid));
+            self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
         if !span.is_dummy() {
             // The query doesn't know where it is being invoked, so we need to fix the span.
             self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
@@ -182,7 +182,7 @@ impl<'tcx> TyCtxt<'tcx> {
         // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
         // improve caching of queries.
         let inputs =
-            self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid));
+            self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
         debug!(?inputs);
         if !span.is_dummy() {
             // The query doesn't know where it is being invoked, so we need to fix the span.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index e2379f282ec..56340ff0095 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -629,8 +629,7 @@ impl<'tcx> Body<'tcx> {
     ) -> Option<(u128, &'a SwitchTargets)> {
         // There are two places here we need to evaluate a constant.
         let eval_mono_const = |constant: &ConstOperand<'tcx>| {
-            // FIXME(#132279): what is this, why are we using an empty environment with
-            // `RevealAll` here.
+            // FIXME(#132279): what is this, why are we using an empty environment here.
             let typing_env = ty::TypingEnv::fully_monomorphized();
             let mono_literal = instance.instantiate_mir_and_normalize_erasing_regions(
                 tcx,
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 2bfcd0a6227..ece468947c2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -603,8 +603,8 @@ fn write_function_coverage_info(
     for (id, expression) in expressions.iter_enumerated() {
         writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?;
     }
-    for coverage::Mapping { kind, source_region } in mappings {
-        writeln!(w, "{INDENT}coverage {kind:?} => {source_region:?};")?;
+    for coverage::Mapping { kind, span } in mappings {
+        writeln!(w, "{INDENT}coverage {kind:?} => {span:?};")?;
     }
     writeln!(w)?;
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 76338be33aa..0f2a6d598a0 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1373,18 +1373,20 @@ rustc_queries! {
     /// Gets the ParameterEnvironment for a given item; this environment
     /// will be in "user-facing" mode, meaning that it is suitable for
     /// type-checking etc, and it does not normalize specializable
-    /// associated types. This is almost always what you want,
-    /// unless you are doing MIR optimizations, in which case you
-    /// might want to use `reveal_all()` method to change modes.
+    /// associated types.
+    ///
+    /// You should almost certainly not use this. If you already have an InferCtxt, then
+    /// you should also probably have a `ParamEnv` from when it was built. If you don't,
+    /// then you should take a `TypingEnv` to ensure that you handle opaque types correctly.
     query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
         desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
         feedable
     }
 
-    /// Like `param_env`, but returns the `ParamEnv` in `Reveal::All` mode.
-    /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`,
-    /// as this method is more efficient.
-    query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> {
+    /// Like `param_env`, but returns the `ParamEnv` after all opaque types have been
+    /// replaced with their hidden type. This is used in the old trait solver
+    /// when in `PostAnalysis` mode and should not be called directly.
+    query param_env_normalized_for_post_analysis(def_id: DefId) -> ty::ParamEnv<'tcx> {
         desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
     }
 
@@ -1465,13 +1467,13 @@ rustc_queries! {
     /// *IMPORTANT*: *DO NOT* run this query before promoted MIR body is constructed,
     /// because this query partially depends on that query.
     /// Otherwise, there is a risk of query cycles.
-    query list_significant_drop_tys(ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx ty::List<Ty<'tcx>> {
+    query list_significant_drop_tys(ty: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> &'tcx ty::List<Ty<'tcx>> {
         desc { |tcx| "computing when `{}` has a significant destructor", ty.value }
         cache_on_disk_if { false }
     }
 
     /// Computes the layout of a type. Note that this implicitly
-    /// executes in "reveal all" mode, and will normalize the input type.
+    /// executes in `TypingMode::PostAnalysis`, and will normalize the input type.
     query layout_of(
         key: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>
     ) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 09731d565b6..d61ef7641ee 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -23,7 +23,7 @@ use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_span::symbol::Symbol;
 use rustc_span::{DUMMY_SP, Span};
 // FIXME: Remove this import and import via `solve::`
-pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal};
+pub use rustc_type_ir::solve::BuiltinImplSource;
 use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 
@@ -551,7 +551,7 @@ pub struct DerivedCause<'tcx> {
     pub parent_code: InternedObligationCauseCode<'tcx>,
 }
 
-#[derive(Clone, Debug, TypeVisitable)]
+#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
 pub enum SelectionError<'tcx> {
     /// The trait is not implemented.
     Unimplemented,
@@ -573,7 +573,7 @@ pub enum SelectionError<'tcx> {
     ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> },
 }
 
-#[derive(Clone, Debug, TypeVisitable)]
+#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
 pub struct SignatureMismatchData<'tcx> {
     pub found_trait_ref: ty::TraitRef<'tcx>,
     pub expected_trait_ref: ty::TraitRef<'tcx>,
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 05556ae38a8..094fc62afbb 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -11,20 +11,10 @@ use self::EvaluationResult::*;
 use super::{SelectionError, SelectionResult};
 use crate::ty;
 
-pub type SelectionCache<'tcx> = Cache<
-    // This cache does not use `ParamEnvAnd` in its keys because `ParamEnv::and` can replace
-    // caller bounds with an empty list if the `TraitPredicate` looks global, which may happen
-    // after erasing lifetimes from the predicate.
-    (ty::ParamEnv<'tcx>, ty::TraitPredicate<'tcx>),
-    SelectionResult<'tcx, SelectionCandidate<'tcx>>,
->;
-
-pub type EvaluationCache<'tcx> = Cache<
-    // See above: this cache does not use `ParamEnvAnd` in its keys due to sometimes incorrectly
-    // caching with the wrong `ParamEnv`.
-    (ty::ParamEnv<'tcx>, ty::PolyTraitPredicate<'tcx>),
-    EvaluationResult,
->;
+pub type SelectionCache<'tcx, ENV> =
+    Cache<(ENV, ty::TraitPredicate<'tcx>), SelectionResult<'tcx, SelectionCandidate<'tcx>>>;
+
+pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>), EvaluationResult>;
 
 /// The selection process begins by considering all impls, where
 /// clauses, and so forth that might resolve an obligation. Sometimes
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 79d56702be2..447cbc8932e 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -18,6 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::DataTypeKind;
 use rustc_span::symbol::sym;
+use rustc_type_ir::solve::AdtDestructorKind;
 use tracing::{debug, info, trace};
 
 use super::{
@@ -232,6 +233,13 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
     fn is_fundamental(self) -> bool {
         self.is_fundamental()
     }
+
+    fn destructor(self, tcx: TyCtxt<'tcx>) -> Option<AdtDestructorKind> {
+        Some(match self.destructor(tcx)?.constness {
+            hir::Constness::Const => AdtDestructorKind::Const,
+            hir::Constness::NotConst => AdtDestructorKind::NotConst,
+        })
+    }
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)]
@@ -402,10 +410,6 @@ impl<'tcx> AdtDef<'tcx> {
         self.destructor(tcx).is_some()
     }
 
-    pub fn has_non_const_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
-        matches!(self.destructor(tcx), Some(Destructor { constness: hir::Constness::NotConst, .. }))
-    }
-
     /// Asserts this is a struct or union and returns its unique variant.
     pub fn non_enum_variant(self) -> &'tcx VariantDef {
         assert!(self.is_struct() || self.is_union());
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 47a84d4b258..aba5719138c 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -174,7 +174,6 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for CtfeProvenance {
 impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> {
     fn encode(&self, e: &mut E) {
         self.caller_bounds().encode(e);
-        self.reveal().encode(e);
     }
 }
 
@@ -310,8 +309,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx>
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::ParamEnv<'tcx> {
     fn decode(d: &mut D) -> Self {
         let caller_bounds = Decodable::decode(d);
-        let reveal = Decodable::decode(d);
-        ty::ParamEnv::new(caller_bounds, reveal)
+        ty::ParamEnv::new(caller_bounds)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index d853edb34c9..d27205e26ab 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -151,10 +151,6 @@ impl<'tcx> Const<'tcx> {
 }
 
 impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
-    fn try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option<u64> {
-        self.try_to_target_usize(interner)
-    }
-
     fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
         Const::new_infer(tcx, infer)
     }
@@ -336,7 +332,7 @@ impl<'tcx> Const<'tcx> {
     pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
         let (scalar, ty) = self.try_to_scalar()?;
         let scalar = scalar.try_to_scalar_int().ok()?;
-        let input = typing_env.with_reveal_all_normalized(tcx).as_query_input(ty);
+        let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(ty);
         let size = tcx.layout_of(input).ok()?.size;
         Some(scalar.to_bits(size))
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 55c29825fbc..2c867e6b8ca 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -4,7 +4,7 @@
 
 pub mod tls;
 
-use std::assert_matches::assert_matches;
+use std::assert_matches::{assert_matches, debug_assert_matches};
 use std::borrow::Borrow;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
@@ -377,10 +377,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     }
 
     fn impl_is_const(self, def_id: DefId) -> bool {
+        debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true });
         self.is_conditionally_const(def_id)
     }
 
     fn fn_is_const(self, def_id: DefId) -> bool {
+        debug_assert_matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
+        self.is_conditionally_const(def_id)
+    }
+
+    fn alias_has_const_conditions(self, def_id: DefId) -> bool {
+        debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy);
         self.is_conditionally_const(def_id)
     }
 
@@ -663,6 +670,7 @@ bidirectional_lang_item_map! {
     CoroutineYield,
     Destruct,
     DiscriminantKind,
+    Drop,
     DynMetadata,
     Fn,
     FnMut,
@@ -1318,12 +1326,12 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Caches the results of trait selection. This cache is used
     /// for things that do not have to do with the parameters in scope.
-    pub selection_cache: traits::SelectionCache<'tcx>,
+    pub selection_cache: traits::SelectionCache<'tcx, ty::TypingEnv<'tcx>>,
 
     /// Caches the results of trait evaluation. This cache is used
     /// for things that do not have to do with the parameters in scope.
     /// Merge this with `selection_cache`?
-    pub evaluation_cache: traits::EvaluationCache<'tcx>,
+    pub evaluation_cache: traits::EvaluationCache<'tcx, ty::TypingEnv<'tcx>>,
 
     /// Caches the results of goal evaluation in the new solver.
     pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
@@ -1363,8 +1371,17 @@ impl<'tcx> GlobalCtxt<'tcx> {
         tls::enter_context(&icx, || f(icx.tcx))
     }
 
-    pub fn finish(&self) -> FileEncodeResult {
-        self.dep_graph.finish_encoding()
+    pub fn finish(&'tcx self) {
+        // We assume that no queries are run past here. If there are new queries
+        // after this point, they'll show up as "<unknown>" in self-profiling data.
+        self.enter(|tcx| tcx.alloc_self_profile_query_strings());
+
+        self.enter(|tcx| tcx.save_dep_graph());
+        self.enter(|tcx| tcx.query_key_hash_verify_all());
+
+        if let Err((path, error)) = self.dep_graph.finish_encoding() {
+            self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error });
+        }
     }
 }
 
@@ -1558,10 +1575,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
-        self.sess.consider_optimizing(|| self.crate_name(LOCAL_CRATE), msg)
-    }
-
     /// Obtain all lang items of this crate and all dependencies (recursively)
     pub fn lang_items(self) -> &'tcx rustc_hir::lang_items::LanguageItems {
         self.get_lang_items(())
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 84f52bfe48f..fd807882e0f 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicate};
+use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicateKind};
 use rustc_span::{BytePos, Span};
 use rustc_type_ir::TyKind::*;
 
@@ -180,7 +180,7 @@ fn suggest_changing_unsized_bound(
     // First look at the `where` clause because we can have `where T: ?Sized`,
     // then look at params.
     for (where_pos, predicate) in generics.predicates.iter().enumerate() {
-        let WherePredicate::BoundPredicate(predicate) = predicate else {
+        let WherePredicateKind::BoundPredicate(predicate) = predicate.kind else {
             continue;
         };
         if !predicate.is_param_bound(param.def_id.to_def_id()) {
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 43d243b0584..4a82af32559 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -58,12 +58,9 @@ impl<'tcx> TypeError<'tcx> {
                 pluralize!(values.found)
             )
             .into(),
-            TypeError::FixedArraySize(values) => format!(
-                "expected an array with a fixed size of {} element{}, found one with {} element{}",
-                values.expected,
-                pluralize!(values.expected),
-                values.found,
-                pluralize!(values.found)
+            TypeError::ArraySize(values) => format!(
+                "expected an array with a size of {}, found one with a size of {}",
+                values.expected, values.found,
             )
             .into(),
             TypeError::ArgCount => "incorrect number of function parameters".into(),
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index dab3e18de33..73fd8aa5b6c 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -504,8 +504,8 @@ impl<'tcx> Instance<'tcx> {
     /// ```
     ///
     /// trying to resolve `Debug::fmt` applied to `T` will yield `Ok(None)`, because we do not
-    /// know what code ought to run. (Note that this setting is also affected by the
-    /// `RevealMode` in the parameter environment.)
+    /// know what code ought to run. This setting is also affected by the current `TypingMode`
+    /// of the environment.
     ///
     /// Presuming that coherence and type-check have succeeded, if this method is invoked
     /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index fc29b438d3a..01ad76aedc3 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -682,14 +682,14 @@ pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasTypingEnv<
 /// Blanket extension trait for contexts that can compute layouts of types.
 pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
     /// Computes the layout of a type. Note that this implicitly
-    /// executes in "reveal all" mode, and will normalize the input type.
+    /// executes in `TypingMode::PostAnalysis`, and will normalize the input type.
     #[inline]
     fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
         self.spanned_layout_of(ty, DUMMY_SP)
     }
 
     /// Computes the layout of a type, at `span`. Note that this implicitly
-    /// executes in "reveal all" mode, and will normalize the input type.
+    /// executes in `TypingMode::PostAnalysis`, and will normalize the input type.
     // FIXME(eddyb) avoid passing information like this, and instead add more
     // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 2bc055453a4..c7a2223ecd7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -32,11 +32,10 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
-use rustc_hir::LangItem;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
+use rustc_hir::{LangItem, Safety};
 use rustc_index::IndexVec;
 use rustc_macros::{
     Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
@@ -104,7 +103,6 @@ use crate::metadata::ModChild;
 use crate::middle::privacy::EffectiveVisibilities;
 use crate::mir::{Body, CoroutineLayout};
 use crate::query::{IntoQueryParam, Providers};
-use crate::traits::{self, Reveal};
 use crate::ty;
 pub use crate::ty::diagnostics::*;
 use crate::ty::fast_reject::SimplifiedType;
@@ -960,147 +958,50 @@ impl<'tcx> rustc_type_ir::visit::Flags for Clauses<'tcx> {
 /// [dev guide chapter][param_env_guide] for more information.
 ///
 /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
-#[derive(Copy, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+#[derive(HashStable, TypeVisitable, TypeFoldable)]
 pub struct ParamEnv<'tcx> {
-    /// This packs both caller bounds and the reveal enum into one pointer.
-    ///
     /// Caller bounds are `Obligation`s that the caller must satisfy. This is
     /// basically the set of bounds on the in-scope type parameters, translated
     /// into `Obligation`s, and elaborated and normalized.
     ///
     /// Use the `caller_bounds()` method to access.
-    ///
-    /// Typically, this is `Reveal::UserFacing`, but during codegen we
-    /// want `Reveal::All`.
-    ///
-    /// Note: This is packed, use the reveal() method to access it.
-    packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>,
+    caller_bounds: Clauses<'tcx>,
 }
 
 impl<'tcx> rustc_type_ir::inherent::ParamEnv<TyCtxt<'tcx>> for ParamEnv<'tcx> {
-    fn reveal(self) -> Reveal {
-        self.reveal()
-    }
-
     fn caller_bounds(self) -> impl IntoIterator<Item = ty::Clause<'tcx>> {
         self.caller_bounds()
     }
 }
 
-#[derive(Copy, Clone)]
-struct ParamTag {
-    reveal: traits::Reveal,
-}
-
-rustc_data_structures::impl_tag! {
-    impl Tag for ParamTag;
-    ParamTag { reveal: traits::Reveal::UserFacing },
-    ParamTag { reveal: traits::Reveal::All },
-}
-
-impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("ParamEnv")
-            .field("caller_bounds", &self.caller_bounds())
-            .field("reveal", &self.reveal())
-            .finish()
-    }
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        self.caller_bounds().hash_stable(hcx, hasher);
-        self.reveal().hash_stable(hcx, hasher);
-    }
-}
-
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
-    fn try_fold_with<F: ty::fold::FallibleTypeFolder<TyCtxt<'tcx>>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(ParamEnv::new(
-            self.caller_bounds().try_fold_with(folder)?,
-            self.reveal().try_fold_with(folder)?,
-        ))
-    }
-}
-
-impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
-    fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
-        try_visit!(self.caller_bounds().visit_with(visitor));
-        self.reveal().visit_with(visitor)
-    }
-}
-
 impl<'tcx> ParamEnv<'tcx> {
-    /// Construct a trait environment suitable for contexts where
-    /// there are no where-clauses in scope. Hidden types (like `impl
-    /// Trait`) are left hidden. In majority of cases it is incorrect
+    /// Construct a trait environment suitable for contexts where there are
+    /// no where-clauses in scope. In the majority of cases it is incorrect
     /// to use an empty environment. See the [dev guide section][param_env_guide]
     /// for information on what a `ParamEnv` is and how to acquire one.
     ///
     /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
     #[inline]
     pub fn empty() -> Self {
-        Self::new(ListWithCachedTypeInfo::empty(), Reveal::UserFacing)
+        Self::new(ListWithCachedTypeInfo::empty())
     }
 
     #[inline]
     pub fn caller_bounds(self) -> Clauses<'tcx> {
-        self.packed.pointer()
-    }
-
-    #[inline]
-    pub fn reveal(self) -> traits::Reveal {
-        self.packed.tag().reveal
-    }
-
-    /// Construct a trait environment with no where-clauses in scope
-    /// where the values of all `impl Trait` and other hidden types
-    /// are revealed. This is suitable for monomorphized, post-typeck
-    /// environments like codegen or doing optimizations.
-    ///
-    /// N.B., if you want to have predicates in scope, use `ParamEnv::new`,
-    /// or invoke `param_env.with_reveal_all()`.
-    #[inline]
-    pub fn reveal_all() -> Self {
-        Self::new(ListWithCachedTypeInfo::empty(), Reveal::All)
+        self.caller_bounds
     }
 
     /// Construct a trait environment with the given set of predicates.
     #[inline]
-    pub fn new(caller_bounds: Clauses<'tcx>, reveal: Reveal) -> Self {
-        ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
-    }
-
-    /// Returns a new parameter environment with the same clauses, but
-    /// which "reveals" the true results of projections in all cases
-    /// (even for associated types that are specializable). This is
-    /// the desired behavior during codegen and certain other special
-    /// contexts; normally though we want to use `Reveal::UserFacing`,
-    /// which is the default.
-    /// All opaque types in the caller_bounds of the `ParamEnv`
-    /// will be normalized to their underlying types.
-    /// See PR #65989 and issue #65918 for more details
-    pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
-        if self.packed.tag().reveal == traits::Reveal::All {
-            return self;
-        }
-
-        // No need to reveal opaques with the new solver enabled,
-        // since we have lazy norm.
-        if tcx.next_trait_solver_globally() {
-            return ParamEnv::new(self.caller_bounds(), Reveal::All);
-        }
-
-        ParamEnv::new(tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), Reveal::All)
+    pub fn new(caller_bounds: Clauses<'tcx>) -> Self {
+        ParamEnv { caller_bounds }
     }
 
     /// Returns this same environment but with no caller bounds.
     #[inline]
     pub fn without_caller_bounds(self) -> Self {
-        Self::new(ListWithCachedTypeInfo::empty(), self.reveal())
+        Self::new(ListWithCachedTypeInfo::empty())
     }
 
     /// Creates a pair of param-env and value for use in queries.
@@ -1148,7 +1049,7 @@ impl<'tcx> TypingEnv<'tcx> {
     /// use `TypingMode::PostAnalysis`, they may still have where-clauses
     /// in scope.
     pub fn fully_monomorphized() -> TypingEnv<'tcx> {
-        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::reveal_all() }
+        TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::empty() }
     }
 
     /// Create a typing environment for use during analysis outside of a body.
@@ -1166,15 +1067,25 @@ impl<'tcx> TypingEnv<'tcx> {
     pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> {
         TypingEnv {
             typing_mode: TypingMode::PostAnalysis,
-            param_env: tcx.param_env_reveal_all_normalized(def_id),
+            param_env: tcx.param_env_normalized_for_post_analysis(def_id),
         }
     }
 
     /// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all
     /// opaque types in the `param_env`.
-    pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
-        let TypingEnv { typing_mode: _, param_env } = self;
-        let param_env = param_env.with_reveal_all_normalized(tcx);
+    pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
+        let TypingEnv { typing_mode, param_env } = self;
+        if let TypingMode::PostAnalysis = typing_mode {
+            return self;
+        }
+
+        // No need to reveal opaques with the new solver enabled,
+        // since we have lazy norm.
+        let param_env = if tcx.next_trait_solver_globally() {
+            ParamEnv::new(param_env.caller_bounds())
+        } else {
+            ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
+        };
         TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env }
     }
 
@@ -1365,6 +1276,11 @@ impl VariantDef {
     pub fn tail(&self) -> &FieldDef {
         self.tail_opt().expect("expected unsized ADT to have a tail field")
     }
+
+    /// Returns whether this variant has unsafe fields.
+    pub fn has_unsafe_fields(&self) -> bool {
+        self.fields.iter().any(|x| x.safety == Safety::Unsafe)
+    }
 }
 
 impl PartialEq for VariantDef {
@@ -1447,6 +1363,7 @@ pub struct FieldDef {
     pub did: DefId,
     pub name: Symbol,
     pub vis: Visibility<DefId>,
+    pub safety: hir::Safety,
 }
 
 impl PartialEq for FieldDef {
@@ -1459,15 +1376,16 @@ impl PartialEq for FieldDef {
         // of `FieldDef` changes, a compile-error will be produced, reminding
         // us to revisit this assumption.
 
-        let Self { did: lhs_did, name: _, vis: _ } = &self;
+        let Self { did: lhs_did, name: _, vis: _, safety: _ } = &self;
 
-        let Self { did: rhs_did, name: _, vis: _ } = other;
+        let Self { did: rhs_did, name: _, vis: _, safety: _ } = other;
 
         let res = lhs_did == rhs_did;
 
         // Double check that implicit assumption detailed above.
         if cfg!(debug_assertions) && res {
-            let deep = self.name == other.name && self.vis == other.vis;
+            let deep =
+                self.name == other.name && self.vis == other.vis && self.safety == other.safety;
             assert!(deep, "FieldDef for the same def-id has differing data");
         }
 
@@ -1487,7 +1405,7 @@ impl Hash for FieldDef {
         // of `FieldDef` changes, a compile-error will be produced, reminding
         // us to revisit this assumption.
 
-        let Self { did, name: _, vis: _ } = &self;
+        let Self { did, name: _, vis: _, safety: _ } = &self;
 
         did.hash(s)
     }
@@ -1640,10 +1558,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let is_box = self.is_lang_item(did.to_def_id(), LangItem::OwnedBox);
 
         // This is here instead of layout because the choice must make it into metadata.
-        if is_box
-            || !self
-                .consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did)))
-        {
+        if is_box {
             flags.insert(ReprFlags::IS_LINEAR);
         }
 
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 7c280bc8b49..f7322217aa3 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -86,6 +86,7 @@ trivially_parameterized_over_tcx! {
     rustc_attr::Stability,
     rustc_hir::Constness,
     rustc_hir::Defaultness,
+    rustc_hir::Safety,
     rustc_hir::CoroutineKind,
     rustc_hir::IsAsync,
     rustc_hir::LangItem,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 039c988f5c9..cd4123f0a3f 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -16,8 +16,8 @@ use rustc_hir::definitions::{DefKey, DefPathDataName};
 use rustc_macros::{Lift, extension};
 use rustc_session::Limit;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
-use rustc_span::FileNameDisplayPreference;
 use rustc_span::symbol::{Ident, Symbol, kw};
+use rustc_span::{FileNameDisplayPreference, sym};
 use rustc_type_ir::{Upcast as _, elaborate};
 use smallvec::SmallVec;
 
@@ -26,8 +26,8 @@ use super::*;
 use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::query::{IntoQueryParam, Providers};
 use crate::ty::{
-    ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TypeFoldable,
-    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TraitPredicate,
+    TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 
 macro_rules! p {
@@ -993,10 +993,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
             match bound_predicate.skip_binder() {
                 ty::ClauseKind::Trait(pred) => {
-                    let trait_ref = bound_predicate.rebind(pred.trait_ref);
-
                     // Don't print `+ Sized`, but rather `+ ?Sized` if absent.
-                    if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
+                    if tcx.is_lang_item(pred.def_id(), LangItem::Sized) {
                         match pred.polarity {
                             ty::PredicatePolarity::Positive => {
                                 has_sized_bound = true;
@@ -1007,24 +1005,22 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     }
 
                     self.insert_trait_and_projection(
-                        trait_ref,
-                        pred.polarity,
+                        bound_predicate.rebind(pred),
                         None,
                         &mut traits,
                         &mut fn_traits,
                     );
                 }
                 ty::ClauseKind::Projection(pred) => {
-                    let proj_ref = bound_predicate.rebind(pred);
-                    let trait_ref = proj_ref.required_poly_trait_ref(tcx);
-
-                    // Projection type entry -- the def-id for naming, and the ty.
-                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
+                    let proj = bound_predicate.rebind(pred);
+                    let trait_ref = proj.map_bound(|proj| TraitPredicate {
+                        trait_ref: proj.projection_term.trait_ref(tcx),
+                        polarity: ty::PredicatePolarity::Positive,
+                    });
 
                     self.insert_trait_and_projection(
                         trait_ref,
-                        ty::PredicatePolarity::Positive,
-                        Some(proj_ty),
+                        Some((proj.projection_def_id(), proj.term())),
                         &mut traits,
                         &mut fn_traits,
                     );
@@ -1042,88 +1038,66 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
         let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound;
 
-        for (fn_once_trait_ref, entry) in fn_traits {
+        for ((bound_args, is_async), entry) in fn_traits {
             write!(self, "{}", if first { "" } else { " + " })?;
             write!(self, "{}", if paren_needed { "(" } else { "" })?;
 
-            self.wrap_binder(&fn_once_trait_ref, |trait_ref, cx| {
-                define_scoped_cx!(cx);
-                // Get the (single) generic ty (the args) of this FnOnce trait ref.
-                let generics = tcx.generics_of(trait_ref.def_id);
-                let own_args = generics.own_args_no_defaults(tcx, trait_ref.args);
-
-                match (entry.return_ty, own_args[0].expect_ty()) {
-                    // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
-                    // a return type.
-                    (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
-                        let name = if entry.fn_trait_ref.is_some() {
-                            "Fn"
-                        } else if entry.fn_mut_trait_ref.is_some() {
-                            "FnMut"
-                        } else {
-                            "FnOnce"
-                        };
-
-                        p!(write("{}(", name));
+            let trait_def_id = if is_async {
+                tcx.async_fn_trait_kind_to_def_id(entry.kind).expect("expected AsyncFn lang items")
+            } else {
+                tcx.fn_trait_kind_to_def_id(entry.kind).expect("expected Fn lang items")
+            };
 
-                        for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() {
-                            if idx > 0 {
-                                p!(", ");
-                            }
-                            p!(print(ty));
-                        }
+            if let Some(return_ty) = entry.return_ty {
+                self.wrap_binder(&bound_args, |args, cx| {
+                    define_scoped_cx!(cx);
+                    p!(write("{}", tcx.item_name(trait_def_id)));
+                    p!("(");
 
-                        p!(")");
-                        if let Some(ty) = return_ty.skip_binder().as_type() {
-                            if !ty.is_unit() {
-                                p!(" -> ", print(return_ty));
-                            }
+                    for (idx, ty) in args.iter().enumerate() {
+                        if idx > 0 {
+                            p!(", ");
                         }
-                        p!(write("{}", if paren_needed { ")" } else { "" }));
-
-                        first = false;
+                        p!(print(ty));
                     }
-                    // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
-                    // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
-                    _ => {
-                        if entry.has_fn_once {
-                            traits
-                                .entry((fn_once_trait_ref, ty::PredicatePolarity::Positive))
-                                .or_default()
-                                .extend(
-                                    // Group the return ty with its def id, if we had one.
-                                    entry.return_ty.map(|ty| {
-                                        (tcx.require_lang_item(LangItem::FnOnceOutput, None), ty)
-                                    }),
-                                );
-                        }
-                        if let Some(trait_ref) = entry.fn_mut_trait_ref {
-                            traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default();
-                        }
-                        if let Some(trait_ref) = entry.fn_trait_ref {
-                            traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default();
+
+                    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 { "" }));
 
-                Ok(())
-            })?;
+                    first = false;
+                    Ok(())
+                })?;
+            } else {
+                // Otherwise, render this like a regular trait.
+                traits.insert(
+                    bound_args.map_bound(|args| ty::TraitPredicate {
+                        polarity: ty::PredicatePolarity::Positive,
+                        trait_ref: ty::TraitRef::new(tcx, trait_def_id, [Ty::new_tup(tcx, args)]),
+                    }),
+                    FxIndexMap::default(),
+                );
+            }
         }
 
         // Print the rest of the trait types (that aren't Fn* family of traits)
-        for ((trait_ref, polarity), assoc_items) in traits {
+        for (trait_pred, assoc_items) in traits {
             write!(self, "{}", if first { "" } else { " + " })?;
 
-            self.wrap_binder(&trait_ref, |trait_ref, cx| {
+            self.wrap_binder(&trait_pred, |trait_pred, cx| {
                 define_scoped_cx!(cx);
 
-                if polarity == ty::PredicatePolarity::Negative {
+                if trait_pred.polarity == ty::PredicatePolarity::Negative {
                     p!("!");
                 }
-                p!(print(trait_ref.print_only_trait_name()));
+                p!(print(trait_pred.trait_ref.print_only_trait_name()));
 
-                let generics = tcx.generics_of(trait_ref.def_id);
-                let own_args = generics.own_args_no_defaults(tcx, trait_ref.args);
+                let generics = tcx.generics_of(trait_pred.def_id());
+                let own_args = generics.own_args_no_defaults(tcx, trait_pred.trait_ref.args);
 
                 if !own_args.is_empty() || !assoc_items.is_empty() {
                     let mut first = true;
@@ -1230,51 +1204,48 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
     /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
     fn insert_trait_and_projection(
         &mut self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        polarity: ty::PredicatePolarity,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
         traits: &mut FxIndexMap<
-            (ty::PolyTraitRef<'tcx>, ty::PredicatePolarity),
+            ty::PolyTraitPredicate<'tcx>,
             FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
         >,
-        fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+        fn_traits: &mut FxIndexMap<
+            (ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>, bool),
+            OpaqueFnEntry<'tcx>,
+        >,
     ) {
-        let trait_def_id = trait_ref.def_id();
-
-        // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
-        // super-trait ref and record it there.
-        // We skip negative Fn* bounds since they can't use parenthetical notation anyway.
-        if polarity == ty::PredicatePolarity::Positive
-            && let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait()
-        {
-            // If we have a FnOnce, then insert it into
-            if trait_def_id == fn_once_trait {
-                let entry = fn_traits.entry(trait_ref).or_default();
-                // Optionally insert the return_ty as well.
-                if let Some((_, ty)) = proj_ty {
-                    entry.return_ty = Some(ty);
-                }
-                entry.has_fn_once = true;
-                return;
-            } else if self.tcx().is_lang_item(trait_def_id, LangItem::FnMut) {
-                let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref)
-                    .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
-                    .unwrap();
+        let tcx = self.tcx();
+        let trait_def_id = trait_pred.def_id();
 
-                fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref);
-                return;
-            } else if self.tcx().is_lang_item(trait_def_id, LangItem::Fn) {
-                let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref)
-                    .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
-                    .unwrap();
+        let fn_trait_and_async = if let Some(kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) {
+            Some((kind, false))
+        } else if let Some(kind) = tcx.async_fn_trait_kind_from_def_id(trait_def_id) {
+            Some((kind, true))
+        } else {
+            None
+        };
 
-                fn_traits.entry(super_trait_ref).or_default().fn_trait_ref = Some(trait_ref);
-                return;
+        if trait_pred.polarity() == ty::PredicatePolarity::Positive
+            && let Some((kind, is_async)) = fn_trait_and_async
+            && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
+        {
+            let entry = fn_traits
+                .entry((trait_pred.rebind(types), is_async))
+                .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None });
+            if kind.extends(entry.kind) {
+                entry.kind = kind;
+            }
+            if let Some((proj_def_id, proj_ty)) = proj_ty
+                && tcx.item_name(proj_def_id) == sym::Output
+            {
+                entry.return_ty = Some(proj_ty);
             }
+            return;
         }
 
         // Otherwise, just group our traits and projection types.
-        traits.entry((trait_ref, polarity)).or_default().extend(proj_ty);
+        traits.entry(trait_pred).or_default().extend(proj_ty);
     }
 
     fn pretty_print_inherent_projection(
@@ -3189,10 +3160,10 @@ define_print_and_forward_display! {
 
     TraitRefPrintSugared<'tcx> {
         if !with_reduced_queries()
-            && let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id)
+            && cx.tcx().trait_def(self.0.def_id).paren_sugar
             && let ty::Tuple(args) = self.0.args.type_at(1).kind()
         {
-            p!(write("{}", kind.as_str()), "(");
+            p!(write("{}", cx.tcx().item_name(self.0.def_id)), "(");
             for (i, arg) in args.iter().enumerate() {
                 if i > 0 {
                     p!(", ");
@@ -3415,11 +3386,7 @@ pub fn provide(providers: &mut Providers) {
     *providers = Providers { trimmed_def_paths, ..*providers };
 }
 
-#[derive(Default)]
 pub struct OpaqueFnEntry<'tcx> {
-    // The trait ref is already stored as a key, so just track if we have it as a real predicate
-    has_fn_once: bool,
-    fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
-    fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+    kind: ty::ClosureKind,
     return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
 }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 504a3c8a6d8..afdec7a86d4 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -3,7 +3,6 @@ use std::iter;
 pub use rustc_type_ir::relate::*;
 
 use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
 use crate::ty::{self as ty, Ty, TyCtxt};
 
 pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
@@ -86,13 +85,10 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
         // in `a`.
         let mut a_v: Vec<_> = a.into_iter().collect();
         let mut b_v: Vec<_> = b.into_iter().collect();
-        // `skip_binder` here is okay because `stable_cmp` doesn't look at binders
-        a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
         a_v.dedup();
-        b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
         b_v.dedup();
         if a_v.len() != b_v.len() {
-            return Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b)));
+            return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
         }
 
         let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
@@ -112,7 +108,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
                     ty::ExistentialPredicate::AutoTrait(a),
                     ty::ExistentialPredicate::AutoTrait(b),
                 ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
-                _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))),
+                _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
             }
         });
         tcx.mk_poly_existential_predicates_from_iter(v)
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index e48fac6c7e8..0af0a5f170d 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -237,7 +237,6 @@ TrivialTypeTraversalImpls! {
     crate::mir::coverage::ConditionId,
     crate::mir::Local,
     crate::mir::Promoted,
-    crate::traits::Reveal,
     crate::ty::adjustment::AutoBorrowMutability,
     crate::ty::AdtKind,
     crate::ty::BoundRegion,
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 20c3f84bb4d..55a7a837b6d 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -423,8 +423,8 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn async_drop_glue_morphology(self, did: DefId) -> AsyncDropGlueMorphology {
         let ty: Ty<'tcx> = self.type_of(did).instantiate_identity();
 
-        // Async drop glue morphology is an internal detail, so reveal_all probably
-        // should be fine
+        // Async drop glue morphology is an internal detail, so
+        // using `TypingMode::PostAnalysis` probably should be fine.
         let typing_env = ty::TypingEnv::fully_monomorphized();
         if ty.needs_async_drop(self, typing_env) {
             AsyncDropGlueMorphology::Custom
@@ -1053,7 +1053,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
                     // This is because for default trait methods with RPITITs, we
                     // install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))`
                     // predicate, which would trivially cause a cycle when we do
-                    // anything that requires `ParamEnv::with_reveal_all_normalized`.
+                    // anything that requires `TypingEnv::with_post_analysis_normalized`.
                     term: projection_pred.term,
                 })
                 .upcast(self.tcx)
@@ -1672,45 +1672,6 @@ pub fn needs_drop_components_with_async<'tcx>(
     }
 }
 
-pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
-    match *ty.kind() {
-        ty::Bool
-        | ty::Char
-        | ty::Int(_)
-        | ty::Uint(_)
-        | ty::Float(_)
-        | ty::Infer(ty::IntVar(_))
-        | ty::Infer(ty::FloatVar(_))
-        | ty::Str
-        | ty::RawPtr(_, _)
-        | ty::Ref(..)
-        | ty::FnDef(..)
-        | ty::FnPtr(..)
-        | ty::Never
-        | ty::Foreign(_) => true,
-
-        ty::Alias(..)
-        | ty::Dynamic(..)
-        | ty::Error(_)
-        | ty::Bound(..)
-        | ty::Param(_)
-        | ty::Placeholder(_)
-        | ty::Infer(_) => false,
-
-        // Not trivial because they have components, and instead of looking inside,
-        // we'll just perform trait selection.
-        ty::Closure(..)
-        | ty::CoroutineClosure(..)
-        | ty::Coroutine(..)
-        | ty::CoroutineWitness(..)
-        | ty::Adt(..) => false,
-
-        ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => is_trivially_const_drop(ty),
-
-        ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)),
-    }
-}
-
 /// Does the equivalent of
 /// ```ignore (illustrative)
 /// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();