From 5a6bffb2d778a58fd3bfee890aed8597a447510a Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Thu, 8 Oct 2026 10:34:01 +0100 Subject: [PATCH 1/3] Copy over some methods from At to InferCtxt --- compiler/rustc_infer/src/infer/at.rs | 140 ++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 6a34bd4884d73..f2059654c89eb 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -27,7 +27,7 @@ use relate::lattice::{LatticeOp, LatticeOpKind}; use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate; -use rustc_middle::ty::{Const, TypingMode}; +use rustc_middle::ty::{Const, ParamEnv, TypingMode}; use rustc_span::bug; use super::*; @@ -124,6 +124,144 @@ impl<'tcx> InferCtxt<'tcx> { forked.inner.borrow_mut().projection_cache().clear(); forked } + + /// Makes `actual <: expected`. For example, if type-checking a + /// call like `foo(x)`, where `foo: fn(i32)`, you might have + /// `sup(i32, x)`, since the "expected" type is the type that + /// appears in the signature. + pub fn sup( + self, + cause: &ObligationCause<'tcx>, + param_env: ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: ToTrace<'tcx>, + { + if self.next_trait_solver { + NextSolverRelate::relate( + &self, + param_env, + expected, + ty::Contravariant, + actual, + cause.span, + ) + .map(|goals| self.at(&cause, param_env).goals_to_obligations(goals)) + } else { + let mut op = TypeRelating::new( + &self, + ToTrace::to_trace(&cause, expected, actual), + param_env, + define_opaque_types, + ty::Contravariant, + ); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) + } + } + + /// Makes `expected <: actual`. + pub fn sub( + self, + cause: &ObligationCause<'tcx>, + param_env: ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: ToTrace<'tcx>, + { + if self.next_trait_solver { + NextSolverRelate::relate(&self, param_env, expected, ty::Covariant, actual, cause.span) + .map(|goals| self.at(&cause, param_env).goals_to_obligations(goals)) + } else { + let mut op = TypeRelating::new( + &self, + ToTrace::to_trace(&cause, expected, actual), + param_env, + define_opaque_types, + ty::Covariant, + ); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) + } + } + + /// Makes `expected == actual`. + pub fn eq( + self, + cause: &ObligationCause<'tcx>, + param_env: ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: ToTrace<'tcx>, + { + self.eq_trace( + cause, + param_env, + define_opaque_types, + ToTrace::to_trace(cause, expected, actual), + expected, + actual, + ) + } + + /// Makes `expected == actual`. + pub fn eq_trace( + self, + cause: &ObligationCause<'tcx>, + param_env: ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + trace: TypeTrace<'tcx>, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: Relate>, + { + if self.next_trait_solver { + NextSolverRelate::relate(&self, param_env, expected, ty::Invariant, actual, cause.span) + .map(|goals| self.at(&cause, param_env).goals_to_obligations(goals)) + } else { + let mut op = + TypeRelating::new(&self, trace, param_env, define_opaque_types, ty::Invariant); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) + } + } + + pub fn relate( + self, + cause: &ObligationCause<'tcx>, + param_env: ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + expected: T, + variance: ty::Variance, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: ToTrace<'tcx>, + { + match variance { + ty::Covariant => self.sub(cause, param_env, define_opaque_types, expected, actual), + ty::Invariant => self.eq(cause, param_env, define_opaque_types, expected, actual), + ty::Contravariant => self.sup(cause, param_env, define_opaque_types, expected, actual), + + // We could make this make sense but it's not readily + // exposed and I don't feel like dealing with it. Note + // that bivariance in general does a bit more than just + // *nothing*, it checks that the types are the same + // "modulo variance" basically. + ty::Bivariant => panic!("Bivariant given to `relate()`"), + } + } } pub trait ToTrace<'tcx>: Relate> + Copy { From 8880c1bd8f08992e9fbb7958b55be2fe2e56bc96 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 12 Oct 2026 09:11:46 +0100 Subject: [PATCH 2/3] Call into for the bodies of the methods to avoid repeating behaviour too early --- compiler/rustc_infer/src/infer/at.rs | 60 ++-------------------------- 1 file changed, 4 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index f2059654c89eb..2bfebe2b26d73 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -140,27 +140,7 @@ impl<'tcx> InferCtxt<'tcx> { where T: ToTrace<'tcx>, { - if self.next_trait_solver { - NextSolverRelate::relate( - &self, - param_env, - expected, - ty::Contravariant, - actual, - cause.span, - ) - .map(|goals| self.at(&cause, param_env).goals_to_obligations(goals)) - } else { - let mut op = TypeRelating::new( - &self, - ToTrace::to_trace(&cause, expected, actual), - param_env, - define_opaque_types, - ty::Contravariant, - ); - op.relate(expected, actual)?; - Ok(InferOk { value: (), obligations: op.into_obligations() }) - } + self.at(cause, param_env).sup(define_opaque_types, expected, actual) } /// Makes `expected <: actual`. @@ -175,20 +155,7 @@ impl<'tcx> InferCtxt<'tcx> { where T: ToTrace<'tcx>, { - if self.next_trait_solver { - NextSolverRelate::relate(&self, param_env, expected, ty::Covariant, actual, cause.span) - .map(|goals| self.at(&cause, param_env).goals_to_obligations(goals)) - } else { - let mut op = TypeRelating::new( - &self, - ToTrace::to_trace(&cause, expected, actual), - param_env, - define_opaque_types, - ty::Covariant, - ); - op.relate(expected, actual)?; - Ok(InferOk { value: (), obligations: op.into_obligations() }) - } + self.at(cause, param_env).sub(define_opaque_types, expected, actual) } /// Makes `expected == actual`. @@ -226,15 +193,7 @@ impl<'tcx> InferCtxt<'tcx> { where T: Relate>, { - if self.next_trait_solver { - NextSolverRelate::relate(&self, param_env, expected, ty::Invariant, actual, cause.span) - .map(|goals| self.at(&cause, param_env).goals_to_obligations(goals)) - } else { - let mut op = - TypeRelating::new(&self, trace, param_env, define_opaque_types, ty::Invariant); - op.relate(expected, actual)?; - Ok(InferOk { value: (), obligations: op.into_obligations() }) - } + self.at(cause, param_env).eq_trace(define_opaque_types, trace, expected, actual) } pub fn relate( @@ -249,18 +208,7 @@ impl<'tcx> InferCtxt<'tcx> { where T: ToTrace<'tcx>, { - match variance { - ty::Covariant => self.sub(cause, param_env, define_opaque_types, expected, actual), - ty::Invariant => self.eq(cause, param_env, define_opaque_types, expected, actual), - ty::Contravariant => self.sup(cause, param_env, define_opaque_types, expected, actual), - - // We could make this make sense but it's not readily - // exposed and I don't feel like dealing with it. Note - // that bivariance in general does a bit more than just - // *nothing*, it checks that the types are the same - // "modulo variance" basically. - ty::Bivariant => panic!("Bivariant given to `relate()`"), - } + self.at(cause, param_env).relate(define_opaque_types, expected, variance, actual) } } From 031d65a6e802798b83b6206f78dbbe9eb35bcdef Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 12 Oct 2026 12:51:20 +0100 Subject: [PATCH 3/3] Re-directions in doc comments + _raw prefix --- compiler/rustc_infer/src/infer/at.rs | 75 +++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 2bfebe2b26d73..16c6fed9e9a42 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -129,7 +129,10 @@ impl<'tcx> InferCtxt<'tcx> { /// call like `foo(x)`, where `foo: fn(i32)`, you might have /// `sup(i32, x)`, since the "expected" type is the type that /// appears in the signature. - pub fn sup( + /// + /// If possible, prefer the wrapper methods on `ObligationCtxt`, + /// `FnCtxt`, or `TypeChecker`. + pub fn sup_raw( self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, @@ -144,7 +147,10 @@ impl<'tcx> InferCtxt<'tcx> { } /// Makes `expected <: actual`. - pub fn sub( + /// + /// If possible, prefer the wrapper methods on `ObligationCtxt`, + /// `FnCtxt`, or `TypeChecker`. + pub fn sub_raw( self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, @@ -159,7 +165,10 @@ impl<'tcx> InferCtxt<'tcx> { } /// Makes `expected == actual`. - pub fn eq( + /// + /// If possible, prefer the wrapper methods on `ObligationCtxt`, + /// `FnCtxt`, or `TypeChecker`. + pub fn eq_raw( self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, @@ -170,7 +179,7 @@ impl<'tcx> InferCtxt<'tcx> { where T: ToTrace<'tcx>, { - self.eq_trace( + self.eq_trace_raw( cause, param_env, define_opaque_types, @@ -181,7 +190,10 @@ impl<'tcx> InferCtxt<'tcx> { } /// Makes `expected == actual`. - pub fn eq_trace( + /// + /// If possible, prefer the wrapper methods on `ObligationCtxt`, + /// `FnCtxt`, or `TypeChecker`. + pub fn eq_trace_raw( self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, @@ -196,7 +208,9 @@ impl<'tcx> InferCtxt<'tcx> { self.at(cause, param_env).eq_trace(define_opaque_types, trace, expected, actual) } - pub fn relate( + /// If possible, prefer the wrapper methods on `ObligationCtxt`, + /// `FnCtxt`, or `TypeChecker`. + pub fn relate_raw( self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, @@ -210,6 +224,43 @@ impl<'tcx> InferCtxt<'tcx> { { self.at(cause, param_env).relate(define_opaque_types, expected, variance, actual) } + + /// Computes the least-upper-bound, or mutual supertype, of two + /// values. The order of the arguments doesn't matter, but since + /// this can result in an error (e.g., if asked to compute LUB of + /// u32 and i32), it is meaningful to call one of them the + /// "expected type". + /// + /// If possible, prefer the wrapper methods on `ObligationCtxt`, + /// `FnCtxt`, or `TypeChecker`. + pub fn lub_raw( + self, + cause: &ObligationCause<'tcx>, + param_env: ParamEnv<'tcx>, + expected: T, + actual: T, + ) -> InferResult<'tcx, T> + where + T: ToTrace<'tcx>, + { + self.at(cause, param_env).lub(expected, actual) + } + + pub fn goals_to_obligations( + &self, + cause: &ObligationCause<'tcx>, + goals: Vec>>, + ) -> InferOk<'tcx, ()> { + InferOk { + value: (), + obligations: goals + .into_iter() + .map(|goal| { + Obligation::new(self.tcx, cause.clone(), goal.param_env, goal.predicate) + }) + .collect(), + } + } } pub trait ToTrace<'tcx>: Relate> + Copy { @@ -221,6 +272,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// call like `foo(x)`, where `foo: fn(i32)`, you might have /// `sup(i32, x)`, since the "expected" type is the type that /// appears in the signature. + /// + /// FIXME: To be removed in favor of the [`InferCtxt::sup_raw`] method instead. pub fn sup( self, define_opaque_types: DefineOpaqueTypes, @@ -254,6 +307,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { } /// Makes `expected <: actual`. + /// + /// FIXME: To be removed in favor of the [`InferCtxt::sub_raw`] method instead. pub fn sub( self, define_opaque_types: DefineOpaqueTypes, @@ -287,6 +342,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { } /// Makes `expected == actual`. + /// + /// FIXME: To be removed in favor of the [`InferCtxt::eq_raw`] method instead. pub fn eq( self, define_opaque_types: DefineOpaqueTypes, @@ -305,6 +362,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { } /// Makes `expected == actual`. + /// + /// FIXME: To be removed in favor of the [`InferCtxt::eq_trace_raw`] method instead. pub fn eq_trace( self, define_opaque_types: DefineOpaqueTypes, @@ -338,6 +397,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { } } + /// FIXME: To be removed in favor of the [`InferCtxt::relate_raw`] method instead. pub fn relate( self, define_opaque_types: DefineOpaqueTypes, @@ -367,6 +427,8 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// this can result in an error (e.g., if asked to compute LUB of /// u32 and i32), it is meaningful to call one of them the /// "expected type". + /// + /// FIXME: To be removed in favor of the [`InferCtxt::lub_raw`] method instead. pub fn lub(self, expected: T, actual: T) -> InferResult<'tcx, T> where T: ToTrace<'tcx>, @@ -381,6 +443,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { Ok(InferOk { value, obligations: op.into_obligations() }) } + /// FIXME: To be removed in favor of the [`InferCtxt::goals_to_obligations`] method instead. fn goals_to_obligations( &self, goals: Vec>>,