From c9aa6d1094f2b44b3906d21c7c37b8a4ef4d6cc4 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Tue, 13 Oct 2026 07:50:13 +0100 Subject: [PATCH 1/3] Remove the 'sup' method from 'At' and migrate to 'sup_raw' --- compiler/rustc_hir_typeck/src/callee.rs | 9 ++- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- compiler/rustc_hir_typeck/src/demand.rs | 3 +- compiler/rustc_hir_typeck/src/expr.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 11 ++- .../rustc_hir_typeck/src/method/confirm.rs | 3 +- compiler/rustc_hir_typeck/src/method/probe.rs | 4 +- compiler/rustc_infer/src/infer/at.rs | 70 ++++++++----------- compiler/rustc_infer/src/infer/mod.rs | 2 +- .../src/traits/engine.rs | 3 +- .../src/traits/select/confirmation.rs | 9 ++- 11 files changed, 63 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index b431e9951a87e..9a648baa266ec 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -733,8 +733,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ObligationCauseCode::WellFormed(WellFormedLoc::HirId(call_expr.hir_id)), ); if self - .at(&cause, self.param_env) - .sup(DefineOpaqueTypes::Yes, formal_input_tys[0], adjusted_arg_type) + .sup_raw( + &cause, + self.param_env, + DefineOpaqueTypes::Yes, + formal_input_tys[0], + adjusted_arg_type, + ) .is_err() { return do_check(); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 1f55fd49fc86b..068ec3424d91d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -170,7 +170,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let res = if self.use_lub { at.lub(b, a) } else { - at.sup(DefineOpaqueTypes::Yes, b, a) + self.sup_raw(&self.cause, self.param_env, DefineOpaqueTypes::Yes, b, a) .map(|InferOk { value: (), obligations }| InferOk { value: b, obligations }) }; diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 36e0a22c76133..2f4f2a99cc218 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -190,8 +190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Result<(), Diag<'a>> { - self.at(cause, self.param_env) - .sup(DefineOpaqueTypes::Yes, expected, actual) + self.sup_raw(cause, self.param_env, DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) .map_err(|e| { self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b1b8ecb7d1844..99daf9588415d 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2119,7 +2119,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(_) = remaining_fields.remove(&ident) { let target_ty = self.field_ty(base_expr.span, f, args); let cause = self.misc(base_expr.span); - match self.at(&cause, self.param_env).sup( + match self.sup_raw( + &cause, + self.param_env, // We're already using inference variables for any params, // and don't allow converting between different structs, // so there is no way this ever actually defines an opaque diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 68eb349bab8f0..c31f0d31ac532 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -3263,9 +3263,14 @@ impl<'a, 'tcx> ArgMatchingCtxt<'a, 'tcx> { // Using probe here, since we don't want this subtyping to affect inference. let subtyping_error = self.probe(|_| { - self.at(&self.misc(arg_span), self.param_env) - .sup(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty) - .err() + self.sup_raw( + &self.misc(arg_span), + self.param_env, + DefineOpaqueTypes::Yes, + formal_input_ty, + coerced_ty, + ) + .err() }); // Same as above: if either the coerce type or the checked type is an error type, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 721e9a38fc50c..2b340cf1b6d49 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -561,7 +561,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_ty, method_self_ty, self.span, pick ); let cause = self.cause(self.self_expr.span, ObligationCauseCode::Misc); - match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) { + match self.sup_raw(&cause, self.param_env, DefineOpaqueTypes::Yes, method_self_ty, self_ty) + { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c74047590331c..fee295aa0e149 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1971,7 +1971,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.xform_self_ty(candidate.item, trait_ref.self_ty(), trait_ref.args); // Guide the trait selection to show impls that have methods whose type matches // up with the `self` parameter of the method. - let _ = self.at(&ObligationCause::dummy(), self.param_env).sup( + let _ = self.sup_raw( + &ObligationCause::dummy(), + self.param_env, DefineOpaqueTypes::Yes, xform_self_ty, self_ty, diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 16c6fed9e9a42..8eabbc0dcb06f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -133,7 +133,7 @@ impl<'tcx> InferCtxt<'tcx> { /// If possible, prefer the wrapper methods on `ObligationCtxt`, /// `FnCtxt`, or `TypeChecker`. pub fn sup_raw( - self, + &self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, define_opaque_types: DefineOpaqueTypes, @@ -143,7 +143,27 @@ impl<'tcx> InferCtxt<'tcx> { where T: ToTrace<'tcx>, { - self.at(cause, param_env).sup(define_opaque_types, expected, actual) + if self.next_trait_solver { + NextSolverRelate::relate( + self, + param_env, + expected, + ty::Contravariant, + actual, + cause.span, + ) + .map(|goals| self.goals_to_obligations(cause, 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`. @@ -268,44 +288,6 @@ pub trait ToTrace<'tcx>: Relate> + Copy { } impl<'a, 'tcx> At<'a, 'tcx> { - /// 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. - /// - /// FIXME: To be removed in favor of the [`InferCtxt::sup_raw`] method instead. - pub fn sup( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - if self.infcx.next_trait_solver { - NextSolverRelate::relate( - self.infcx, - self.param_env, - expected, - ty::Contravariant, - actual, - self.cause.span, - ) - .map(|goals| self.goals_to_obligations(goals)) - } else { - let mut op = TypeRelating::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - define_opaque_types, - ty::Contravariant, - ); - op.relate(expected, actual)?; - Ok(InferOk { value: (), obligations: op.into_obligations() }) - } - } - /// Makes `expected <: actual`. /// /// FIXME: To be removed in favor of the [`InferCtxt::sub_raw`] method instead. @@ -411,7 +393,13 @@ impl<'a, 'tcx> At<'a, 'tcx> { match variance { ty::Covariant => self.sub(define_opaque_types, expected, actual), ty::Invariant => self.eq(define_opaque_types, expected, actual), - ty::Contravariant => self.sup(define_opaque_types, expected, actual), + ty::Contravariant => self.infcx.sup_raw( + self.cause, + self.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 diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c45c5e44aaa31..84093f2bdb484 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -891,7 +891,7 @@ impl<'tcx> InferCtxt<'tcx> { if a_is_expected { Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) } else { - Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a)) + Ok(self.sup_raw(cause, param_env, DefineOpaqueTypes::Yes, b, a)) } }) } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 3e6d14625c6b2..8f57c3c222d6a 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -283,8 +283,7 @@ where actual: T, ) -> Result<(), TypeError<'tcx>> { self.infcx - .at(cause, param_env) - .sup(DefineOpaqueTypes::Yes, expected, actual) + .sup_raw(cause, param_env, DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 6d5cddde61076..1fb8c84176fac 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1033,8 +1033,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // only the **lifetime bound** is changed. let InferOk { mut obligations, .. } = self .infcx - .at(&obligation.cause, obligation.param_env) - .sup(DefineOpaqueTypes::Yes, target, source_trait) + .sup_raw( + &obligation.cause, + obligation.param_env, + DefineOpaqueTypes::Yes, + target, + source_trait, + ) .map_err(|_| SelectionError::Unimplemented)?; // Register one obligation for 'a: 'b. From e1f60107508e0a2f904bff2e3b3f0ed6395e5f07 Mon Sep 17 00:00:00 2001 From: Fallible Date: Tue, 13 Oct 2026 09:28:00 +0100 Subject: [PATCH 2/3] Apply suggestion from @lcnr Co-authored-by: lcnr --- compiler/rustc_hir_typeck/src/callee.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9a648baa266ec..085122da3c7fb 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -732,6 +732,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr.span, ObligationCauseCode::WellFormed(WellFormedLoc::HirId(call_expr.hir_id)), ); + // FIXME: This needs to happen in a `probe` as the `sup` + // call can currently guide type inference. if self .sup_raw( &cause, From ae85a2a18855a4c004bc95bf6b388a602dc9c08f Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Tue, 13 Oct 2026 10:36:04 +0100 Subject: [PATCH 3/3] Use demand_suptype_diag instead --- compiler/rustc_hir_typeck/src/expr.rs | 29 +++++---------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 99daf9588415d..47a09eacebe93 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -24,7 +24,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, HirId, QPath, is_range_literal}; use rustc_hir_analysis::diagnostics::{NoFieldOnType, NoVariantNamed}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; -use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin}; +use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_infer::traits::WellFormedLoc; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; @@ -2119,29 +2119,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(_) = remaining_fields.remove(&ident) { let target_ty = self.field_ty(base_expr.span, f, args); let cause = self.misc(base_expr.span); - match self.sup_raw( - &cause, - self.param_env, - // We're already using inference variables for any params, - // and don't allow converting between different structs, - // so there is no way this ever actually defines an opaque - // type. Thus choosing `Yes` is fine. - DefineOpaqueTypes::Yes, - target_ty, - fru_ty, - ) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations) - } - Err(_) => { - span_bug!( - cause.span, - "subtyping remaining fields of type changing FRU \ - failed: {target_ty} != {fru_ty}: {}::{}", - variant.name, - ident.name, - ); - } + if let Err(diag) = + self.demand_suptype_diag(cause.span, target_ty, fru_ty) + { + diag.delay_as_bug(); } } self.deeply_resolve_ignoring_regions(fru_ty)