about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee <workingjubilee@gmail.com>2024-10-31 17:50:43 -0700
committerGitHub <noreply@github.com>2024-10-31 17:50:43 -0700
commitc57b351d38102ca83190deb03cf956a2fa488ff2 (patch)
treef8051219dd67caf9fe403dcaac7befa12c49f926
parent6da4221d96ce6c3b5319e39e6687b3cfe9649895 (diff)
parentdc750665ae84cdedfbae4d5b3c69f4d20faa14dc (diff)
downloadrust-c57b351d38102ca83190deb03cf956a2fa488ff2.tar.gz
rust-c57b351d38102ca83190deb03cf956a2fa488ff2.zip
Rollup merge of #132403 - lcnr:typing-mode, r=compiler-errors
continue `TypingMode` refactor

There are still quite a few places which (indirectly) rely on the `Reveal` of a `ParamEnv`, but we're slowly getting there

r? `@compiler-errors`
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs7
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs21
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs13
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs21
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs11
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs11
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs27
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs20
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs2
20 files changed, 155 insertions, 105 deletions
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 5210241d5e4..b6c227638a1 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -16,7 +16,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt, TypingMode};
+use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
 use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -589,7 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
                 // which path expressions are getting called on and which path expressions are only used
                 // as function pointers. This is required for correctness.
-                let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
+                let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
                 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
                 let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args);
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 56da6791847..dcdaafaecc2 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -32,14 +32,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
         let def_id = body.source.def_id().expect_local();
         let param_env = tcx.param_env(def_id);
-        Self::new_with_param_env(tcx, body, param_env)
-    }
 
-    pub fn new_with_param_env(
-        tcx: TyCtxt<'tcx>,
-        body: &'mir mir::Body<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Self {
         let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local());
         ConstCx { body, tcx, param_env, const_kind }
     }
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 3f977dc4b05..961a27ae9ba 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::CallSource;
 use rustc_middle::span_bug;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, TypingMode,
+    self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty,
     suggest_constraining_type_param,
 };
 use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind};
@@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     let obligation =
                         Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
 
-                    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
+                    let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
                     let mut selcx = SelectionContext::new(&infcx);
                     let implsrc = selcx.select(&obligation);
 
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index d81368e9fcc..9043bd3e28e 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -3,7 +3,7 @@ use rustc_errors::DiagCtxtHandle;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::at::ToTrace;
-use rustc_infer::traits::ObligationCause;
+use rustc_infer::traits::{ObligationCause, Reveal};
 use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
@@ -116,6 +116,7 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
 /// This test should be symmetric, as it is primarily about layout compatibility.
 pub(super) fn mir_assign_valid_types<'tcx>(
     tcx: TyCtxt<'tcx>,
+    typing_mode: TypingMode<'tcx>,
     param_env: ParamEnv<'tcx>,
     src: TyAndLayout<'tcx>,
     dest: TyAndLayout<'tcx>,
@@ -124,7 +125,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
     // all normal lifetimes are erased, higher-ranked types with their
     // late-bound lifetimes are still around and can lead to type
     // differences.
-    if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) {
+    if util::relate_types(tcx, typing_mode, param_env, Variance::Covariant, src.ty, dest.ty) {
         // Make sure the layout is equal, too -- just to be safe. Miri really
         // needs layout equality. For performance reason we skip this check when
         // the types are equal. Equal types *can* have different layouts when
@@ -144,6 +145,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
 #[cfg_attr(not(debug_assertions), inline(always))]
 pub(super) fn from_known_layout<'tcx>(
     tcx: TyCtxtAt<'tcx>,
+    typing_mode: TypingMode<'tcx>,
     param_env: ParamEnv<'tcx>,
     known_layout: Option<TyAndLayout<'tcx>>,
     compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
@@ -153,7 +155,13 @@ pub(super) fn from_known_layout<'tcx>(
         Some(known_layout) => {
             if cfg!(debug_assertions) {
                 let check_layout = compute()?;
-                if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
+                if !mir_assign_valid_types(
+                    tcx.tcx,
+                    typing_mode,
+                    param_env,
+                    check_layout,
+                    known_layout,
+                ) {
                     span_bug!(
                         tcx.span,
                         "expected type differs from actual type.\nexpected: {}\nactual: {}",
@@ -203,6 +211,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
+    pub fn typing_mode(&self) -> TypingMode<'tcx> {
+        debug_assert_eq!(self.param_env.reveal(), Reveal::All);
+        TypingMode::PostAnalysis
+    }
+
     /// Returns the span of the currently executed statement/terminator.
     /// This is the span typically used for error reporting.
     #[inline(always)]
@@ -327,7 +340,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return true;
         }
         // Slow path: spin up an inference context to check if these traits are sufficiently equal.
-        let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env));
+        let infcx = self.tcx.infer_ctxt().build(self.typing_mode());
         let ocx = ObligationCtxt::new(&infcx);
         let cause = ObligationCause::dummy_with_span(self.cur_span());
         // equate the two trait refs after normalization
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 43ae98e74b0..a130ae89bcb 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -773,6 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 )?;
             if !mir_assign_valid_types(
                 *self.tcx,
+                self.typing_mode(),
                 self.param_env,
                 self.layout_of(normalized_place_ty)?,
                 op.layout,
@@ -832,7 +833,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             })
         };
         let layout =
-            from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty).into())?;
+            from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
+                self.layout_of(ty).into()
+            })?;
         let imm = match val_val {
             mir::ConstValue::Indirect { alloc_id, offset } => {
                 // This is const data, no mutation allowed.
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 139a1db60e0..cc8d1db6cfb 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -540,6 +540,7 @@ where
                 )?;
             if !mir_assign_valid_types(
                 *self.tcx,
+                self.typing_mode(),
                 self.param_env,
                 self.layout_of(normalized_place_ty)?,
                 place.layout,
@@ -870,8 +871,13 @@ where
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
-        let layout_compat =
-            mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout());
+        let layout_compat = mir_assign_valid_types(
+            *self.tcx,
+            self.typing_mode(),
+            self.param_env,
+            src.layout(),
+            dest.layout(),
+        );
         if !allow_transmute && !layout_compat {
             span_bug!(
                 self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 3bc9f46aea0..50c0446b3cd 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -596,12 +596,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return interp_ok(layout);
         }
 
-        let layout = from_known_layout(self.tcx, self.param_env, layout, || {
-            let local_ty = frame.body.local_decls[local].ty;
-            let local_ty =
-                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
-            self.layout_of(local_ty).into()
-        })?;
+        let layout =
+            from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
+                let local_ty = frame.body.local_decls[local].ty;
+                let local_ty =
+                    self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
+                self.layout_of(local_ty).into()
+            })?;
 
         // Layouts of locals are requested a lot, so we cache them.
         state.layout.set(Some(layout));
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index 7af977bab4d..0cf27d30c36 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -8,24 +8,15 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance};
 use rustc_trait_selection::traits::ObligationCtxt;
 
-/// Returns whether the two types are equal up to subtyping.
-///
-/// This is used in case we don't know the expected subtyping direction
-/// and still want to check whether anything is broken.
-pub fn is_equal_up_to_subtyping<'tcx>(
+/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
+pub fn sub_types<'tcx>(
     tcx: TyCtxt<'tcx>,
+    typing_mode: TypingMode<'tcx>,
     param_env: ParamEnv<'tcx>,
     src: Ty<'tcx>,
     dest: Ty<'tcx>,
 ) -> bool {
-    // Fast path.
-    if src == dest {
-        return true;
-    }
-
-    // Check for subtyping in either direction.
-    relate_types(tcx, param_env, Variance::Covariant, src, dest)
-        || relate_types(tcx, param_env, Variance::Covariant, dest, src)
+    relate_types(tcx, typing_mode, param_env, Variance::Covariant, src, dest)
 }
 
 /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
@@ -35,6 +26,7 @@ pub fn is_equal_up_to_subtyping<'tcx>(
 /// because we want to check for type equality.
 pub fn relate_types<'tcx>(
     tcx: TyCtxt<'tcx>,
+    typing_mode: TypingMode<'tcx>,
     param_env: ParamEnv<'tcx>,
     variance: Variance,
     src: Ty<'tcx>,
@@ -45,8 +37,7 @@ pub fn relate_types<'tcx>(
     }
 
     let mut builder = tcx.infer_ctxt().ignoring_regions();
-    // FIXME(#132279): This should eventually use the already defined hidden types.
-    let infcx = builder.build(TypingMode::from_param_env(param_env));
+    let infcx = builder.build(typing_mode);
     let ocx = ObligationCtxt::new(&infcx);
     let cause = ObligationCause::dummy();
     let src = ocx.normalize(&cause, param_env, src);
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 66a1addfb52..25a9dbb2c11 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -8,7 +8,7 @@ mod type_name;
 
 pub use self::alignment::{is_disaligned, is_within_packed};
 pub use self::check_validity_requirement::check_validity_requirement;
-pub use self::compare_types::{is_equal_up_to_subtyping, relate_types};
+pub use self::compare_types::{relate_types, sub_types};
 pub use self::type_name::type_name;
 
 /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index cd148aef29b..978abab8b08 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -39,7 +39,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
 use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{
-    self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt,
+    self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingMode,
     UserTypeAnnotationIndex,
 };
 
@@ -452,6 +452,15 @@ impl<'tcx> Body<'tcx> {
         self.basic_blocks.as_mut()
     }
 
+    pub fn typing_mode(&self, _tcx: TyCtxt<'tcx>) -> TypingMode<'tcx> {
+        match self.phase {
+            // FIXME(#132279): the MIR is quite clearly inside of a body, so we
+            // should instead reveal opaques defined by that body here.
+            MirPhase::Built | MirPhase::Analysis(_) => TypingMode::non_body_analysis(),
+            MirPhase::Runtime(_) => TypingMode::PostAnalysis,
+        }
+    }
+
     #[inline]
     pub fn local_kind(&self, local: Local) -> LocalKind {
         let index = local.as_usize();
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index c610fac80f6..85beb6ef1e7 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -19,9 +19,8 @@ use smallvec::SmallVec;
 
 use super::{BasicBlock, Const, Local, UserTypeProjection};
 use crate::mir::coverage::CoverageKind;
-use crate::traits::Reveal;
 use crate::ty::adjustment::PointerCoercion;
-use crate::ty::{self, GenericArgsRef, List, Region, Ty, UserTypeAnnotationIndex};
+use crate::ty::{self, GenericArgsRef, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex};
 
 /// Represents the "flavors" of MIR.
 ///
@@ -102,10 +101,10 @@ impl MirPhase {
         }
     }
 
-    pub fn reveal(&self) -> Reveal {
-        match *self {
-            MirPhase::Built | MirPhase::Analysis(_) => Reveal::UserFacing,
-            MirPhase::Runtime(_) => Reveal::All,
+    pub fn param_env<'tcx>(&self, tcx: TyCtxt<'tcx>, body_def_id: DefId) -> ty::ParamEnv<'tcx> {
+        match self {
+            MirPhase::Built | MirPhase::Analysis(_) => tcx.param_env(body_def_id),
+            MirPhase::Runtime(_) => tcx.param_env_reveal_all_normalized(body_def_id),
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 42d6bdf6cee..404470db5c5 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -244,8 +244,13 @@ impl<'tcx> Inliner<'tcx> {
         // Normally, this shouldn't be required, but trait normalization failure can create a
         // validation ICE.
         let output_type = callee_body.return_ty();
-        if !util::relate_types(self.tcx, self.param_env, ty::Covariant, output_type, destination_ty)
-        {
+        if !util::sub_types(
+            self.tcx,
+            caller_body.typing_mode(self.tcx),
+            self.param_env,
+            output_type,
+            destination_ty,
+        ) {
             trace!(?output_type, ?destination_ty);
             return Err("failed to normalize return type");
         }
@@ -275,8 +280,13 @@ impl<'tcx> Inliner<'tcx> {
                 self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
             {
                 let input_type = callee_body.local_decls[input].ty;
-                if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty)
-                {
+                if !util::sub_types(
+                    self.tcx,
+                    caller_body.typing_mode(self.tcx),
+                    self.param_env,
+                    input_type,
+                    arg_ty,
+                ) {
                     trace!(?arg_ty, ?input_type);
                     return Err("failed to normalize tuple argument type");
                 }
@@ -285,8 +295,13 @@ impl<'tcx> Inliner<'tcx> {
             for (arg, input) in args.iter().zip(callee_body.args_iter()) {
                 let input_type = callee_body.local_decls[input].ty;
                 let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx);
-                if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty)
-                {
+                if !util::sub_types(
+                    self.tcx,
+                    caller_body.typing_mode(self.tcx),
+                    self.param_env,
+                    input_type,
+                    arg_ty,
+                ) {
                     trace!(?arg_ty, ?input_type);
                     return Err("failed to normalize argument type");
                 }
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 77356723c46..8109a9b8ba0 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -5,14 +5,14 @@ use rustc_hir::LangItem;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::{Obligation, ObligationCause, Reveal};
+use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{
     self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
-    TypingMode, Variance,
+    Variance,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{FIRST_VARIANT, Size};
@@ -20,7 +20,7 @@ use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_type_ir::Upcast;
 
-use crate::util::{is_within_packed, relate_types};
+use crate::util::{self, is_within_packed};
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum EdgeKind {
@@ -50,11 +50,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
         }
         let def_id = body.source.def_id();
         let mir_phase = self.mir_phase;
-        let param_env = match mir_phase.reveal() {
-            Reveal::UserFacing => tcx.param_env(def_id),
-            Reveal::All => tcx.param_env_reveal_all_normalized(def_id),
-        };
-
+        let param_env = mir_phase.param_env(tcx, def_id);
         let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) {
             // In this case `AbortUnwindingCalls` haven't yet been executed.
             true
@@ -587,7 +583,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             Variance::Covariant
         };
 
-        crate::util::relate_types(self.tcx, self.param_env, variance, src, dest)
+        crate::util::relate_types(
+            self.tcx,
+            self.body.typing_mode(self.tcx),
+            self.param_env,
+            variance,
+            src,
+            dest,
+        )
     }
 
     /// Check that the given predicate definitely holds in the param-env of this MIR body.
@@ -606,7 +609,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             return true;
         }
 
-        let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env));
+        let infcx = self.tcx.infer_ctxt().build(self.body.typing_mode(self.tcx));
         let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(Obligation::new(
             self.tcx,
@@ -798,10 +801,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 }
             }
             ProjectionElem::Subtype(ty) => {
-                if !relate_types(
+                if !util::sub_types(
                     self.tcx,
+                    self.body.typing_mode(self.tcx),
                     self.param_env,
-                    Variance::Covariant,
                     ty,
                     place_ref.ty(&self.body.local_decls, self.tcx).ty,
                 ) {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 1c84f2171bc..436c0fabd29 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -411,7 +411,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
 
     let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal());
-    if !normalize::needs_normalization(&elaborated_env, unnormalized_env.reveal()) {
+    if !elaborated_env.has_aliases() {
         return elaborated_env;
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 12e00ec79ac..954dfe93387 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -1,15 +1,16 @@
 //! Deeply normalize types using the old trait solver.
 
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_infer::infer::InferOk;
 use rustc_infer::infer::at::At;
+use rustc_infer::infer::{InferCtxt, InferOk};
 use rustc_infer::traits::{
     FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
 };
 use rustc_macros::extension;
-use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal};
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt,
+    TypingMode,
 };
 use tracing::{debug, instrument};
 
@@ -109,16 +110,19 @@ where
 }
 
 pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
+    infcx: &InferCtxt<'tcx>,
+    param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
     value: &T,
-    reveal: Reveal,
 ) -> bool {
     let mut flags = ty::TypeFlags::HAS_ALIAS;
 
     // Opaques are treated as rigid with `Reveal::UserFacing`,
     // so we can ignore those.
-    match reveal {
-        Reveal::UserFacing => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
-        Reveal::All => {}
+    match infcx.typing_mode(param_env_for_debug_assertion) {
+        TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
+            flags.remove(ty::TypeFlags::HAS_TY_OPAQUE)
+        }
+        TypingMode::PostAnalysis => {}
     }
 
     value.has_type_flags(flags)
@@ -154,7 +158,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
             "Normalizing {value:?} without wrapping in a `Binder`"
         );
 
-        if !needs_normalization(&value, self.param_env.reveal()) {
+        if !needs_normalization(self.selcx.infcx, self.param_env, &value) {
             value
         } else {
             value.fold_with(self)
@@ -178,7 +182,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if !needs_normalization(&ty, self.param_env.reveal()) {
+        if !needs_normalization(self.selcx.infcx, self.param_env, &ty) {
             return ty;
         }
 
@@ -213,10 +217,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
         match kind {
             ty::Opaque => {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
-                match self.param_env.reveal() {
-                    Reveal::UserFacing => ty.super_fold_with(self),
-
-                    Reveal::All => {
+                match self.selcx.infcx.typing_mode(self.param_env) {
+                    TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
+                        ty.super_fold_with(self)
+                    }
+                    TypingMode::PostAnalysis => {
                         let recursion_limit = self.cx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.depth) {
                             self.selcx.infcx.err_ctxt().report_overflow_error(
@@ -403,7 +408,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let tcx = self.selcx.tcx();
         if tcx.features().generic_const_exprs()
-            || !needs_normalization(&constant, self.param_env.reveal())
+            || !needs_normalization(self.selcx.infcx, self.param_env, &constant)
         {
             constant
         } else {
@@ -420,7 +425,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
 
     #[inline]
     fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
-        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+        if p.allow_normalization() && needs_normalization(self.selcx.infcx, self.param_env, &p) {
             p.super_fold_with(self)
         } else {
             p
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a75c07c2e8c..aab854e9caf 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -16,7 +16,7 @@ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedD
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast};
+use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use tracing::{debug, instrument};
@@ -975,18 +975,21 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     // and the obligation is monomorphic, otherwise passes such as
                     // transmute checking and polymorphic MIR optimizations could
                     // get a result which isn't correct for all monomorphizations.
-                    if obligation.param_env.reveal() == Reveal::All {
-                        // NOTE(eddyb) inference variables can resolve to parameters, so
-                        // assume `poly_trait_ref` isn't monomorphic, if it contains any.
-                        let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref);
-                        !poly_trait_ref.still_further_specializable()
-                    } else {
-                        debug!(
-                            assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
-                            ?obligation.predicate,
-                            "assemble_candidates_from_impls: not eligible due to default",
-                        );
-                        false
+                    match selcx.infcx.typing_mode(obligation.param_env) {
+                        TypingMode::Coherence | TypingMode::Analysis { .. } => {
+                            debug!(
+                                assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
+                                ?obligation.predicate,
+                                "assemble_candidates_from_impls: not eligible due to default",
+                            );
+                            false
+                        }
+                        TypingMode::PostAnalysis => {
+                            // NOTE(eddyb) inference variables can resolve to parameters, so
+                            // assume `poly_trait_ref` isn't monomorphic, if it contains any.
+                            let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref);
+                            !poly_trait_ref.still_further_specializable()
+                        }
                     }
                 }
             }
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 01e6516302c..a8d701a750d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -9,7 +9,7 @@ use rustc_macros::extension;
 pub use rustc_middle::traits::query::NormalizationResult;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor, TypingMode};
 use rustc_span::DUMMY_SP;
 use tracing::{debug, info, instrument};
 
@@ -21,7 +21,7 @@ use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::normalize::needs_normalization;
 use crate::traits::{
-    BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, Reveal, ScrubbedTraitError,
+    BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, ScrubbedTraitError,
 };
 
 #[extension(pub trait QueryNormalizeExt<'tcx>)]
@@ -89,7 +89,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
             }
         }
 
-        if !needs_normalization(&value, self.param_env.reveal()) {
+        if !needs_normalization(self.infcx, self.param_env, &value) {
             return Ok(Normalized { value, obligations: PredicateObligations::new() });
         }
 
@@ -191,7 +191,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
-        if !needs_normalization(&ty, self.param_env.reveal()) {
+        if !needs_normalization(self.infcx, self.param_env, &ty) {
             return Ok(ty);
         }
 
@@ -215,10 +215,12 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
         let res = match kind {
             ty::Opaque => {
                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
-                match self.param_env.reveal() {
-                    Reveal::UserFacing => ty.try_super_fold_with(self)?,
+                match self.infcx.typing_mode(self.param_env) {
+                    TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
+                        ty.try_super_fold_with(self)?
+                    }
 
-                    Reveal::All => {
+                    TypingMode::PostAnalysis => {
                         let args = data.args.try_fold_with(self)?;
                         let recursion_limit = self.cx().recursion_limit();
 
@@ -332,7 +334,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
         &mut self,
         constant: ty::Const<'tcx>,
     ) -> Result<ty::Const<'tcx>, Self::Error> {
-        if !needs_normalization(&constant, self.param_env.reveal()) {
+        if !needs_normalization(self.infcx, self.param_env, &constant) {
             return Ok(constant);
         }
 
@@ -351,7 +353,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
         &mut self,
         p: ty::Predicate<'tcx>,
     ) -> Result<ty::Predicate<'tcx>, Self::Error> {
-        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+        if p.allow_normalization() && needs_normalization(self.infcx, self.param_env, &p) {
             p.try_super_fold_with(self)
         } else {
             Ok(p)
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 22223e4a890..aadb64f45d7 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -12,6 +12,13 @@ use crate::{self as ty, Interner};
 /// The current typing mode of an inference context. We unfortunately have some
 /// slightly different typing rules depending on the current context. See the
 /// doc comment for each variant for how and why they are used.
+///
+/// In most cases you can get the correct typing mode automically via:
+/// - `mir::Body::typing_mode`
+/// - `rustc_lint::LateContext::typing_mode`
+///
+/// If neither of these functions are available, feel free to reach out to
+/// t-types for help.
 #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum TypingMode<I: Interner> {
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index dbadc8432f6..8f9f75d6824 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt, TypingMode};
+use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
 use rustc_span::Span;
 use rustc_span::symbol::sym;
 use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext};
@@ -420,7 +420,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
             TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
         );
 
-        let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(obligation.param_env));
+        let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
         let mut selcx = SelectionContext::new(&infcx);
         let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
             return false;
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index c618bfe4488..41785e161d0 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -362,7 +362,7 @@ fn is_normalizable_helper<'tcx>(
     }
     // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
     cache.insert(ty, false);
-    let infcx = cx.tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
+    let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
     let cause = ObligationCause::dummy();
     let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
         match ty.kind() {