about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-11-28 08:05:16 +0000
committerGitHub <noreply@github.com>2024-11-28 08:05:16 +0000
commit4624dadc209f595fffc87ef54a54156a5d31cec7 (patch)
treedd441ff27ed00a8826fbb8fd042eef1a2293b260 /compiler/rustc_trait_selection/src
parent987d642de5bf3c8e263c477ab728db5cd88c0ec3 (diff)
parent8e2d72bac8e29cda5b1457720dcdc66def70d9d4 (diff)
Merge pull request #4063 from rust-lang/rustup-2024-11-28
Automatic Rustup
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs17
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs25
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs24
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs50
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/_match.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs77
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs191
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs35
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs36
19 files changed, 263 insertions, 320 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 929fa559d75..0f9d4cb1982 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -152,7 +152,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         err: TypeError<'tcx>,
     ) -> Diag<'a> {
         self.report_and_explain_type_error(
-            TypeTrace::types(cause, true, expected, actual),
+            TypeTrace::types(cause, expected, actual),
             param_env,
             err,
         )
@@ -167,7 +167,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         err: TypeError<'tcx>,
     ) -> Diag<'a> {
         self.report_and_explain_type_error(
-            TypeTrace::consts(cause, true, expected, actual),
+            TypeTrace::consts(cause, expected, actual),
             param_env,
             err,
         )
@@ -1792,12 +1792,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     fn suggest_specify_actual_length(
         &self,
-        terr: TypeError<'_>,
-        trace: &TypeTrace<'_>,
+        terr: TypeError<'tcx>,
+        trace: &TypeTrace<'tcx>,
         span: Span,
     ) -> Option<TypeErrorAdditionalDiags> {
         let hir = self.tcx.hir();
-        let TypeError::FixedArraySize(sz) = terr else {
+        let TypeError::ArraySize(sz) = terr else {
             return None;
         };
         let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
@@ -1838,9 +1838,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         if let Some(tykind) = tykind
             && let hir::TyKind::Array(_, length) = tykind
             && let hir::ArrayLen::Body(ct) = length
+            && let Some((scalar, ty)) = sz.found.try_to_scalar()
+            && ty == self.tcx.types.usize
         {
             let span = ct.span();
-            Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
+            Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
+                span,
+                length: scalar.to_target_usize(&self.tcx).unwrap(),
+            })
         } else {
             None
         }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 4e7d7b79ff4..75191894525 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -725,7 +725,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     &obligation.cause,
                     None,
                     None,
-                    TypeError::Sorts(ty::error::ExpectedFound::new(true, expected_ty, ct_ty)),
+                    TypeError::Sorts(ty::error::ExpectedFound::new(expected_ty, ct_ty)),
                     false,
                 );
                 diag
@@ -1449,7 +1449,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 secondary_span,
                 values.map(|(_, normalized_ty, expected_ty)| {
                     obligation.param_env.and(infer::ValuePairs::Terms(ExpectedFound::new(
-                        true,
                         expected_ty,
                         normalized_ty,
                     )))
@@ -1804,24 +1803,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 StringPart::highlighted("cargo tree".to_string()),
                 StringPart::normal("` to explore your dependency tree".to_string()),
             ]);
-
-            // FIXME: this is a giant hack for the benefit of this specific diagnostic. Because
-            // we're so nested in method calls before the error gets emitted, bubbling a single bit
-            // flag informing the top level caller to stop adding extra detail to the diagnostic,
-            // would actually be harder to follow. So we do something naughty here: we consume the
-            // diagnostic, emit it and leave in its place a "delayed bug" that will continue being
-            // modified but won't actually be printed to end users. This *is not ideal*, but allows
-            // us to reduce the verbosity of an error that is already quite verbose and increase its
-            // specificity. Below we modify the main message as well, in a way that *could* break if
-            // the implementation of Diagnostics change significantly, but that would be caught with
-            // a make test failure when this diagnostic is tested.
-            err.primary_message(format!(
-                "{} because the trait comes from a different crate version",
-                err.messages[0].0.as_str().unwrap(),
-            ));
-            let diag = err.clone();
-            err.downgrade_to_delayed_bug();
-            self.tcx.dcx().emit_diagnostic(diag);
             return true;
         }
 
@@ -2755,7 +2736,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             (obligation.cause.clone(), terr)
         };
         self.report_and_explain_type_error(
-            TypeTrace::trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+            TypeTrace::trait_refs(&cause, expected_trait_ref, found_trait_ref),
             obligation.param_env,
             terr,
         )
@@ -2846,7 +2827,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() && not_tupled
         {
             return Ok(self.report_and_explain_type_error(
-                TypeTrace::trait_refs(&obligation.cause, true, expected_trait_ref, found_trait_ref),
+                TypeTrace::trait_refs(&obligation.cause, expected_trait_ref, found_trait_ref),
                 obligation.param_env,
                 ty::error::TypeError::Mismatch,
             ));
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 5ad15feadff..27b45f70946 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -5312,9 +5312,10 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
     };
     let name = tcx.item_name(proj.projection_term.def_id);
     let mut predicates = generics.predicates.iter().peekable();
-    let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None;
+    let mut prev: Option<(&hir::WhereBoundPredicate<'_>, Span)> = None;
     while let Some(pred) = predicates.next() {
-        let hir::WherePredicate::BoundPredicate(pred) = pred else {
+        let curr_span = pred.span;
+        let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind else {
             continue;
         };
         let mut bounds = pred.bounds.iter();
@@ -5340,8 +5341,8 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
                         .iter()
                         .filter(|p| {
                             matches!(
-                                p,
-                                hir::WherePredicate::BoundPredicate(p)
+                                p.kind,
+                                hir::WherePredicateKind::BoundPredicate(p)
                                 if hir::PredicateOrigin::WhereClause == p.origin
                             )
                         })
@@ -5351,20 +5352,21 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
                     // There's only one `where` bound, that needs to be removed. Remove the whole
                     // `where` clause.
                     generics.where_clause_span
-                } else if let Some(hir::WherePredicate::BoundPredicate(next)) = predicates.peek()
+                } else if let Some(next_pred) = predicates.peek()
+                    && let hir::WherePredicateKind::BoundPredicate(next) = next_pred.kind
                     && pred.origin == next.origin
                 {
                     // There's another bound, include the comma for the current one.
-                    pred.span.until(next.span)
-                } else if let Some(prev) = prev
+                    curr_span.until(next_pred.span)
+                } else if let Some((prev, prev_span)) = prev
                     && pred.origin == prev.origin
                 {
                     // Last bound, try to remove the previous comma.
-                    prev.span.shrink_to_hi().to(pred.span)
+                    prev_span.shrink_to_hi().to(curr_span)
                 } else if pred.origin == hir::PredicateOrigin::WhereClause {
-                    pred.span.with_hi(generics.where_clause_span.hi())
+                    curr_span.with_hi(generics.where_clause_span.hi())
                 } else {
-                    pred.span
+                    curr_span
                 };
 
                 err.span_suggestion_verbose(
@@ -5417,7 +5419,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
                 );
             }
         }
-        prev = Some(pred);
+        prev = Some((pred, curr_span));
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 2cc787c8bc5..09bba24ba61 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -204,7 +204,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
             // 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.
-            match self.typing_mode_unchecked() {
+            match self.typing_mode() {
                 TypingMode::Coherence | TypingMode::Analysis { .. } => false,
                 TypingMode::PostAnalysis => {
                     let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 53e5420d27a..0f90c45d032 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -264,14 +264,14 @@ fn fulfillment_error_for_no_solution<'tcx>(
             let (a, b) = infcx.enter_forall_and_leak_universe(
                 obligation.predicate.kind().rebind((pred.a, pred.b)),
             );
-            let expected_found = ExpectedFound::new(true, a, b);
+            let expected_found = ExpectedFound::new(a, b);
             FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
         }
         ty::PredicateKind::Coerce(pred) => {
             let (a, b) = infcx.enter_forall_and_leak_universe(
                 obligation.predicate.kind().rebind((pred.a, pred.b)),
             );
-            let expected_found = ExpectedFound::new(false, a, b);
+            let expected_found = ExpectedFound::new(b, a);
             FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
         }
         ty::PredicateKind::Clause(_)
@@ -346,12 +346,21 @@ fn find_best_leaf_obligation<'tcx>(
     consider_ambiguities: bool,
 ) -> PredicateObligation<'tcx> {
     let obligation = infcx.resolve_vars_if_possible(obligation.clone());
+    // FIXME: we use a probe here as the `BestObligation` visitor does not
+    // check whether it uses candidates which get shadowed by where-bounds.
+    //
+    // We should probably fix the visitor to not do so instead, as this also
+    // means the leaf obligation may be incorrect.
     infcx
-        .visit_proof_tree(obligation.clone().into(), &mut BestObligation {
-            obligation: obligation.clone(),
-            consider_ambiguities,
+        .fudge_inference_if_ok(|| {
+            infcx
+                .visit_proof_tree(obligation.clone().into(), &mut BestObligation {
+                    obligation: obligation.clone(),
+                    consider_ambiguities,
+                })
+                .break_value()
+                .ok_or(())
         })
-        .break_value()
         .unwrap_or(obligation)
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index fac0414d714..6730f28893d 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -318,13 +318,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 elaborate(tcx, computed_preds.clone().chain(user_computed_preds.iter().cloned()));
             new_env = ty::ParamEnv::new(
                 tcx.mk_clauses_from_iter(normalized_preds.filter_map(|p| p.as_clause())),
-                param_env.reveal(),
             );
         }
 
         let final_user_env = ty::ParamEnv::new(
             tcx.mk_clauses_from_iter(user_computed_preds.into_iter().filter_map(|p| p.as_clause())),
-            user_env.reveal(),
         );
         debug!(
             "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index cf63f14fb93..e0a9ddf1876 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -150,8 +150,8 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]>
                     .predicates
                     .iter()
                     .filter_map(|pred| {
-                        match pred {
-                            hir::WherePredicate::BoundPredicate(pred)
+                        match pred.kind {
+                            hir::WherePredicateKind::BoundPredicate(pred)
                                 if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id =>
                             {
                                 // Fetch spans for trait bounds that are Sized:
@@ -707,7 +707,7 @@ fn receiver_is_dispatchable<'tcx>(
         let caller_bounds =
             param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]);
 
-        ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds), param_env.reveal())
+        ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds))
     };
 
     // Receiver: DispatchFromDyn<Receiver[Self => U]>
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index cb36f1a62db..07fb2efb7fe 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -20,13 +20,18 @@ pub fn evaluate_host_effect_obligation<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
-    if matches!(selcx.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) {
+    if matches!(selcx.infcx.typing_mode(), TypingMode::Coherence) {
         span_bug!(
             obligation.cause.span,
             "should not select host obligation in old solver in intercrate mode"
         );
     }
 
+    // Force ambiguity for infer self ty.
+    if obligation.predicate.self_ty().is_ty_var() {
+        return Err(EvaluationFailure::Ambiguous);
+    }
+
     match evaluate_host_effect_from_bounds(selcx, obligation) {
         Ok(result) => return Ok(result),
         Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 2ec5f0d2249..03e483f555d 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -557,8 +557,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                             ProcessResult::Changed(mk_pending(ok.obligations))
                         }
                         Ok(Err(err)) => {
-                            let expected_found =
-                                ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
+                            let expected_found = if subtype.a_is_expected {
+                                ExpectedFound::new(subtype.a, subtype.b)
+                            } else {
+                                ExpectedFound::new(subtype.b, subtype.a)
+                            };
                             ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err))
                         }
                     }
@@ -578,7 +581,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         }
                         Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
                         Ok(Err(err)) => {
-                            let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
+                            let expected_found = ExpectedFound::new(coerce.b, coerce.a);
                             ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err))
                         }
                     }
@@ -703,7 +706,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                 }
                                 Err(err) => {
                                     ProcessResult::Error(FulfillmentErrorCode::ConstEquate(
-                                        ExpectedFound::new(true, c1, c2),
+                                        ExpectedFound::new(c1, c2),
                                         err,
                                     ))
                                 }
@@ -727,7 +730,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                 ProcessResult::Unchanged
                             } else {
                                 // Two different constants using generic parameters ~> error.
-                                let expected_found = ExpectedFound::new(true, c1, c2);
+                                let expected_found = ExpectedFound::new(c1, c2);
                                 ProcessResult::Error(FulfillmentErrorCode::ConstEquate(
                                     expected_found,
                                     TypeError::ConstMismatch(expected_found),
@@ -768,8 +771,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global()
-            && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
         {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
@@ -824,8 +826,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global()
-            && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
         {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 80cef690028..069fab6a6e6 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -423,7 +423,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());
+    let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates));
     if !elaborated_env.has_aliases() {
         return elaborated_env;
     }
@@ -470,8 +470,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     // here. I believe they should not matter, because we are ignoring TypeOutlives param-env
     // predicates here anyway. Keeping them here anyway because it seems safer.
     let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned();
-    let outlives_env =
-        ty::ParamEnv::new(tcx.mk_clauses_from_iter(outlives_env), unnormalized_env.reveal());
+    let outlives_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(outlives_env));
     let Ok(outlives_predicates) =
         do_normalize_predicates(tcx, cause, outlives_env, outlives_predicates)
     else {
@@ -484,7 +483,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     let mut predicates = non_outlives_predicates;
     predicates.extend(outlives_predicates);
     debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
-    ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal())
+    ty::ParamEnv::new(tcx.mk_clauses(&predicates))
 }
 
 #[derive(Debug)]
@@ -552,8 +551,18 @@ pub fn try_evaluate_const<'tcx>(
         | ty::ConstKind::Placeholder(_)
         | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
         ty::ConstKind::Unevaluated(uv) => {
-            // Postpone evaluation of constants that depend on generic parameters or inference variables.
-            let (args, param_env) = if tcx.features().generic_const_exprs()
+            // Postpone evaluation of constants that depend on generic parameters or
+            // inference variables.
+            //
+            // We use `TypingMode::PostAnalysis`  here which is not *technically* correct
+            // to be revealing opaque types here as borrowcheck has not run yet. However,
+            // CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during
+            // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
+            // As a result we always use a revealed env when resolving the instance to evaluate.
+            //
+            // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
+            // instead of having this logic here
+            let (args, typing_env) = if tcx.features().generic_const_exprs()
                 && uv.has_non_region_infer()
             {
                 // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
@@ -569,13 +578,17 @@ pub fn try_evaluate_const<'tcx>(
                             // the generic arguments provided for it, then we should *not* attempt to evaluate it.
                             return Err(EvaluateConstErr::HasGenericsOrInfers);
                         } else {
-                            (replace_param_and_infer_args_with_placeholder(tcx, uv.args), param_env)
+                            let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args);
+                            let typing_env = infcx
+                                .typing_env(tcx.erase_regions(param_env))
+                                .with_post_analysis_normalized(tcx);
+                            (args, typing_env)
                         }
                     }
                     Err(_) | Ok(None) => {
                         let args = GenericArgs::identity_for_item(tcx, uv.def);
-                        let param_env = tcx.param_env(uv.def);
-                        (args, param_env)
+                        let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
+                        (args, typing_env)
                     }
                 }
             } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() {
@@ -594,27 +607,20 @@ pub fn try_evaluate_const<'tcx>(
                 );
 
                 let args = GenericArgs::identity_for_item(tcx, uv.def);
-                let param_env = tcx.param_env(uv.def);
-                (args, param_env)
+                let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
+                (args, typing_env)
             } else {
                 // FIXME: This codepath is reachable under `associated_const_equality` and in the
                 // future will be reachable by `min_generic_const_args`. We should handle inference
                 // variables and generic parameters properly instead of doing nothing.
-                (uv.args, param_env)
+                let typing_env = infcx
+                    .typing_env(tcx.erase_regions(param_env))
+                    .with_post_analysis_normalized(tcx);
+                (uv.args, typing_env)
             };
             let uv = ty::UnevaluatedConst::new(uv.def, args);
 
-            // It's not *technically* correct to be revealing opaque types here as we could still be
-            // before borrowchecking. However, CTFE itself uses `Reveal::All` unconditionally even during
-            // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a result we
-            // always use a revealed env when resolving the instance to evaluate.
-            //
-            // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
-            // instead of having this logic here
-            let typing_env =
-                tcx.erase_regions(infcx.typing_env(param_env)).with_reveal_all_normalized(tcx);
             let erased_uv = tcx.erase_regions(uv);
-
             use rustc_middle::mir::interpret::ErrorHandled;
             match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
                 Ok(Ok(val)) => Ok(ty::Const::new_value(
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 5c38d162712..4d3d8c66e62 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -111,14 +111,13 @@ where
 
 pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
     infcx: &InferCtxt<'tcx>,
-    param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
     value: &T,
 ) -> bool {
     let mut flags = ty::TypeFlags::HAS_ALIAS;
 
-    // Opaques are treated as rigid with `Reveal::UserFacing`,
+    // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
     // so we can ignore those.
-    match infcx.typing_mode(param_env_for_debug_assertion) {
+    match infcx.typing_mode() {
         TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
             flags.remove(ty::TypeFlags::HAS_TY_OPAQUE)
         }
@@ -158,11 +157,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
             "Normalizing {value:?} without wrapping in a `Binder`"
         );
 
-        if !needs_normalization(self.selcx.infcx, self.param_env, &value) {
-            value
-        } else {
-            value.fold_with(self)
-        }
+        if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
     }
 }
 
@@ -182,7 +177,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(self.selcx.infcx, self.param_env, &ty) {
+        if !needs_normalization(self.selcx.infcx, &ty) {
             return ty;
         }
 
@@ -217,7 +212,7 @@ 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.selcx.infcx.typing_mode(self.param_env) {
+                match self.selcx.infcx.typing_mode() {
                     TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
                         ty.super_fold_with(self)
                     }
@@ -407,8 +402,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
     #[instrument(skip(self), level = "debug")]
     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(self.selcx.infcx, self.param_env, &constant)
+        if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &constant)
         {
             constant
         } else {
@@ -426,7 +420,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(self.selcx.infcx, self.param_env, &p) {
+        if p.allow_normalization() && needs_normalization(self.selcx.infcx, &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 aab854e9caf..2864f277df5 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -10,7 +10,6 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
-pub use rustc_middle::traits::Reveal;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
@@ -975,7 +974,7 @@ 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.
-                    match selcx.infcx.typing_mode(obligation.param_env) {
+                    match selcx.infcx.typing_mode() {
                         TypingMode::Coherence | TypingMode::Analysis { .. } => {
                             debug!(
                                 assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 5f89894fb82..22cfbb2c840 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -89,7 +89,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
             }
         }
 
-        if !needs_normalization(self.infcx, self.param_env, &value) {
+        if !needs_normalization(self.infcx, &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(self.infcx, self.param_env, &ty) {
+        if !needs_normalization(self.infcx, &ty) {
             return Ok(ty);
         }
 
@@ -215,7 +215,7 @@ 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.infcx.typing_mode(self.param_env) {
+                match self.infcx.typing_mode() {
                     TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
                         ty.try_super_fold_with(self)?
                     }
@@ -334,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(self.infcx, self.param_env, &constant) {
+        if !needs_normalization(self.infcx, &constant) {
             return Ok(constant);
         }
 
@@ -353,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(self.infcx, self.param_env, &p) {
+        if p.allow_normalization() && needs_normalization(self.infcx, &p) {
             p.try_super_fold_with(self)
         } else {
             Ok(p)
diff --git a/compiler/rustc_trait_selection/src/traits/select/_match.rs b/compiler/rustc_trait_selection/src/traits/select/_match.rs
index 3980d672a11..7c19c35a4f7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/_match.rs
@@ -70,7 +70,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> {
             ) => Ok(a),
 
             (&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
-                Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
+                Err(TypeError::Sorts(ExpectedFound::new(a, b)))
             }
 
             (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.cx(), guar)),
@@ -95,7 +95,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> {
             }
 
             (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
-                return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b)));
+                return Err(TypeError::ConstMismatch(ExpectedFound::new(a, b)));
             }
 
             _ => {}
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 345e1cc31f3..32b4567aba4 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -91,14 +91,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             } else if tcx.is_lang_item(def_id, LangItem::Sized) {
                 // Sized is never implementable by end-users, it is
                 // always automatically computed.
-
-                // FIXME: Consider moving this check to the top level as it
-                // may also be useful for predicates other than `Sized`
-                // Error type cannot possibly implement `Sized` (fixes #123154)
-                if let Err(e) = obligation.predicate.skip_binder().self_ty().error_reported() {
-                    return Err(SelectionError::Overflow(e.into()));
-                }
-
                 let sized_conditions = self.sized_conditions(obligation);
                 self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::Unsize) {
@@ -230,13 +222,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<(), SelectionError<'tcx>> {
         debug!(?stack.obligation);
 
-        // An error type will unify with anything. So, avoid
-        // matching an error type with `ParamCandidate`.
-        // This helps us avoid spurious errors like issue #121941.
-        if stack.obligation.predicate.references_error() {
-            return Ok(());
-        }
-
         let bounds = stack
             .obligation
             .param_env
@@ -563,19 +548,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        // Essentially any user-written impl will match with an error type,
-        // so creating `ImplCandidates` isn't useful. However, we might
-        // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`)
-        // This helps us avoid overflow: see issue #72839
-        // Since compilation is already guaranteed to fail, this is just
-        // to try to show the 'nicest' possible errors to the user.
-        // We don't check for errors in the `ParamEnv` - in practice,
-        // it seems to cause us to be overly aggressive in deciding
-        // to give up searching for candidates, leading to spurious errors.
-        if obligation.predicate.references_error() {
-            return;
-        }
-
         let drcx = DeepRejectCtxt::relate_rigid_infer(self.tcx());
         let obligation_args = obligation.predicate.skip_binder().trait_ref.args;
         self.tcx().for_each_relevant_impl(
@@ -788,9 +760,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         //
                         // Note that this is only sound as projection candidates of opaque types
                         // are always applicable for auto traits.
-                    } else if let TypingMode::Coherence =
-                        self.infcx.typing_mode(obligation.param_env)
-                    {
+                    } else if let TypingMode::Coherence = self.infcx.typing_mode() {
                         // We do not emit auto trait candidates for opaque types in coherence.
                         // Doing so can result in weird dependency cycles.
                         candidates.ambiguous = true;
@@ -933,7 +903,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         //
         // FIXME(@lcnr): This should probably only trigger during analysis,
         // disabling candidates during codegen is also questionable.
-        if let TypingMode::Coherence = self.infcx.typing_mode(param_env) {
+        if let TypingMode::Coherence = self.infcx.typing_mode() {
             return None;
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5b4e895189b..3b64a47181a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -222,7 +222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Enables tracking of intercrate ambiguity causes. See
     /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
+        assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
         assert!(self.intercrate_ambiguity_causes.is_none());
         self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@@ -234,7 +234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn take_intercrate_ambiguity_causes(
         &mut self,
     ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
-        assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
+        assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
@@ -1027,7 +1027,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: PolyTraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        if !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        if !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
             && obligation.is_global()
             && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
         {
@@ -1310,13 +1310,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<EvaluationResult> {
-        let tcx = self.tcx();
+        let infcx = self.infcx;
+        let tcx = infcx.tcx;
         if self.can_use_global_caches(param_env, trait_pred) {
-            if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) {
-                return Some(res);
+            let key = (infcx.typing_env(param_env), trait_pred);
+            if let Some(res) = tcx.evaluation_cache.get(&key, tcx) {
+                Some(res)
+            } else {
+                debug_assert_eq!(infcx.evaluation_cache.get(&(param_env, trait_pred), tcx), None);
+                None
             }
+        } else {
+            self.infcx.evaluation_cache.get(&(param_env, trait_pred), tcx)
         }
-        self.infcx.evaluation_cache.get(&(param_env, trait_pred), tcx)
     }
 
     fn insert_evaluation_cache(
@@ -1332,18 +1338,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
-        if self.can_use_global_caches(param_env, trait_pred) && !trait_pred.has_infer() {
+        let infcx = self.infcx;
+        let tcx = infcx.tcx;
+        if self.can_use_global_caches(param_env, trait_pred) {
             debug!(?trait_pred, ?result, "insert_evaluation_cache global");
             // This may overwrite the cache with the same value
-            // FIXME: Due to #50507 this overwrites the different values
-            // This should be changed to use HashMapExt::insert_same
-            // when that is fixed
-            self.tcx().evaluation_cache.insert((param_env, trait_pred), dep_node, result);
+            tcx.evaluation_cache.insert(
+                (infcx.typing_env(param_env), trait_pred),
+                dep_node,
+                result,
+            );
             return;
+        } else {
+            debug!(?trait_pred, ?result, "insert_evaluation_cache local");
+            self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
         }
-
-        debug!(?trait_pred, ?result, "insert_evaluation_cache");
-        self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
     }
 
     fn check_recursion_depth<T>(
@@ -1459,7 +1468,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
         let obligation = &stack.obligation;
-        match self.infcx.typing_mode(obligation.param_env) {
+        match self.infcx.typing_mode() {
             TypingMode::Coherence => {}
             TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()),
         }
@@ -1485,11 +1494,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // If there are any inference variables in the `ParamEnv`, then we
         // always use a cache local to this particular scope. Otherwise, we
         // switch to a global cache.
-        if param_env.has_infer() {
+        if param_env.has_infer() || pred.has_infer() {
             return false;
         }
 
-        match self.infcx.typing_mode(param_env) {
+        match self.infcx.typing_mode() {
             // Avoid using the global cache during coherence and just rely
             // on the local cache. It is really just a simplification to
             // avoid us having to fear that coherence results "pollute"
@@ -1522,15 +1531,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
-        let tcx = self.tcx();
+        let infcx = self.infcx;
+        let tcx = infcx.tcx;
         let pred = cache_fresh_trait_pred.skip_binder();
 
         if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
-            if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) {
-                return Some(res);
+            if let Some(res) = tcx.selection_cache.get(&(infcx.typing_env(param_env), pred), tcx) {
+                Some(res)
+            } else {
+                debug_assert_eq!(infcx.selection_cache.get(&(param_env, pred), tcx), None);
+                None
             }
+        } else {
+            infcx.selection_cache.get(&(param_env, pred), tcx)
         }
-        self.infcx.selection_cache.get(&(param_env, pred), tcx)
     }
 
     /// Determines whether can we safely cache the result
@@ -1567,7 +1581,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         dep_node: DepNodeIndex,
         candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
     ) {
-        let tcx = self.tcx();
+        let infcx = self.infcx;
+        let tcx = infcx.tcx;
         let pred = cache_fresh_trait_pred.skip_binder();
 
         if !self.can_cache_candidate(&candidate) {
@@ -1578,10 +1593,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
             if let Err(Overflow(OverflowError::Canonical)) = candidate {
                 // Don't cache overflow globally; we only produce this in certain modes.
-            } else if !pred.has_infer() && !candidate.has_infer() {
+            } else {
                 debug!(?pred, ?candidate, "insert_candidate_cache global");
+                debug_assert!(!candidate.has_infer());
+
                 // This may overwrite the cache with the same value.
-                tcx.selection_cache.insert((param_env, pred), dep_node, candidate);
+                tcx.selection_cache.insert(
+                    (infcx.typing_env(param_env), pred),
+                    dep_node,
+                    candidate,
+                );
                 return;
             }
         }
@@ -2487,10 +2508,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id);
 
         let trait_ref = impl_trait_header.trait_ref.instantiate(self.tcx(), impl_args);
-        if trait_ref.references_error() {
-            return Err(());
-        }
-
         debug!(?impl_trait_header);
 
         let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } =
@@ -2522,7 +2539,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         nested_obligations.extend(obligations);
 
         if impl_trait_header.polarity == ty::ImplPolarity::Reservation
-            && !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+            && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
         {
             debug!("reservation impls only apply in intercrate mode");
             return Err(());
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 5bf3dbcbc32..a9cd705465e 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -15,24 +15,24 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::codes::*;
 use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::bug;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{
-    self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode,
-};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
+use rustc_type_ir::solve::NoSolution;
 use specialization_graph::GraphExt;
 use tracing::{debug, instrument};
 
-use super::{SelectionContext, util};
 use crate::error_reporting::traits::to_pretty_impl_header;
 use crate::errors::NegativePositiveConflict;
-use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, coherence};
+use crate::traits::{
+    FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, coherence,
+    predicates_for_generics,
+};
 
 /// Information pertinent to an overlapping impl error.
 #[derive(Debug)]
@@ -87,9 +87,14 @@ pub fn translate_args<'tcx>(
     source_args: GenericArgsRef<'tcx>,
     target_node: specialization_graph::Node,
 ) -> GenericArgsRef<'tcx> {
-    translate_args_with_cause(infcx, param_env, source_impl, source_args, target_node, |_, _| {
-        ObligationCause::dummy()
-    })
+    translate_args_with_cause(
+        infcx,
+        param_env,
+        source_impl,
+        source_args,
+        target_node,
+        &ObligationCause::dummy(),
+    )
 }
 
 /// Like [translate_args], but obligations from the parent implementation
@@ -104,7 +109,7 @@ pub fn translate_args_with_cause<'tcx>(
     source_impl: DefId,
     source_args: GenericArgsRef<'tcx>,
     target_node: specialization_graph::Node,
-    cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
+    cause: &ObligationCause<'tcx>,
 ) -> GenericArgsRef<'tcx> {
     debug!(
         "translate_args({:?}, {:?}, {:?}, {:?})",
@@ -123,7 +128,7 @@ pub fn translate_args_with_cause<'tcx>(
             }
 
             fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
-                .unwrap_or_else(|()| {
+                .unwrap_or_else(|_| {
                     bug!(
                         "When translating generic parameters from {source_impl:?} to \
                         {target_impl:?}, the expected specialization failed to hold"
@@ -137,6 +142,84 @@ pub fn translate_args_with_cause<'tcx>(
     source_args.rebase_onto(infcx.tcx, source_impl, target_args)
 }
 
+/// Attempt to fulfill all obligations of `target_impl` after unification with
+/// `source_trait_ref`. If successful, returns the generic parameters for *all* the
+/// generics of `target_impl`, including both those needed to unify with
+/// `source_trait_ref` and those whose identity is determined via a where
+/// clause in the impl.
+fn fulfill_implication<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    source_trait_ref: ty::TraitRef<'tcx>,
+    source_impl: DefId,
+    target_impl: DefId,
+    cause: &ObligationCause<'tcx>,
+) -> Result<GenericArgsRef<'tcx>, NoSolution> {
+    debug!(
+        "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
+        param_env, source_trait_ref, target_impl
+    );
+
+    let ocx = ObligationCtxt::new(infcx);
+    let source_trait_ref = ocx.normalize(cause, param_env, source_trait_ref);
+
+    if !ocx.select_all_or_error().is_empty() {
+        infcx.dcx().span_delayed_bug(
+            infcx.tcx.def_span(source_impl),
+            format!("failed to fully normalize {source_trait_ref}"),
+        );
+        return Err(NoSolution);
+    }
+
+    let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl);
+    let target_trait_ref = ocx.normalize(
+        cause,
+        param_env,
+        infcx
+            .tcx
+            .impl_trait_ref(target_impl)
+            .expect("expected source impl to be a trait impl")
+            .instantiate(infcx.tcx, target_args),
+    );
+
+    // do the impls unify? If not, no specialization.
+    ocx.eq(cause, param_env, source_trait_ref, target_trait_ref)?;
+
+    // Now check that the source trait ref satisfies all the where clauses of the target impl.
+    // This is not just for correctness; we also need this to constrain any params that may
+    // only be referenced via projection predicates.
+    let predicates = ocx.normalize(
+        cause,
+        param_env,
+        infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args),
+    );
+    let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
+    ocx.register_obligations(obligations);
+
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        // no dice!
+        debug!(
+            "fulfill_implication: for impls on {:?} and {:?}, \
+                 could not fulfill: {:?} given {:?}",
+            source_trait_ref,
+            target_trait_ref,
+            errors,
+            param_env.caller_bounds()
+        );
+        return Err(NoSolution);
+    }
+
+    debug!(
+        "fulfill_implication: an impl for {:?} specializes {:?}",
+        source_trait_ref, target_trait_ref
+    );
+
+    // Now resolve the *generic parameters* we built for the target earlier, replacing
+    // the inference variables inside with whatever we got from fulfillment.
+    Ok(infcx.resolve_vars_if_possible(target_args))
+}
+
 pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool {
     tcx.features().specialization() || tcx.features().min_specialization()
 }
@@ -182,8 +265,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
         return false;
     }
 
-    // create a parameter environment corresponding to a (placeholder) instantiation of impl1
-    let penv = tcx.param_env(impl1_def_id);
+    // create a parameter environment corresponding to an identity instantiation of impl1,
+    // i.e. the most generic instantiation of impl1.
+    let param_env = tcx.param_env(impl1_def_id);
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
     let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
@@ -191,90 +275,15 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
     // Attempt to prove that impl2 applies, given all of the above.
     fulfill_implication(
         &infcx,
-        penv,
+        param_env,
         impl1_trait_header.trait_ref.instantiate_identity(),
         impl1_def_id,
         impl2_def_id,
-        |_, _| ObligationCause::dummy(),
+        &ObligationCause::dummy(),
     )
     .is_ok()
 }
 
-/// Attempt to fulfill all obligations of `target_impl` after unification with
-/// `source_trait_ref`. If successful, returns the generic parameters for *all* the
-/// generics of `target_impl`, including both those needed to unify with
-/// `source_trait_ref` and those whose identity is determined via a where
-/// clause in the impl.
-fn fulfill_implication<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    source_trait_ref: ty::TraitRef<'tcx>,
-    source_impl: DefId,
-    target_impl: DefId,
-    error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
-) -> Result<GenericArgsRef<'tcx>, ()> {
-    debug!(
-        "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
-        param_env, source_trait_ref, target_impl
-    );
-
-    let ocx = ObligationCtxt::new(infcx);
-    let source_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, source_trait_ref);
-
-    if !ocx.select_all_or_error().is_empty() {
-        infcx.dcx().span_delayed_bug(
-            infcx.tcx.def_span(source_impl),
-            format!("failed to fully normalize {source_trait_ref}"),
-        );
-    }
-
-    let source_trait_ref = infcx.resolve_vars_if_possible(source_trait_ref);
-    let source_trait = ImplSubject::Trait(source_trait_ref);
-
-    let selcx = SelectionContext::new(infcx);
-    let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl);
-    let (target_trait, obligations) =
-        util::impl_subject_and_oblig(&selcx, param_env, target_impl, target_args, error_cause);
-
-    // do the impls unify? If not, no specialization.
-    let Ok(InferOk { obligations: more_obligations, .. }) = infcx
-        .at(&ObligationCause::dummy(), param_env)
-        // Ok to use `Yes`, as all the generic params are already replaced by inference variables,
-        // which will match the opaque type no matter if it is defining or not.
-        // Any concrete type that would match the opaque would already be handled by coherence rules,
-        // and thus either be ok to match here and already have errored, or it won't match, in which
-        // case there is no issue anyway.
-        .eq(DefineOpaqueTypes::Yes, source_trait, target_trait)
-    else {
-        debug!("fulfill_implication: {:?} does not unify with {:?}", source_trait, target_trait);
-        return Err(());
-    };
-
-    // attempt to prove all of the predicates for impl2 given those for impl1
-    // (which are packed up in penv)
-    ocx.register_obligations(obligations.chain(more_obligations));
-
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        // no dice!
-        debug!(
-            "fulfill_implication: for impls on {:?} and {:?}, \
-                 could not fulfill: {:?} given {:?}",
-            source_trait,
-            target_trait,
-            errors,
-            param_env.caller_bounds()
-        );
-        return Err(());
-    }
-
-    debug!("fulfill_implication: an impl for {:?} specializes {:?}", source_trait, target_trait);
-
-    // Now resolve the *generic parameters* we built for the target earlier, replacing
-    // the inference variables inside with whatever we got from fulfillment.
-    Ok(infcx.resolve_vars_if_possible(target_args))
-}
-
 /// Query provider for `specialization_graph_of`.
 pub(super) fn specialization_graph_provider(
     tcx: TyCtxt<'_>,
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index b7a2f20b769..da1045b664a 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -3,19 +3,16 @@ use std::collections::BTreeMap;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Diag;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::InferCtxt;
 pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt, Upcast,
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
 };
 use rustc_span::Span;
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
 
-use super::{NormalizeExt, ObligationCause, PredicateObligation, SelectionContext};
-
 ///////////////////////////////////////////////////////////////////////////
 // `TraitAliasExpander` iterator
 ///////////////////////////////////////////////////////////////////////////
@@ -166,34 +163,6 @@ impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
 // Other
 ///////////////////////////////////////////////////////////////////////////
 
-/// Instantiate all bound parameters of the impl subject with the given args,
-/// returning the resulting subject and all obligations that arise.
-/// The obligations are closed under normalization.
-pub(crate) fn impl_subject_and_oblig<'a, 'tcx>(
-    selcx: &SelectionContext<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    impl_def_id: DefId,
-    impl_args: GenericArgsRef<'tcx>,
-    cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
-) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
-    let subject = selcx.tcx().impl_subject(impl_def_id);
-    let subject = subject.instantiate(selcx.tcx(), impl_args);
-
-    let InferOk { value: subject, obligations: normalization_obligations1 } =
-        selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject);
-
-    let predicates = selcx.tcx().predicates_of(impl_def_id);
-    let predicates = predicates.instantiate(selcx.tcx(), impl_args);
-    let InferOk { value: predicates, obligations: normalization_obligations2 } =
-        selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates);
-    let impl_obligations = super::predicates_for_generics(cause, param_env, predicates);
-
-    let impl_obligations =
-        impl_obligations.chain(normalization_obligations1).chain(normalization_obligations2);
-
-    (subject, impl_obligations)
-}
-
 /// Casts a trait reference into a reference to one of its super
 /// traits; returns `None` if `target_trait_def_id` is not a
 /// supertrait.
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 437343b569c..c95b1641d1f 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -963,30 +963,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
 /// bounds that must hold on the elided self type. These are derived
 /// from the declarations of `SomeTrait`, `Send`, and friends -- if
 /// they declare `trait SomeTrait : 'static`, for example, then
-/// `'static` would appear in the list. The hard work is done by
-/// `infer::required_region_bounds`, see that for more information.
-pub fn object_region_bounds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    existential_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
-) -> Vec<ty::Region<'tcx>> {
-    let predicates = existential_predicates.iter().filter_map(|predicate| {
-        if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() {
-            None
-        } else {
-            Some(predicate.with_self_ty(tcx, tcx.types.trait_object_dummy_self))
-        }
-    });
-
-    required_region_bounds(tcx, tcx.types.trait_object_dummy_self, predicates)
-}
-
-/// Given a set of predicates that apply to an object type, returns
-/// the region bounds that the (erased) `Self` type must
-/// outlive. Precisely *because* the `Self` type is erased, the
-/// parameter `erased_self_ty` must be supplied to indicate what type
-/// has been used to represent `Self` in the predicates
-/// themselves. This should really be a unique type; `FreshTy(0)` is a
-/// popular choice.
+/// `'static` would appear in the list.
 ///
 /// N.B., in some cases, particularly around higher-ranked bounds,
 /// this function returns a kind of conservative approximation.
@@ -996,13 +973,14 @@ pub fn object_region_bounds<'tcx>(
 ///
 /// Requires that trait definitions have been processed so that we can
 /// elaborate predicates and walk supertraits.
-#[instrument(skip(tcx, predicates), level = "debug", ret)]
-pub(crate) fn required_region_bounds<'tcx>(
+pub fn object_region_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    erased_self_ty: Ty<'tcx>,
-    predicates: impl Iterator<Item = ty::Clause<'tcx>>,
+    existential_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
 ) -> Vec<ty::Region<'tcx>> {
-    assert!(!erased_self_ty.has_escaping_bound_vars());
+    let erased_self_ty = tcx.types.trait_object_dummy_self;
+
+    let predicates =
+        existential_predicates.iter().map(|predicate| predicate.with_self_ty(tcx, erased_self_ty));
 
     traits::elaborate(tcx, predicates)
         .filter_map(|pred| {