about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-05-08 08:14:18 +0200
committerGitHub <noreply@github.com>2025-05-08 08:14:18 +0200
commitaace48811beab19e404eb38b5b415e59de695a37 (patch)
tree47598c1437f12a187740317f6e65241277a05055
parent1521f2cff333930a5f74013db476bf10f16afa83 (diff)
parente7979eab891c4dd603f73d31b0d50e58a1c3f29c (diff)
downloadrust-aace48811beab19e404eb38b5b415e59de695a37.tar.gz
rust-aace48811beab19e404eb38b5b415e59de695a37.zip
Rollup merge of #140641 - lcnr:opaque-type-storage-entries, r=compiler-errors
detect additional uses of opaques after writeback

Based on #140607. It's a lot harder to encounter in practice than I though :sweat_smile: :grin: I've still added it with the expectation that somebody will encounter it at some point.

Also modifies the `EvalCtxt` to use the same impl to detect newly added opaque types.

r? ``@compiler-errors``
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/opaque_types.rs26
-rw-r--r--compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs9
-rw-r--r--compiler/rustc_infer/src/infer/context.rs59
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs28
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs22
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs8
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs51
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs39
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs47
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs30
14 files changed, 204 insertions, 139 deletions
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 78233a34c46..60187abd558 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -32,6 +32,7 @@ mod gather_locals;
 mod intrinsicck;
 mod method;
 mod op;
+mod opaque_types;
 mod pat;
 mod place_op;
 mod rvalue_scopes;
@@ -245,9 +246,7 @@ fn typeck_with_inspect<'tcx>(
 
     let typeck_results = fcx.resolve_type_vars_in_body(body);
 
-    // We clone the defined opaque types during writeback in the new solver
-    // because we have to use them during normalization.
-    let _ = fcx.infcx.take_opaque_types();
+    fcx.detect_opaque_types_added_during_writeback();
 
     // Consistency check our TypeckResults instance can hold all ItemLocalIds
     // it will need to hold.
diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs
new file mode 100644
index 00000000000..e0224f8c6e1
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/opaque_types.rs
@@ -0,0 +1,26 @@
+use super::FnCtxt;
+impl<'tcx> FnCtxt<'_, 'tcx> {
+    /// We may in theory add further uses of an opaque after cloning the opaque
+    /// types storage during writeback when computing the defining uses.
+    ///
+    /// Silently ignoring them is dangerous and could result in ICE or even in
+    /// unsoundness, so we make sure we catch such cases here. There's currently
+    /// no known code where this actually happens, even with the new solver which
+    /// does normalize types in writeback after cloning the opaque type storage.
+    ///
+    /// FIXME(@lcnr): I believe this should be possible in theory and would like
+    /// an actual test here. After playing around with this for an hour, I wasn't
+    /// able to do anything which didn't already try to normalize the opaque before
+    /// then, either allowing compilation to succeed or causing an ambiguity error.
+    pub(super) fn detect_opaque_types_added_during_writeback(&self) {
+        let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
+        for (key, hidden_type) in
+            self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
+        {
+            let opaque_type_string = self.tcx.def_path_str(key.def_id);
+            let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
+            self.dcx().span_delayed_bug(hidden_type.span, msg);
+        }
+        let _ = self.take_opaque_types();
+    }
+}
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index 56859eef45f..26be5fc6d19 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -1,10 +1,10 @@
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::ops::Deref;
 
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{self as hir, HirId, HirIdMap, LangItem};
-use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, InferOk, OpaqueTypeStorageEntries, TyCtxtInferExt};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_span::Span;
@@ -37,6 +37,11 @@ pub(crate) struct TypeckRootCtxt<'tcx> {
 
     pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>>,
 
+    // Used to detect opaque types uses added after we've already checked them.
+    //
+    // See [FnCtxt::detect_opaque_types_added_during_writeback] for more details.
+    pub(super) checked_opaque_types_storage_entries: Cell<Option<OpaqueTypeStorageEntries>>,
+
     /// Some additional `Sized` obligations badly affect type inference.
     /// These obligations are added in a later stage of typeck.
     /// Removing these may also cause additional complications, see #101066.
@@ -85,12 +90,14 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
         let infcx =
             tcx.infer_ctxt().ignoring_regions().build(TypingMode::typeck_for_body(tcx, def_id));
         let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
+        let fulfillment_cx = RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx));
 
         TypeckRootCtxt {
-            typeck_results,
-            fulfillment_cx: RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx)),
             infcx,
+            typeck_results,
             locals: RefCell::new(Default::default()),
+            fulfillment_cx,
+            checked_opaque_types_storage_entries: Cell::new(None),
             deferred_sized_obligations: RefCell::new(Vec::new()),
             deferred_call_resolutions: RefCell::new(Default::default()),
             deferred_cast_checks: RefCell::new(Vec::new()),
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 8e7ce83044c..9be041f75d7 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -535,13 +535,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         let tcx = self.tcx();
         // We clone the opaques instead of stealing them here as they are still used for
         // normalization in the next generation trait solver.
-        //
-        // FIXME(-Znext-solver): Opaque types defined after this would simply get dropped
-        // at the end of typeck. While this seems unlikely to happen in practice this
-        // should still get fixed. Either by preventing writeback from defining new opaque
-        // types or by using this function at the end of writeback and running it as a
-        // fixpoint.
         let opaque_types = self.fcx.infcx.clone_opaque_types();
+        let num_entries = self.fcx.inner.borrow_mut().opaque_types().num_entries();
+        let prev = self.fcx.checked_opaque_types_storage_entries.replace(Some(num_entries));
+        debug_assert_eq!(prev, None);
         for (opaque_type_key, hidden_type) in opaque_types {
             let hidden_type = self.resolve(hidden_type, &hidden_type.span);
             let opaque_type_key = self.resolve(opaque_type_key, &hidden_type.span);
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index 22d7ce79bb4..359b9da11ce 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -6,7 +6,10 @@ use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 
-use super::{BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin};
+use super::{
+    BoundRegionConversionTime, InferCtxt, OpaqueTypeStorageEntries, RegionVariableOrigin,
+    SubregionOrigin,
+};
 
 impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
     type Interner = TyCtxt<'tcx>;
@@ -213,4 +216,58 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
     fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>, span: Span) {
         self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(span));
     }
+
+    type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries;
+    fn opaque_types_storage_num_entries(&self) -> OpaqueTypeStorageEntries {
+        self.inner.borrow_mut().opaque_types().num_entries()
+    }
+    fn clone_opaque_types_lookup_table(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
+        self.inner.borrow_mut().opaque_types().iter_lookup_table().map(|(k, h)| (k, h.ty)).collect()
+    }
+    fn clone_duplicate_opaque_types(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
+        self.inner
+            .borrow_mut()
+            .opaque_types()
+            .iter_duplicate_entries()
+            .map(|(k, h)| (k, h.ty))
+            .collect()
+    }
+    fn clone_opaque_types_added_since(
+        &self,
+        prev_entries: OpaqueTypeStorageEntries,
+    ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
+        self.inner
+            .borrow_mut()
+            .opaque_types()
+            .opaque_types_added_since(prev_entries)
+            .map(|(k, h)| (k, h.ty))
+            .collect()
+    }
+
+    fn register_hidden_type_in_storage(
+        &self,
+        opaque_type_key: ty::OpaqueTypeKey<'tcx>,
+        hidden_ty: Ty<'tcx>,
+        span: Span,
+    ) -> Option<Ty<'tcx>> {
+        self.register_hidden_type_in_storage(
+            opaque_type_key,
+            ty::OpaqueHiddenType { span, ty: hidden_ty },
+        )
+    }
+    fn add_duplicate_opaque_type(
+        &self,
+        opaque_type_key: ty::OpaqueTypeKey<'tcx>,
+        hidden_ty: Ty<'tcx>,
+        span: Span,
+    ) {
+        self.inner
+            .borrow_mut()
+            .opaque_types()
+            .add_duplicate(opaque_type_key, ty::OpaqueHiddenType { span, ty: hidden_ty })
+    }
+
+    fn reset_opaque_types(&self) {
+        let _ = self.take_opaque_types();
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 070d285b5a6..b408d76010d 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -9,7 +9,7 @@ use free_regions::RegionRelations;
 pub use freshen::TypeFreshener;
 use lexical_region_resolve::LexicalRegionResolutions;
 pub use lexical_region_resolve::RegionResolutionError;
-use opaque_types::OpaqueTypeStorage;
+pub use opaque_types::{OpaqueTypeStorage, OpaqueTypeStorageEntries, OpaqueTypeTable};
 use region_constraints::{
     GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound,
 };
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index df7144c31da..220d5e9bda2 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -18,7 +18,7 @@ use crate::traits::{self, Obligation, PredicateObligations};
 
 mod table;
 
-pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
+pub use table::{OpaqueTypeStorage, OpaqueTypeStorageEntries, OpaqueTypeTable};
 
 impl<'tcx> InferCtxt<'tcx> {
     /// This is a backwards compatibility hack to prevent breaking changes from
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index 3c5bf9d722b..46752840e1b 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -14,6 +14,16 @@ pub struct OpaqueTypeStorage<'tcx> {
     duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
 }
 
+/// The number of entries in the opaque type storage at a given point.
+///
+/// Used to check that we haven't added any new opaque types after checking
+/// the opaque types currently in the storage.
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
+pub struct OpaqueTypeStorageEntries {
+    opaque_types: usize,
+    duplicate_entries: usize,
+}
+
 impl<'tcx> OpaqueTypeStorage<'tcx> {
     #[instrument(level = "debug")]
     pub(crate) fn remove(
@@ -49,6 +59,24 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
         std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
     }
 
+    pub fn num_entries(&self) -> OpaqueTypeStorageEntries {
+        OpaqueTypeStorageEntries {
+            opaque_types: self.opaque_types.len(),
+            duplicate_entries: self.duplicate_entries.len(),
+        }
+    }
+
+    pub fn opaque_types_added_since(
+        &self,
+        prev_entries: OpaqueTypeStorageEntries,
+    ) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
+        self.opaque_types
+            .iter()
+            .skip(prev_entries.opaque_types)
+            .map(|(k, v)| (*k, *v))
+            .chain(self.duplicate_entries.iter().skip(prev_entries.duplicate_entries).copied())
+    }
+
     /// Only returns the opaque types from the lookup table. These are used
     /// when normalizing opaque types and have a unique key.
     ///
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index 9e8fbd66b70..90a7c2e9f78 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -39,13 +39,6 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
         term: <Self::Interner as Interner>::Term,
     ) -> Option<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>>;
 
-    fn clone_opaque_types_lookup_table(
-        &self,
-    ) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
-    fn clone_duplicate_opaque_types(
-        &self,
-    ) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
-
     fn make_deduplicated_outlives_constraints(
         &self,
     ) -> Vec<ty::OutlivesPredicate<Self::Interner, <Self::Interner as Interner>::GenericArg>>;
@@ -64,20 +57,6 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
         span: <Self::Interner as Interner>::Span,
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> <Self::Interner as Interner>::GenericArg;
-
-    fn register_hidden_type_in_storage(
-        &self,
-        opaque_type_key: ty::OpaqueTypeKey<Self::Interner>,
-        hidden_ty: <Self::Interner as Interner>::Ty,
-        span: <Self::Interner as Interner>::Span,
-    ) -> Option<<Self::Interner as Interner>::Ty>;
-    fn add_duplicate_opaque_type(
-        &self,
-        opaque_type_key: ty::OpaqueTypeKey<Self::Interner>,
-        hidden_ty: <Self::Interner as Interner>::Ty,
-        span: <Self::Interner as Interner>::Span,
-    );
-
     fn add_item_bounds_for_hidden_type(
         &self,
         def_id: <Self::Interner as Interner>::DefId,
@@ -86,7 +65,6 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
         hidden_ty: <Self::Interner as Interner>::Ty,
         goals: &mut Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
     );
-    fn reset_opaque_types(&self);
 
     fn fetch_eligible_assoc_item(
         &self,
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index 65b10e4f23f..f87b1367d6a 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -250,13 +250,7 @@ where
         // to the `var_values`.
         let opaque_types = self
             .delegate
-            .clone_opaque_types_lookup_table()
-            .into_iter()
-            .filter(|(a, _)| {
-                self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
-            })
-            .chain(self.delegate.clone_duplicate_opaque_types())
-            .collect();
+            .clone_opaque_types_added_since(self.initial_opaque_types_storage_num_entries);
 
         ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
     }
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index bf9f21d05f6..c8c914be63b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -23,8 +23,7 @@ use crate::solve::inspect::{self, ProofTreeBuilder};
 use crate::solve::search_graph::SearchGraph;
 use crate::solve::{
     CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource,
-    HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput,
-    QueryResult,
+    HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, QueryResult,
 };
 
 pub(super) mod canonical;
@@ -99,8 +98,6 @@ where
     current_goal_kind: CurrentGoalKind,
     pub(super) var_values: CanonicalVarValues<I>,
 
-    predefined_opaques_in_body: I::PredefinedOpaques,
-
     /// The highest universe index nameable by the caller.
     ///
     /// When we enter a new binder inside of the query we create new universes
@@ -111,6 +108,10 @@ where
     /// if we have a coinductive cycle and because that's the only way we can return
     /// new placeholders to the caller.
     pub(super) max_input_universe: ty::UniverseIndex,
+    /// The opaque types from the canonical input. We only need to return opaque types
+    /// which have been added to the storage while evaluating this goal.
+    pub(super) initial_opaque_types_storage_num_entries:
+        <D::Infcx as InferCtxtLike>::OpaqueTypeStorageEntries,
 
     pub(super) search_graph: &'a mut SearchGraph<D>,
 
@@ -305,10 +306,8 @@ where
 
             // Only relevant when canonicalizing the response,
             // which we don't do within this evaluation context.
-            predefined_opaques_in_body: delegate
-                .cx()
-                .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
             max_input_universe: ty::UniverseIndex::ROOT,
+            initial_opaque_types_storage_num_entries: Default::default(),
             variables: Default::default(),
             var_values: CanonicalVarValues::dummy(),
             current_goal_kind: CurrentGoalKind::Misc,
@@ -342,25 +341,10 @@ where
         canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
         f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
     ) -> R {
-        let (ref delegate, input, var_values) =
-            SolverDelegate::build_with_canonical(cx, &canonical_input);
-
-        let mut ecx = EvalCtxt {
-            delegate,
-            variables: canonical_input.canonical.variables,
-            var_values,
-            current_goal_kind: CurrentGoalKind::from_query_input(cx, input),
-            predefined_opaques_in_body: input.predefined_opaques_in_body,
-            max_input_universe: canonical_input.canonical.max_universe,
-            search_graph,
-            nested_goals: Default::default(),
-            origin_span: I::Span::dummy(),
-            tainted: Ok(()),
-            inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
-        };
+        let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input);
 
         for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
-            let prev = ecx.delegate.register_hidden_type_in_storage(key, ty, ecx.origin_span);
+            let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy());
             // It may be possible that two entries in the opaque type storage end up
             // with the same key after resolving contained inference variables.
             //
@@ -373,13 +357,24 @@ where
             // the canonical input. This is more annoying to implement and may cause a
             // perf regression, so we do it inside of the query for now.
             if let Some(prev) = prev {
-                debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_type_storage`");
+                debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
             }
         }
 
-        if !ecx.nested_goals.is_empty() {
-            panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals);
-        }
+        let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries();
+        let mut ecx = EvalCtxt {
+            delegate,
+            variables: canonical_input.canonical.variables,
+            var_values,
+            current_goal_kind: CurrentGoalKind::from_query_input(cx, input),
+            max_input_universe: canonical_input.canonical.max_universe,
+            initial_opaque_types_storage_num_entries,
+            search_graph,
+            nested_goals: Default::default(),
+            origin_span: I::Span::dummy(),
+            tainted: Ok(()),
+            inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
+        };
 
         let result = f(&mut ecx, input.goal);
         ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe);
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
index 0a9e7fafaea..ed0cedc4077 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
@@ -26,32 +26,33 @@ where
     I: Interner,
 {
     pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T {
-        let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
+        let ProbeCtxt { ecx: outer, probe_kind, _result } = self;
 
-        let delegate = outer_ecx.delegate;
-        let max_input_universe = outer_ecx.max_input_universe;
-        let mut nested_ecx = EvalCtxt {
+        let delegate = outer.delegate;
+        let max_input_universe = outer.max_input_universe;
+        let mut nested = EvalCtxt {
             delegate,
-            variables: outer_ecx.variables,
-            var_values: outer_ecx.var_values,
-            current_goal_kind: outer_ecx.current_goal_kind,
-            predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body,
+            variables: outer.variables,
+            var_values: outer.var_values,
+            current_goal_kind: outer.current_goal_kind,
             max_input_universe,
-            search_graph: outer_ecx.search_graph,
-            nested_goals: outer_ecx.nested_goals.clone(),
-            origin_span: outer_ecx.origin_span,
-            tainted: outer_ecx.tainted,
-            inspect: outer_ecx.inspect.take_and_enter_probe(),
+            initial_opaque_types_storage_num_entries: outer
+                .initial_opaque_types_storage_num_entries,
+            search_graph: outer.search_graph,
+            nested_goals: outer.nested_goals.clone(),
+            origin_span: outer.origin_span,
+            tainted: outer.tainted,
+            inspect: outer.inspect.take_and_enter_probe(),
         };
-        let r = nested_ecx.delegate.probe(|| {
-            let r = f(&mut nested_ecx);
-            nested_ecx.inspect.probe_final_state(delegate, max_input_universe);
+        let r = nested.delegate.probe(|| {
+            let r = f(&mut nested);
+            nested.inspect.probe_final_state(delegate, max_input_universe);
             r
         });
-        if !nested_ecx.inspect.is_noop() {
+        if !nested.inspect.is_noop() {
             let probe_kind = probe_kind(&r);
-            nested_ecx.inspect.probe_kind(probe_kind);
-            outer_ecx.inspect = nested_ecx.inspect.finish_probe();
+            nested.inspect.probe_kind(probe_kind);
+            outer.inspect = nested.inspect.finish_probe();
         }
         r
     }
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 87b8db59a78..3601c2cba9b 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -104,25 +104,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect())
     }
 
-    fn clone_opaque_types_lookup_table(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
-        self.0
-            .inner
-            .borrow_mut()
-            .opaque_types()
-            .iter_lookup_table()
-            .map(|(k, h)| (k, h.ty))
-            .collect()
-    }
-    fn clone_duplicate_opaque_types(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
-        self.0
-            .inner
-            .borrow_mut()
-            .opaque_types()
-            .iter_duplicate_entries()
-            .map(|(k, h)| (k, h.ty))
-            .collect()
-    }
-
     fn make_deduplicated_outlives_constraints(
         &self,
     ) -> Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> {
@@ -168,30 +149,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         self.0.instantiate_canonical_var(span, cv_info, universe_map)
     }
 
-    fn register_hidden_type_in_storage(
-        &self,
-        opaque_type_key: ty::OpaqueTypeKey<'tcx>,
-        hidden_ty: Ty<'tcx>,
-        span: Span,
-    ) -> Option<Ty<'tcx>> {
-        self.0.register_hidden_type_in_storage(
-            opaque_type_key,
-            ty::OpaqueHiddenType { span, ty: hidden_ty },
-        )
-    }
-    fn add_duplicate_opaque_type(
-        &self,
-        opaque_type_key: ty::OpaqueTypeKey<'tcx>,
-        hidden_ty: Ty<'tcx>,
-        span: Span,
-    ) {
-        self.0
-            .inner
-            .borrow_mut()
-            .opaque_types()
-            .add_duplicate(opaque_type_key, ty::OpaqueHiddenType { span, ty: hidden_ty })
-    }
-
     fn add_item_bounds_for_hidden_type(
         &self,
         def_id: DefId,
@@ -203,10 +160,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals);
     }
 
-    fn reset_opaque_types(&self) {
-        let _ = self.take_opaque_types();
-    }
-
     fn fetch_eligible_assoc_item(
         &self,
         goal_trait_ref: ty::TraitRef<'tcx>,
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 7d2654de440..c1490762117 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -1,3 +1,5 @@
+use std::fmt::Debug;
+
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
@@ -245,4 +247,32 @@ pub trait InferCtxtLike: Sized {
         r: <Self::Interner as Interner>::Region,
         span: <Self::Interner as Interner>::Span,
     );
+
+    type OpaqueTypeStorageEntries: Debug + Copy + Default;
+    fn opaque_types_storage_num_entries(&self) -> Self::OpaqueTypeStorageEntries;
+    fn clone_opaque_types_lookup_table(
+        &self,
+    ) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
+    fn clone_duplicate_opaque_types(
+        &self,
+    ) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
+    fn clone_opaque_types_added_since(
+        &self,
+        prev_entries: Self::OpaqueTypeStorageEntries,
+    ) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
+
+    fn register_hidden_type_in_storage(
+        &self,
+        opaque_type_key: ty::OpaqueTypeKey<Self::Interner>,
+        hidden_ty: <Self::Interner as Interner>::Ty,
+        span: <Self::Interner as Interner>::Span,
+    ) -> Option<<Self::Interner as Interner>::Ty>;
+    fn add_duplicate_opaque_type(
+        &self,
+        opaque_type_key: ty::OpaqueTypeKey<Self::Interner>,
+        hidden_ty: <Self::Interner as Interner>::Ty,
+        span: <Self::Interner as Interner>::Span,
+    );
+
+    fn reset_opaque_types(&self);
 }