about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection')
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs220
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs93
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs69
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs109
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs133
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs7
10 files changed, 308 insertions, 378 deletions
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 91c91d4e52f..1b58c9b864e 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -177,18 +177,10 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
         R: Debug + TypeFoldable<'tcx>,
         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
     {
-        self.enter_with_canonical(
-            DUMMY_SP,
-            canonical_key,
-            |ref infcx, key, canonical_inference_vars| {
-                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-                let value = operation(infcx, &mut *fulfill_cx, key)?;
-                infcx.make_canonicalized_query_response(
-                    canonical_inference_vars,
-                    value,
-                    &mut *fulfill_cx,
-                )
-            },
-        )
+        let (ref infcx, key, canonical_inference_vars) =
+            self.build_with_canonical(DUMMY_SP, canonical_key);
+        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+        let value = operation(infcx, &mut *fulfill_cx, key)?;
+        infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index c02265ffdd7..c716c4b0be9 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{PolyTraitRef, Region, RegionVid};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
@@ -90,143 +90,105 @@ impl<'tcx> AutoTraitFinder<'tcx> {
 
         let trait_pred = ty::Binder::dummy(trait_ref);
 
-        let bail_out = tcx.infer_ctxt().enter(|infcx| {
-            let mut selcx = SelectionContext::new(&infcx);
-            let result = selcx.select(&Obligation::new(
-                ObligationCause::dummy(),
-                orig_env,
-                trait_pred.to_poly_trait_predicate(),
-            ));
-
-            match result {
-                Ok(Some(ImplSource::UserDefined(_))) => {
-                    debug!(
-                        "find_auto_trait_generics({:?}): \
-                         manual impl found, bailing out",
-                        trait_ref
-                    );
-                    return true;
-                }
-                _ => {}
+        let infcx = tcx.infer_ctxt().build();
+        let mut selcx = SelectionContext::new(&infcx);
+        for f in [
+            PolyTraitRef::to_poly_trait_predicate,
+            PolyTraitRef::to_poly_trait_predicate_negative_polarity,
+        ] {
+            let result =
+                selcx.select(&Obligation::new(ObligationCause::dummy(), orig_env, f(&trait_pred)));
+            if let Ok(Some(ImplSource::UserDefined(_))) = result {
+                debug!(
+                    "find_auto_trait_generics({:?}): \
+                 manual impl found, bailing out",
+                    trait_ref
+                );
+                // If an explicit impl exists, it always takes priority over an auto impl
+                return AutoTraitResult::ExplicitImpl;
             }
-
-            let result = selcx.select(&Obligation::new(
-                ObligationCause::dummy(),
-                orig_env,
-                trait_pred.to_poly_trait_predicate_negative_polarity(),
-            ));
-
-            match result {
-                Ok(Some(ImplSource::UserDefined(_))) => {
-                    debug!(
-                        "find_auto_trait_generics({:?}): \
-                         manual impl found, bailing out",
-                        trait_ref
-                    );
-                    true
-                }
-                _ => false,
-            }
-        });
-
-        // If an explicit impl exists, it always takes priority over an auto impl
-        if bail_out {
-            return AutoTraitResult::ExplicitImpl;
         }
 
-        tcx.infer_ctxt().enter(|infcx| {
-            let mut fresh_preds = FxHashSet::default();
+        let infcx = tcx.infer_ctxt().build();
+        let mut fresh_preds = FxHashSet::default();
+
+        // Due to the way projections are handled by SelectionContext, we need to run
+        // evaluate_predicates twice: once on the original param env, and once on the result of
+        // the first evaluate_predicates call.
+        //
+        // The problem is this: most of rustc, including SelectionContext and traits::project,
+        // are designed to work with a concrete usage of a type (e.g., Vec<u8>
+        // fn<T>() { Vec<T> }. This information will generally never change - given
+        // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
+        // If we're unable to prove that 'T' implements a particular trait, we're done -
+        // there's nothing left to do but error out.
+        //
+        // However, synthesizing an auto trait impl works differently. Here, we start out with
+        // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
+        // with - and progressively discover the conditions we need to fulfill for it to
+        // implement a certain auto trait. This ends up breaking two assumptions made by trait
+        // selection and projection:
+        //
+        // * We can always cache the result of a particular trait selection for the lifetime of
+        // an InfCtxt
+        // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
+        // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
+        //
+        // We fix the first assumption by manually clearing out all of the InferCtxt's caches
+        // in between calls to SelectionContext.select. This allows us to keep all of the
+        // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
+        // them between calls.
+        //
+        // We fix the second assumption by reprocessing the result of our first call to
+        // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
+        // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
+        // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
+        // SelectionContext to return it back to us.
+
+        let Some((new_env, user_env)) = self.evaluate_predicates(
+            &infcx,
+            trait_did,
+            ty,
+            orig_env,
+            orig_env,
+            &mut fresh_preds,
+            false,
+        ) else {
+            return AutoTraitResult::NegativeImpl;
+        };
+
+        let (full_env, full_user_env) = self
+            .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds, true)
+            .unwrap_or_else(|| {
+                panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
+            });
 
-            // Due to the way projections are handled by SelectionContext, we need to run
-            // evaluate_predicates twice: once on the original param env, and once on the result of
-            // the first evaluate_predicates call.
-            //
-            // The problem is this: most of rustc, including SelectionContext and traits::project,
-            // are designed to work with a concrete usage of a type (e.g., Vec<u8>
-            // fn<T>() { Vec<T> }. This information will generally never change - given
-            // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
-            // If we're unable to prove that 'T' implements a particular trait, we're done -
-            // there's nothing left to do but error out.
-            //
-            // However, synthesizing an auto trait impl works differently. Here, we start out with
-            // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
-            // with - and progressively discover the conditions we need to fulfill for it to
-            // implement a certain auto trait. This ends up breaking two assumptions made by trait
-            // selection and projection:
-            //
-            // * We can always cache the result of a particular trait selection for the lifetime of
-            // an InfCtxt
-            // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
-            // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
-            //
-            // We fix the first assumption by manually clearing out all of the InferCtxt's caches
-            // in between calls to SelectionContext.select. This allows us to keep all of the
-            // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
-            // them between calls.
-            //
-            // We fix the second assumption by reprocessing the result of our first call to
-            // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
-            // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
-            // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
-            // SelectionContext to return it back to us.
-
-            let Some((new_env, user_env)) = self.evaluate_predicates(
-                &infcx,
-                trait_did,
-                ty,
-                orig_env,
-                orig_env,
-                &mut fresh_preds,
-                false,
-            ) else {
-                return AutoTraitResult::NegativeImpl;
-            };
-
-            let (full_env, full_user_env) = self
-                .evaluate_predicates(
-                    &infcx,
-                    trait_did,
-                    ty,
-                    new_env,
-                    user_env,
-                    &mut fresh_preds,
-                    true,
-                )
-                .unwrap_or_else(|| {
-                    panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
-                });
-
-            debug!(
-                "find_auto_trait_generics({:?}): fulfilling \
-                 with {:?}",
-                trait_ref, full_env
-            );
-            infcx.clear_caches();
-
-            // At this point, we already have all of the bounds we need. FulfillmentContext is used
-            // to store all of the necessary region/lifetime bounds in the InferContext, as well as
-            // an additional sanity check.
-            let errors =
-                super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
-            if !errors.is_empty() {
-                panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
-            }
+        debug!(
+            "find_auto_trait_generics({:?}): fulfilling \
+             with {:?}",
+            trait_ref, full_env
+        );
+        infcx.clear_caches();
+
+        // At this point, we already have all of the bounds we need. FulfillmentContext is used
+        // to store all of the necessary region/lifetime bounds in the InferContext, as well as
+        // an additional sanity check.
+        let errors =
+            super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
+        if !errors.is_empty() {
+            panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+        }
 
-            infcx.process_registered_region_obligations(&Default::default(), full_env);
+        infcx.process_registered_region_obligations(&Default::default(), full_env);
 
-            let region_data = infcx
-                .inner
-                .borrow_mut()
-                .unwrap_region_constraints()
-                .region_constraint_data()
-                .clone();
+        let region_data =
+            infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
 
-            let vid_to_region = self.map_vid_to_region(&region_data);
+        let vid_to_region = self.map_vid_to_region(&region_data);
 
-            let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
+        let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
 
-            AutoTraitResult::PositiveImpl(auto_trait_callback(info))
-        })
+        AutoTraitResult::PositiveImpl(auto_trait_callback(info))
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index dde7527302c..8a62bf01567 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -29,60 +29,61 @@ pub fn codegen_select_candidate<'tcx>(
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    let mut infcx_builder =
-        tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
-    infcx_builder.enter(|infcx| {
-        //~^ HACK `Bubble` is required for
-        // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
-        let mut selcx = SelectionContext::new(&infcx);
+    let infcx = tcx
+        .infer_ctxt()
+        .ignoring_regions()
+        .with_opaque_type_inference(DefiningAnchor::Bubble)
+        .build();
+    //~^ HACK `Bubble` is required for
+    // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
+    let mut selcx = SelectionContext::new(&infcx);
 
-        let obligation_cause = ObligationCause::dummy();
-        let obligation =
-            Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
+    let obligation_cause = ObligationCause::dummy();
+    let obligation =
+        Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
 
-        let selection = match selcx.select(&obligation) {
-            Ok(Some(selection)) => selection,
-            Ok(None) => return Err(CodegenObligationError::Ambiguity),
-            Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
-            Err(e) => {
-                bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
-            }
-        };
+    let selection = match selcx.select(&obligation) {
+        Ok(Some(selection)) => selection,
+        Ok(None) => return Err(CodegenObligationError::Ambiguity),
+        Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
+        Err(e) => {
+            bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
+        }
+    };
 
-        debug!(?selection);
+    debug!(?selection);
 
-        // Currently, we use a fulfillment context to completely resolve
-        // all nested obligations. This is because they can inform the
-        // inference of the impl's type parameters.
-        let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
-        let impl_source = selection.map(|predicate| {
-            fulfill_cx.register_predicate_obligation(&infcx, predicate);
-        });
+    // Currently, we use a fulfillment context to completely resolve
+    // all nested obligations. This is because they can inform the
+    // inference of the impl's type parameters.
+    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
+    let impl_source = selection.map(|predicate| {
+        fulfill_cx.register_predicate_obligation(&infcx, predicate);
+    });
 
-        // In principle, we only need to do this so long as `impl_source`
-        // contains unbound type parameters. It could be a slight
-        // optimization to stop iterating early.
-        let errors = fulfill_cx.select_all_or_error(&infcx);
-        if !errors.is_empty() {
-            // `rustc_monomorphize::collector` assumes there are no type errors.
-            // Cycle errors are the only post-monomorphization errors possible; emit them now so
-            // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
-            for err in errors {
-                if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
-                    infcx.err_ctxt().report_overflow_error_cycle(&cycle);
-                }
+    // In principle, we only need to do this so long as `impl_source`
+    // contains unbound type parameters. It could be a slight
+    // optimization to stop iterating early.
+    let errors = fulfill_cx.select_all_or_error(&infcx);
+    if !errors.is_empty() {
+        // `rustc_monomorphize::collector` assumes there are no type errors.
+        // Cycle errors are the only post-monomorphization errors possible; emit them now so
+        // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
+        for err in errors {
+            if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
+                infcx.err_ctxt().report_overflow_error_cycle(&cycle);
             }
-            return Err(CodegenObligationError::FulfillmentError);
         }
+        return Err(CodegenObligationError::FulfillmentError);
+    }
 
-        let impl_source = infcx.resolve_vars_if_possible(impl_source);
-        let impl_source = infcx.tcx.erase_regions(impl_source);
+    let impl_source = infcx.resolve_vars_if_possible(impl_source);
+    let impl_source = infcx.tcx.erase_regions(impl_source);
 
-        // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
-        // as they will get constrained elsewhere, too.
-        // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
-        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
+    // as they will get constrained elsewhere, too.
+    // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
+    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
-        Ok(&*tcx.arena.alloc(impl_source))
-    })
+    Ok(&*tcx.arena.alloc(impl_source))
 }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index c3144ff6b07..7fc5c2ed0ea 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -100,11 +100,10 @@ where
         return no_overlap();
     }
 
-    let overlaps = tcx.infer_ctxt().enter(|infcx| {
-        let selcx = &mut SelectionContext::intercrate(&infcx);
-        overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
-    });
-
+    let infcx = tcx.infer_ctxt().build();
+    let selcx = &mut SelectionContext::intercrate(&infcx);
+    let overlaps =
+        overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
     if !overlaps {
         return no_overlap();
     }
@@ -112,13 +111,10 @@ where
     // In the case where we detect an error, run the check again, but
     // this time tracking intercrate ambiguity causes for better
     // diagnostics. (These take time and can lead to false errors.)
-    tcx.infer_ctxt().enter(|infcx| {
-        let selcx = &mut SelectionContext::intercrate(&infcx);
-        selcx.enable_tracking_intercrate_ambiguity_causes();
-        on_overlap(
-            overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
-        )
-    })
+    let infcx = tcx.infer_ctxt().build();
+    let selcx = &mut SelectionContext::intercrate(&infcx);
+    selcx.enable_tracking_intercrate_ambiguity_causes();
+    on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
 }
 
 fn with_fresh_ty_vars<'cx, 'tcx>(
@@ -298,33 +294,32 @@ fn negative_impl<'cx, 'tcx>(
     let tcx = selcx.infcx().tcx;
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
-    tcx.infer_ctxt().enter(|infcx| {
-        // create a parameter environment corresponding to a (placeholder) instantiation of impl1
-        let impl_env = tcx.param_env(impl1_def_id);
-        let subject1 = match traits::fully_normalize(
-            &infcx,
-            ObligationCause::dummy(),
-            impl_env,
-            tcx.impl_subject(impl1_def_id),
-        ) {
-            Ok(s) => s,
-            Err(err) => {
-                tcx.sess.delay_span_bug(
-                    tcx.def_span(impl1_def_id),
-                    format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
-                );
-                return false;
-            }
-        };
+    let infcx = tcx.infer_ctxt().build();
+    // create a parameter environment corresponding to a (placeholder) instantiation of impl1
+    let impl_env = tcx.param_env(impl1_def_id);
+    let subject1 = match traits::fully_normalize(
+        &infcx,
+        ObligationCause::dummy(),
+        impl_env,
+        tcx.impl_subject(impl1_def_id),
+    ) {
+        Ok(s) => s,
+        Err(err) => {
+            tcx.sess.delay_span_bug(
+                tcx.def_span(impl1_def_id),
+                format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
+            );
+            return false;
+        }
+    };
 
-        // Attempt to prove that impl2 applies, given all of the above.
-        let selcx = &mut SelectionContext::new(&infcx);
-        let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
-        let (subject2, obligations) =
-            impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
+    // Attempt to prove that impl2 applies, given all of the above.
+    let selcx = &mut SelectionContext::new(&infcx);
+    let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
+    let (subject2, obligations) =
+        impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
 
-        !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
-    })
+    !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
 }
 
 fn equate<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index e7270bd7c2d..5b4fa1df426 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1930,16 +1930,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         }
 
         let normalize = |candidate| {
-            self.tcx.infer_ctxt().enter(|ref infcx| {
-                let normalized = infcx
-                    .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
-                    .normalize(candidate)
-                    .ok();
-                match normalized {
-                    Some(normalized) => normalized.value,
-                    None => candidate,
-                }
-            })
+            let infcx = self.tcx.infer_ctxt().build();
+            infcx
+                .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+                .normalize(candidate)
+                .map_or(candidate, |normalized| normalized.value)
         };
 
         // Sort impl candidates so that ordering is consistent for UI tests.
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index f0346e4ae69..be603c609cb 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -23,65 +23,64 @@ pub fn can_type_implement_copy<'tcx>(
     parent_cause: ObligationCause<'tcx>,
 ) -> Result<(), CopyImplementationError<'tcx>> {
     // FIXME: (@jroesch) float this code up
-    tcx.infer_ctxt().enter(|infcx| {
-        let (adt, substs) = match self_type.kind() {
-            // These types used to have a builtin impl.
-            // Now libcore provides that impl.
-            ty::Uint(_)
-            | ty::Int(_)
-            | ty::Bool
-            | ty::Float(_)
-            | ty::Char
-            | ty::RawPtr(..)
-            | ty::Never
-            | ty::Ref(_, _, hir::Mutability::Not)
-            | ty::Array(..) => return Ok(()),
+    let infcx = tcx.infer_ctxt().build();
+    let (adt, substs) = match self_type.kind() {
+        // These types used to have a builtin impl.
+        // Now libcore provides that impl.
+        ty::Uint(_)
+        | ty::Int(_)
+        | ty::Bool
+        | ty::Float(_)
+        | ty::Char
+        | ty::RawPtr(..)
+        | ty::Never
+        | ty::Ref(_, _, hir::Mutability::Not)
+        | ty::Array(..) => return Ok(()),
 
-            ty::Adt(adt, substs) => (adt, substs),
+        ty::Adt(adt, substs) => (adt, substs),
 
-            _ => return Err(CopyImplementationError::NotAnAdt),
-        };
+        _ => return Err(CopyImplementationError::NotAnAdt),
+    };
 
-        let mut infringing = Vec::new();
-        for variant in adt.variants() {
-            for field in &variant.fields {
-                let ty = field.ty(tcx, substs);
-                if ty.references_error() {
-                    continue;
-                }
-                let span = tcx.def_span(field.did);
-                // FIXME(compiler-errors): This gives us better spans for bad
-                // projection types like in issue-50480.
-                // If the ADT has substs, point to the cause we are given.
-                // If it does not, then this field probably doesn't normalize
-                // to begin with, and point to the bad field's span instead.
-                let cause = if field
-                    .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
-                    .has_non_region_param()
-                {
-                    parent_cause.clone()
-                } else {
-                    ObligationCause::dummy_with_span(span)
-                };
-                match traits::fully_normalize(&infcx, cause, param_env, ty) {
-                    Ok(ty) => {
-                        if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
-                            infringing.push((field, ty));
-                        }
-                    }
-                    Err(errors) => {
-                        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
-                    }
-                };
+    let mut infringing = Vec::new();
+    for variant in adt.variants() {
+        for field in &variant.fields {
+            let ty = field.ty(tcx, substs);
+            if ty.references_error() {
+                continue;
             }
+            let span = tcx.def_span(field.did);
+            // FIXME(compiler-errors): This gives us better spans for bad
+            // projection types like in issue-50480.
+            // If the ADT has substs, point to the cause we are given.
+            // If it does not, then this field probably doesn't normalize
+            // to begin with, and point to the bad field's span instead.
+            let cause = if field
+                .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
+                .has_non_region_param()
+            {
+                parent_cause.clone()
+            } else {
+                ObligationCause::dummy_with_span(span)
+            };
+            match traits::fully_normalize(&infcx, cause, param_env, ty) {
+                Ok(ty) => {
+                    if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
+                        infringing.push((field, ty));
+                    }
+                }
+                Err(errors) => {
+                    infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+                }
+            };
         }
-        if !infringing.is_empty() {
-            return Err(CopyImplementationError::InfrigingFields(infringing));
-        }
-        if adt.has_dtor(tcx) {
-            return Err(CopyImplementationError::HasDestructor);
-        }
+    }
+    if !infringing.is_empty() {
+        return Err(CopyImplementationError::InfrigingFields(infringing));
+    }
+    if adt.has_dtor(tcx) {
+        return Err(CopyImplementationError::HasDestructor);
+    }
 
-        Ok(())
-    })
+    Ok(())
 }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 5153ce11ca0..274a366873c 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -234,54 +234,51 @@ fn do_normalize_predicates<'tcx>(
     // by wfcheck anyway, so I'm not sure we have to check
     // them here too, and we will remove this function when
     // we move over to lazy normalization *anyway*.
-    tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
-        let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
-            Ok(predicates) => predicates,
-            Err(errors) => {
-                let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
-                return Err(reported);
-            }
-        };
+    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
+        Ok(predicates) => predicates,
+        Err(errors) => {
+            let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+            return Err(reported);
+        }
+    };
 
-        debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
+    debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
 
-        // We can use the `elaborated_env` here; the region code only
-        // cares about declarations like `'a: 'b`.
-        let outlives_env = OutlivesEnvironment::new(elaborated_env);
+    // We can use the `elaborated_env` here; the region code only
+    // cares about declarations like `'a: 'b`.
+    let outlives_env = OutlivesEnvironment::new(elaborated_env);
+
+    // FIXME: It's very weird that we ignore region obligations but apparently
+    // still need to use `resolve_regions` as we need the resolved regions in
+    // the normalized predicates.
+    let errors = infcx.resolve_regions(&outlives_env);
+    if !errors.is_empty() {
+        tcx.sess.delay_span_bug(
+            span,
+            format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
+        );
+    }
 
-        // FIXME: It's very weird that we ignore region obligations but apparently
-        // still need to use `resolve_regions` as we need the resolved regions in
-        // the normalized predicates.
-        let errors = infcx.resolve_regions(&outlives_env);
-        if !errors.is_empty() {
-            tcx.sess.delay_span_bug(
+    match infcx.fully_resolve(predicates) {
+        Ok(predicates) => Ok(predicates),
+        Err(fixup_err) => {
+            // If we encounter a fixup error, it means that some type
+            // variable wound up unconstrained. I actually don't know
+            // if this can happen, and I certainly don't expect it to
+            // happen often, but if it did happen it probably
+            // represents a legitimate failure due to some kind of
+            // unconstrained variable.
+            //
+            // @lcnr: Let's still ICE here for now. I want a test case
+            // for that.
+            span_bug!(
                 span,
-                format!(
-                    "failed region resolution while normalizing {elaborated_env:?}: {errors:?}"
-                ),
+                "inference variables in normalized parameter environment: {}",
+                fixup_err
             );
         }
-
-        match infcx.fully_resolve(predicates) {
-            Ok(predicates) => Ok(predicates),
-            Err(fixup_err) => {
-                // If we encounter a fixup error, it means that some type
-                // variable wound up unconstrained. I actually don't know
-                // if this can happen, and I certainly don't expect it to
-                // happen often, but if it did happen it probably
-                // represents a legitimate failure due to some kind of
-                // unconstrained variable.
-                //
-                // @lcnr: Let's still ICE here for now. I want a test case
-                // for that.
-                span_bug!(
-                    span,
-                    "inference variables in normalized parameter environment: {}",
-                    fixup_err
-                );
-            }
-        }
-    })
+    }
 }
 
 // FIXME: this is gonna need to be removed ...
@@ -473,21 +470,20 @@ pub fn impossible_predicates<'tcx>(
 ) -> bool {
     debug!("impossible_predicates(predicates={:?})", predicates);
 
-    let result = tcx.infer_ctxt().enter(|infcx| {
-        let param_env = ty::ParamEnv::reveal_all();
-        let ocx = ObligationCtxt::new(&infcx);
-        let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
-        for predicate in predicates {
-            let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
-            ocx.register_obligation(obligation);
-        }
-        let errors = ocx.select_all_or_error();
+    let infcx = tcx.infer_ctxt().build();
+    let param_env = ty::ParamEnv::reveal_all();
+    let ocx = ObligationCtxt::new(&infcx);
+    let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
+    for predicate in predicates {
+        let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+        ocx.register_obligation(obligation);
+    }
+    let errors = ocx.select_all_or_error();
 
-        // Clean up after ourselves
-        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+    // Clean up after ourselves
+    let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
-        !errors.is_empty()
-    });
+    let result = !errors.is_empty();
     debug!("impossible_predicates = {:?}", result);
     result
 }
@@ -578,18 +574,16 @@ fn is_impossible_method<'tcx>(
         }
     });
 
-    tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
-        for obligation in predicates_for_trait {
-            // Ignore overflow error, to be conservative.
-            if let Ok(result) = infcx.evaluate_obligation(&obligation)
-                && !result.may_apply()
-            {
-                return true;
-            }
+    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    for obligation in predicates_for_trait {
+        // Ignore overflow error, to be conservative.
+        if let Ok(result) = infcx.evaluate_obligation(&obligation)
+            && !result.may_apply()
+        {
+            return true;
         }
-
-        false
-    })
+    }
+    false
 }
 
 #[derive(Clone, Debug)]
@@ -952,10 +946,9 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
         }),
     );
 
-    let implsrc = tcx.infer_ctxt().enter(|infcx| {
-        let mut selcx = SelectionContext::new(&infcx);
-        selcx.select(&obligation).unwrap()
-    });
+    let infcx = tcx.infer_ctxt().build();
+    let mut selcx = SelectionContext::new(&infcx);
+    let implsrc = selcx.select(&obligation).unwrap();
 
     let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
         bug!();
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 8f87a7fdeba..31dd30c5c6a 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -734,10 +734,9 @@ fn receiver_is_dispatchable<'tcx>(
         Obligation::new(ObligationCause::dummy(), param_env, predicate)
     };
 
-    tcx.infer_ctxt().enter(|ref infcx| {
-        // the receiver is dispatchable iff the obligation holds
-        infcx.predicate_must_hold_modulo_regions(&obligation)
-    })
+    let infcx = tcx.infer_ctxt().build();
+    // the receiver is dispatchable iff the obligation holds
+    infcx.predicate_must_hold_modulo_regions(&obligation)
 }
 
 fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index bfc3b760050..c891658582a 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -149,13 +149,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
     let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
-    tcx.infer_ctxt().enter(|infcx| {
-        let impl1_trait_ref = match traits::fully_normalize(
-            &infcx,
-            ObligationCause::dummy(),
-            penv,
-            impl1_trait_ref,
-        ) {
+    let infcx = tcx.infer_ctxt().build();
+    let impl1_trait_ref =
+        match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
             Ok(impl1_trait_ref) => impl1_trait_ref,
             Err(_errors) => {
                 tcx.sess.delay_span_bug(
@@ -166,9 +162,8 @@ 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, impl1_trait_ref, impl2_def_id).is_ok()
-    })
+    // Attempt to prove that impl2 applies, given all of the above.
+    fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
 }
 
 /// Attempt to fulfill all obligations of `target_impl` after unification with
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index b6cfff9eb0a..932dbbb81e5 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -265,9 +265,8 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
 
 pub fn provide(providers: &mut Providers) {
     providers.has_structural_eq_impls = |tcx, ty| {
-        tcx.infer_ctxt().enter(|infcx| {
-            let cause = ObligationCause::dummy();
-            type_marked_structural(&infcx, ty, cause)
-        })
+        let infcx = tcx.infer_ctxt().build();
+        let cause = ObligationCause::dummy();
+        type_marked_structural(&infcx, ty, cause)
     };
 }