about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs1
-rw-r--r--compiler/rustc_infer/src/infer/context.rs69
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs245
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/lattice.rs1
-rw-r--r--compiler/rustc_infer/src/infer/relate/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/relate/type_relating.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/lib.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/relate.rs15
-rw-r--r--compiler/rustc_next_trait_solver/src/relate/combine.rs34
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs37
-rw-r--r--compiler/rustc_type_ir/src/relate.rs14
-rw-r--r--compiler/rustc_type_ir/src/relate/combine.rs255
13 files changed, 376 insertions, 305 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index bf079e813f1..e72c21e8fad 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -11,6 +11,7 @@ use rustc_middle::span_bug;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::relate::combine::InferCtxtCombineExt;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index c06836edcfb..10b22c98a0d 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -1,22 +1,27 @@
 ///! Definition of `InferCtxtLike` from the librarified type layer.
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode};
 use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
+use rustc_middle::ty::relate::{Relate, RelateResult};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::DUMMY_SP;
-use rustc_type_ir::InferCtxtLike;
-use rustc_type_ir::relate::Relate;
+use rustc_span::{DUMMY_SP, ErrorGuaranteed};
 
 use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
 
-impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
+impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
     type Interner = TyCtxt<'tcx>;
 
     fn cx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
+    fn next_trait_solver(&self) -> bool {
+        self.next_trait_solver
+    }
+
     fn solver_mode(&self) -> ty::solve::SolverMode {
         match self.intercrate {
             true => SolverMode::Coherence,
@@ -131,6 +136,59 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
         self.enter_forall(value, f)
     }
 
+    fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) {
+        self.inner.borrow_mut().int_unification_table().union(a, b);
+    }
+
+    fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) {
+        self.inner.borrow_mut().float_unification_table().union(a, b);
+    }
+
+    fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) {
+        self.inner.borrow_mut().const_unification_table().union(a, b);
+    }
+
+    fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) {
+        self.inner.borrow_mut().effect_unification_table().union(a, b);
+    }
+
+    fn instantiate_int_var_raw(
+        &self,
+        vid: rustc_type_ir::IntVid,
+        value: rustc_type_ir::IntVarValue,
+    ) {
+        self.inner.borrow_mut().int_unification_table().union_value(vid, value);
+    }
+
+    fn instantiate_float_var_raw(
+        &self,
+        vid: rustc_type_ir::FloatVid,
+        value: rustc_type_ir::FloatVarValue,
+    ) {
+        self.inner.borrow_mut().float_unification_table().union_value(vid, value);
+    }
+
+    fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) {
+        self.inner
+            .borrow_mut()
+            .effect_unification_table()
+            .union_value(vid, EffectVarValue::Known(value));
+    }
+
+    fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
+        &self,
+        relation: &mut R,
+        target_is_expected: bool,
+        target_vid: rustc_type_ir::ConstVid,
+        source_ct: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ()> {
+        self.instantiate_const_var(relation, target_is_expected, target_vid, source_ct)
+    }
+
+    fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
+        self.set_tainted_by_errors(e)
+    }
+
     fn relate<T: Relate<TyCtxt<'tcx>>>(
         &self,
         param_env: ty::ParamEnv<'tcx>,
@@ -154,6 +212,9 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
     fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
         self.shallow_resolve(ty)
     }
+    fn shallow_resolve_const(&self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        self.shallow_resolve_const(ct)
+    }
 
     fn resolve_vars_if_possible<T>(&self, value: T) -> T
     where
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
deleted file mode 100644
index f879fbc5578..00000000000
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ /dev/null
@@ -1,245 +0,0 @@
-//! There are four type combiners: `TypeRelating`, `Lub`, and `Glb`,
-//! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL.
-//!
-//! Each implements the trait [TypeRelation] and contains methods for
-//! combining two instances of various things and yielding a new instance.
-//! These combiner methods always yield a `Result<T>`. To relate two
-//! types, you can use `infcx.at(cause, param_env)` which then allows
-//! you to use the relevant methods of [At](crate::infer::at::At).
-//!
-//! Combiners mostly do their specific behavior and then hand off the
-//! bulk of the work to [InferCtxt::super_combine_tys] and
-//! [InferCtxt::super_combine_consts].
-//!
-//! Combining two types may have side-effects on the inference contexts
-//! which can be undone by using snapshots. You probably want to use
-//! either [InferCtxt::commit_if_ok] or [InferCtxt::probe].
-//!
-//! On success, the  LUB/GLB operations return the appropriate bound. The
-//! return value of `Equate` or `Sub` shouldn't really be used.
-
-use rustc_middle::bug;
-use rustc_middle::infer::unify_key::EffectVarValue;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, InferConst, IntType, Ty, TypeVisitableExt, UintType};
-pub use rustc_next_trait_solver::relate::combine::*;
-use tracing::debug;
-
-use super::{RelateResult, StructurallyRelateAliases};
-use crate::infer::{InferCtxt, relate};
-
-impl<'tcx> InferCtxt<'tcx> {
-    pub fn super_combine_tys<R>(
-        &self,
-        relation: &mut R,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
-    ) -> RelateResult<'tcx, Ty<'tcx>>
-    where
-        R: PredicateEmittingRelation<InferCtxt<'tcx>>,
-    {
-        debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
-        debug_assert!(!a.has_escaping_bound_vars());
-        debug_assert!(!b.has_escaping_bound_vars());
-
-        match (a.kind(), b.kind()) {
-            (&ty::Error(e), _) | (_, &ty::Error(e)) => {
-                self.set_tainted_by_errors(e);
-                return Ok(Ty::new_error(self.tcx, e));
-            }
-
-            // Relate integral variables to other types
-            (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => {
-                self.inner.borrow_mut().int_unification_table().union(a_id, b_id);
-                Ok(a)
-            }
-            (&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => {
-                self.unify_integral_variable(v_id, IntType(v));
-                Ok(b)
-            }
-            (&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => {
-                self.unify_integral_variable(v_id, IntType(v));
-                Ok(a)
-            }
-            (&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => {
-                self.unify_integral_variable(v_id, UintType(v));
-                Ok(b)
-            }
-            (&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => {
-                self.unify_integral_variable(v_id, UintType(v));
-                Ok(a)
-            }
-
-            // Relate floating-point variables to other types
-            (&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => {
-                self.inner.borrow_mut().float_unification_table().union(a_id, b_id);
-                Ok(a)
-            }
-            (&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
-                self.unify_float_variable(v_id, ty::FloatVarValue::Known(v));
-                Ok(b)
-            }
-            (&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => {
-                self.unify_float_variable(v_id, ty::FloatVarValue::Known(v));
-                Ok(a)
-            }
-
-            // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
-            (ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..))
-                if self.next_trait_solver() =>
-            {
-                bug!(
-                    "We do not expect to encounter `TyVar` this late in combine \
-                    -- they should have been handled earlier"
-                )
-            }
-            (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)))
-            | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _)
-                if self.next_trait_solver() =>
-            {
-                bug!("We do not expect to encounter `Fresh` variables in the new solver")
-            }
-
-            (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => {
-                match relation.structurally_relate_aliases() {
-                    StructurallyRelateAliases::Yes => {
-                        relate::structurally_relate_tys(relation, a, b)
-                    }
-                    StructurallyRelateAliases::No => {
-                        relation.register_alias_relate_predicate(a, b);
-                        Ok(a)
-                    }
-                }
-            }
-
-            // All other cases of inference are errors
-            (&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
-                Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
-            }
-
-            // During coherence, opaque types should be treated as *possibly*
-            // equal to any other type (except for possibly itself). This is an
-            // extremely heavy hammer, but can be relaxed in a forwards-compatible
-            // way later.
-            (&ty::Alias(ty::Opaque, _), _) | (_, &ty::Alias(ty::Opaque, _)) if self.intercrate => {
-                relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
-                Ok(a)
-            }
-
-            _ => relate::structurally_relate_tys(relation, a, b),
-        }
-    }
-
-    pub fn super_combine_consts<R>(
-        &self,
-        relation: &mut R,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>>
-    where
-        R: PredicateEmittingRelation<InferCtxt<'tcx>>,
-    {
-        debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
-        debug_assert!(!a.has_escaping_bound_vars());
-        debug_assert!(!b.has_escaping_bound_vars());
-
-        if a == b {
-            return Ok(a);
-        }
-
-        let a = self.shallow_resolve_const(a);
-        let b = self.shallow_resolve_const(b);
-
-        match (a.kind(), b.kind()) {
-            (
-                ty::ConstKind::Infer(InferConst::Var(a_vid)),
-                ty::ConstKind::Infer(InferConst::Var(b_vid)),
-            ) => {
-                self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid);
-                Ok(a)
-            }
-
-            (
-                ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
-                ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
-            ) => {
-                self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid);
-                Ok(a)
-            }
-
-            // All other cases of inference with other variables are errors.
-            (
-                ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
-                ty::ConstKind::Infer(_),
-            )
-            | (
-                ty::ConstKind::Infer(_),
-                ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
-            ) => {
-                bug!(
-                    "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
-                )
-            }
-
-            (ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
-                self.instantiate_const_var(relation, true, vid, b)?;
-                Ok(b)
-            }
-
-            (_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
-                self.instantiate_const_var(relation, false, vid, a)?;
-                Ok(a)
-            }
-
-            (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
-                Ok(self.unify_effect_variable(vid, b))
-            }
-
-            (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
-                Ok(self.unify_effect_variable(vid, a))
-            }
-
-            (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
-                if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
-            {
-                match relation.structurally_relate_aliases() {
-                    StructurallyRelateAliases::No => {
-                        relation.register_predicates([if self.next_trait_solver() {
-                            ty::PredicateKind::AliasRelate(
-                                a.into(),
-                                b.into(),
-                                ty::AliasRelationDirection::Equate,
-                            )
-                        } else {
-                            ty::PredicateKind::ConstEquate(a, b)
-                        }]);
-
-                        Ok(b)
-                    }
-                    StructurallyRelateAliases::Yes => {
-                        relate::structurally_relate_consts(relation, a, b)
-                    }
-                }
-            }
-            _ => relate::structurally_relate_consts(relation, a, b),
-        }
-    }
-
-    #[inline(always)]
-    fn unify_integral_variable(&self, vid: ty::IntVid, val: ty::IntVarValue) {
-        self.inner.borrow_mut().int_unification_table().union_value(vid, val);
-    }
-
-    #[inline(always)]
-    fn unify_float_variable(&self, vid: ty::FloatVid, val: ty::FloatVarValue) {
-        self.inner.borrow_mut().float_unification_table().union_value(vid, val);
-    }
-
-    fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        self.inner
-            .borrow_mut()
-            .effect_unification_table()
-            .union_value(vid, EffectVarValue::Known(val));
-        val
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 726a2296d11..7049444db9b 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -183,7 +183,7 @@ impl<'tcx> InferCtxt<'tcx> {
     ///
     /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
     #[instrument(level = "debug", skip(self, relation))]
-    pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
+    pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
         &self,
         relation: &mut R,
         target_is_expected: bool,
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index 8cec312abf7..fc208a08471 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -18,6 +18,7 @@
 //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
 use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::combine::InferCtxtCombineExt;
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
 use rustc_span::Span;
diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs
index baab5bb274a..e156f72d78d 100644
--- a/compiler/rustc_infer/src/infer/relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/relate/mod.rs
@@ -3,12 +3,10 @@
 //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
 
 pub use rustc_middle::ty::relate::RelateResult;
-pub use rustc_next_trait_solver::relate::*;
-
-pub use self::combine::PredicateEmittingRelation;
+pub use rustc_type_ir::relate::combine::PredicateEmittingRelation;
+pub use rustc_type_ir::relate::*;
 
 #[allow(hidden_glob_reexports)]
-pub(super) mod combine;
 mod generalize;
 mod higher_ranked;
 pub(super) mod lattice;
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index d99acabb825..d2dc4589103 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -1,4 +1,5 @@
 use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::combine::InferCtxtCombineExt;
 use rustc_middle::ty::relate::{
     Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
 };
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs
index ca140500e2c..de74ac32804 100644
--- a/compiler/rustc_next_trait_solver/src/lib.rs
+++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -12,6 +12,5 @@
 pub mod canonicalizer;
 pub mod coherence;
 pub mod delegate;
-pub mod relate;
 pub mod resolve;
 pub mod solve;
diff --git a/compiler/rustc_next_trait_solver/src/relate.rs b/compiler/rustc_next_trait_solver/src/relate.rs
deleted file mode 100644
index db819961bbd..00000000000
--- a/compiler/rustc_next_trait_solver/src/relate.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-pub use rustc_type_ir::relate::*;
-
-pub mod combine;
-
-/// Whether aliases should be related structurally or not. Used
-/// to adjust the behavior of generalization and combine.
-///
-/// This should always be `No` unless in a few special-cases when
-/// instantiating canonical responses and in the new solver. Each
-/// such case should have a comment explaining why it is used.
-#[derive(Debug, Copy, Clone)]
-pub enum StructurallyRelateAliases {
-    Yes,
-    No,
-}
diff --git a/compiler/rustc_next_trait_solver/src/relate/combine.rs b/compiler/rustc_next_trait_solver/src/relate/combine.rs
deleted file mode 100644
index 96968327d8e..00000000000
--- a/compiler/rustc_next_trait_solver/src/relate/combine.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-pub use rustc_type_ir::relate::*;
-use rustc_type_ir::solve::Goal;
-use rustc_type_ir::{InferCtxtLike, Interner, Upcast};
-
-use super::StructurallyRelateAliases;
-
-pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
-    TypeRelation<I>
-where
-    Infcx: InferCtxtLike<Interner = I>,
-    I: Interner,
-{
-    fn span(&self) -> I::Span;
-
-    fn param_env(&self) -> I::ParamEnv;
-
-    /// Whether aliases should be related structurally. This is pretty much
-    /// always `No` unless you're equating in some specific locations of the
-    /// new solver. See the comments in these use-cases for more details.
-    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
-
-    /// Register obligations that must hold in order for this relation to hold
-    fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
-
-    /// Register predicates that must hold in order for this relation to hold.
-    /// This uses the default `param_env` of the obligation.
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
-    );
-
-    /// Register `AliasRelate` obligation(s) that both types must be related to each other.
-    fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
-}
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 1d0b2345b80..2f6476c6e23 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -1,5 +1,6 @@
 use crate::fold::TypeFoldable;
-use crate::relate::Relate;
+use crate::relate::combine::PredicateEmittingRelation;
+use crate::relate::{Relate, RelateResult};
 use crate::solve::{Goal, NoSolution, SolverMode};
 use crate::{self as ty, Interner};
 
@@ -7,6 +8,14 @@ pub trait InferCtxtLike: Sized {
     type Interner: Interner;
     fn cx(&self) -> Self::Interner;
 
+    /// Whether the new trait solver is enabled. This only exists because rustc
+    /// shares code between the new and old trait solvers; for all other users,
+    /// this should always be true. If this is unknowingly false and you try to
+    /// use the new trait solver, things will break badly.
+    fn next_trait_solver(&self) -> bool {
+        true
+    }
+
     fn solver_mode(&self) -> SolverMode;
 
     fn universe(&self) -> ty::UniverseIndex;
@@ -58,6 +67,28 @@ pub trait InferCtxtLike: Sized {
         f: impl FnOnce(T) -> U,
     ) -> U;
 
+    fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
+    fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
+    fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);
+    fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid);
+
+    fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue);
+    fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue);
+    fn instantiate_effect_var_raw(
+        &self,
+        vid: ty::EffectVid,
+        value: <Self::Interner as Interner>::Const,
+    );
+    fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
+        &self,
+        relation: &mut R,
+        target_is_expected: bool,
+        target_vid: ty::ConstVid,
+        source_ct: <Self::Interner as Interner>::Const,
+    ) -> RelateResult<Self::Interner, ()>;
+
+    fn set_tainted_by_errors(&self, e: <Self::Interner as Interner>::ErrorGuaranteed);
+
     fn relate<T: Relate<Self::Interner>>(
         &self,
         param_env: <Self::Interner as Interner>::ParamEnv,
@@ -77,6 +108,10 @@ pub trait InferCtxtLike: Sized {
         &self,
         ty: <Self::Interner as Interner>::Ty,
     ) -> <Self::Interner as Interner>::Ty;
+    fn shallow_resolve_const(
+        &self,
+        ty: <Self::Interner as Interner>::Const,
+    ) -> <Self::Interner as Interner>::Const;
 
     fn resolve_vars_if_possible<T>(&self, value: T) -> T
     where
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index 9c725f34d8e..8e5d917e915 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -9,8 +9,22 @@ use crate::fold::TypeFoldable;
 use crate::inherent::*;
 use crate::{self as ty, Interner};
 
+pub mod combine;
+
 pub type RelateResult<I, T> = Result<T, TypeError<I>>;
 
+/// Whether aliases should be related structurally or not. Used
+/// to adjust the behavior of generalization and combine.
+///
+/// This should always be `No` unless in a few special-cases when
+/// instantiating canonical responses and in the new solver. Each
+/// such case should have a comment explaining why it is used.
+#[derive(Debug, Copy, Clone)]
+pub enum StructurallyRelateAliases {
+    Yes,
+    No,
+}
+
 /// Extra information about why we ended up with a particular variance.
 /// This is only used to add more information to error messages, and
 /// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
new file mode 100644
index 00000000000..9dfcde609c7
--- /dev/null
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -0,0 +1,255 @@
+use tracing::debug;
+
+use super::{
+    ExpectedFound, RelateResult, StructurallyRelateAliases, TypeRelation,
+    structurally_relate_consts, structurally_relate_tys,
+};
+use crate::error::TypeError;
+use crate::inherent::*;
+use crate::solve::{Goal, SolverMode};
+use crate::visit::TypeVisitableExt as _;
+use crate::{self as ty, InferCtxtLike, Interner, Upcast};
+
+pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
+    TypeRelation<I>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    fn span(&self) -> I::Span;
+
+    fn param_env(&self) -> I::ParamEnv;
+
+    /// Whether aliases should be related structurally. This is pretty much
+    /// always `No` unless you're equating in some specific locations of the
+    /// new solver. See the comments in these use-cases for more details.
+    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
+
+    /// Register obligations that must hold in order for this relation to hold
+    fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
+
+    /// Register predicates that must hold in order for this relation to hold.
+    /// This uses the default `param_env` of the obligation.
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
+    );
+
+    /// Register `AliasRelate` obligation(s) that both types must be related to each other.
+    fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
+}
+
+pub trait InferCtxtCombineExt<I: Interner>: InferCtxtLike {
+    fn super_combine_tys<R>(&self, relation: &mut R, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>
+    where
+        R: PredicateEmittingRelation<Self>;
+
+    fn super_combine_consts<R>(
+        &self,
+        relation: &mut R,
+        a: I::Const,
+        b: I::Const,
+    ) -> RelateResult<I, I::Const>
+    where
+        R: PredicateEmittingRelation<Self>;
+}
+
+impl<I: Interner, Infcx: InferCtxtLike<Interner = I>> InferCtxtCombineExt<I> for Infcx {
+    fn super_combine_tys<R>(&self, relation: &mut R, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>
+    where
+        R: PredicateEmittingRelation<Infcx>,
+    {
+        debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
+        debug_assert!(!a.has_escaping_bound_vars());
+        debug_assert!(!b.has_escaping_bound_vars());
+
+        match (a.kind(), b.kind()) {
+            (ty::Error(e), _) | (_, ty::Error(e)) => {
+                self.set_tainted_by_errors(e);
+                return Ok(Ty::new_error(self.cx(), e));
+            }
+
+            // Relate integral variables to other types
+            (ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => {
+                self.equate_int_vids_raw(a_id, b_id);
+                Ok(a)
+            }
+            (ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => {
+                self.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
+                Ok(b)
+            }
+            (ty::Int(v), ty::Infer(ty::IntVar(v_id))) => {
+                self.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
+                Ok(a)
+            }
+            (ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => {
+                self.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
+                Ok(b)
+            }
+            (ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => {
+                self.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
+                Ok(a)
+            }
+
+            // Relate floating-point variables to other types
+            (ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => {
+                self.equate_float_vids_raw(a_id, b_id);
+                Ok(a)
+            }
+            (ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => {
+                self.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
+                Ok(b)
+            }
+            (ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => {
+                self.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
+                Ok(a)
+            }
+
+            // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
+            (ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..))
+                if self.next_trait_solver() =>
+            {
+                panic!(
+                    "We do not expect to encounter `TyVar` this late in combine \
+                    -- they should have been handled earlier"
+                )
+            }
+            (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)))
+            | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _)
+                if self.next_trait_solver() =>
+            {
+                panic!("We do not expect to encounter `Fresh` variables in the new solver")
+            }
+
+            (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => {
+                match relation.structurally_relate_aliases() {
+                    StructurallyRelateAliases::Yes => structurally_relate_tys(relation, a, b),
+                    StructurallyRelateAliases::No => {
+                        relation.register_alias_relate_predicate(a, b);
+                        Ok(a)
+                    }
+                }
+            }
+
+            // All other cases of inference are errors
+            (ty::Infer(_), _) | (_, ty::Infer(_)) => {
+                Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
+            }
+
+            (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => {
+                match self.solver_mode() {
+                    SolverMode::Normal => {
+                        assert!(!self.next_trait_solver());
+                        structurally_relate_tys(relation, a, b)
+                    }
+                    // During coherence, opaque types should be treated as *possibly*
+                    // equal to any other type (except for possibly itself). This is an
+                    // extremely heavy hammer, but can be relaxed in a forwards-compatible
+                    // way later.
+                    SolverMode::Coherence => {
+                        relation
+                            .register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
+                        Ok(a)
+                    }
+                }
+            }
+
+            _ => structurally_relate_tys(relation, a, b),
+        }
+    }
+
+    fn super_combine_consts<R>(
+        &self,
+        relation: &mut R,
+        a: I::Const,
+        b: I::Const,
+    ) -> RelateResult<I, I::Const>
+    where
+        R: PredicateEmittingRelation<Infcx>,
+    {
+        debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
+        debug_assert!(!a.has_escaping_bound_vars());
+        debug_assert!(!b.has_escaping_bound_vars());
+
+        if a == b {
+            return Ok(a);
+        }
+
+        let a = self.shallow_resolve_const(a);
+        let b = self.shallow_resolve_const(b);
+
+        match (a.kind(), b.kind()) {
+            (
+                ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
+                ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
+            ) => {
+                self.equate_const_vids_raw(a_vid, b_vid);
+                Ok(a)
+            }
+
+            (
+                ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)),
+                ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)),
+            ) => {
+                self.equate_effect_vids_raw(a_vid, b_vid);
+                Ok(a)
+            }
+
+            // All other cases of inference with other variables are errors.
+            (
+                ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
+                ty::ConstKind::Infer(_),
+            )
+            | (
+                ty::ConstKind::Infer(_),
+                ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
+            ) => {
+                panic!(
+                    "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
+                )
+            }
+
+            (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => {
+                self.instantiate_const_var_raw(relation, true, vid, b)?;
+                Ok(b)
+            }
+
+            (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => {
+                self.instantiate_const_var_raw(relation, false, vid, a)?;
+                Ok(a)
+            }
+
+            (ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => {
+                self.instantiate_effect_var_raw(vid, b);
+                Ok(b)
+            }
+
+            (_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => {
+                self.instantiate_effect_var_raw(vid, a);
+                Ok(a)
+            }
+
+            (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
+                if self.cx().features().generic_const_exprs() || self.next_trait_solver() =>
+            {
+                match relation.structurally_relate_aliases() {
+                    StructurallyRelateAliases::No => {
+                        relation.register_predicates([if self.next_trait_solver() {
+                            ty::PredicateKind::AliasRelate(
+                                a.into(),
+                                b.into(),
+                                ty::AliasRelationDirection::Equate,
+                            )
+                        } else {
+                            ty::PredicateKind::ConstEquate(a, b)
+                        }]);
+
+                        Ok(b)
+                    }
+                    StructurallyRelateAliases::Yes => structurally_relate_consts(relation, a, b),
+                }
+            }
+            _ => structurally_relate_consts(relation, a, b),
+        }
+    }
+}