From 7aa3f3ce52c5be3682540bd51a66215f72506ef2 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 13 Apr 2026 19:38:49 +0800 Subject: [PATCH] normalize each predicate inside `predicates_for_generics` --- compiler/rustc_hir_typeck/src/expr.rs | 5 +++- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 17 ++----------- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 2 +- .../rustc_hir_typeck/src/method/confirm.rs | 4 ++-- compiler/rustc_hir_typeck/src/method/mod.rs | 14 +++++++---- compiler/rustc_hir_typeck/src/method/probe.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 9 +++---- .../src/traits/specialize/mod.rs | 19 ++++++++------- .../hr-associated-type-bound-param-6.stderr | 24 +++++++++---------- 10 files changed, 48 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 55e6d233f475..e21cadcf3ffe 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3557,6 +3557,8 @@ fn find_and_report_unsatisfied_index_impl( // Register the impl's predicates. One of these predicates // must be unsatisfied, or else we wouldn't have gotten here // in the first place. + let unnormalized_predicates = + self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args); ocx.register_obligations(traits::predicates_for_generics( |idx, span| { cause.clone().derived_cause( @@ -3574,8 +3576,9 @@ fn find_and_report_unsatisfied_index_impl( }, ) }, + |pred| ocx.normalize(&cause, self.param_env, pred), self.param_env, - self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args), + unnormalized_predicates, )); // Normalize the output type, which we can use later on as the diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d3dcb65e71ee..f57a22f21235 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -423,20 +423,6 @@ pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec, - ) -> ty::InstantiatedPredicates<'tcx> { - let bounds = self.tcx.predicates_of(def_id); - let result = bounds.instantiate(self.tcx, args); - let result = self.normalize(span, result); - debug!("instantiate_bounds(bounds={:?}, args={:?}) = {:?}", bounds, args, result); - result - } - pub(crate) fn normalize(&self, span: Span, value: T) -> T where T: TypeFoldable>, @@ -1426,10 +1412,11 @@ pub(crate) fn add_required_obligations_with_code( ) { let param_env = self.param_env; - let bounds = self.instantiate_bounds(span, def_id, args); + let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args); for obligation in traits::predicates_for_generics( |idx, predicate_span| self.cause(span, code(idx, predicate_span)), + |pred| self.normalize(span, pred), param_env, bounds, ) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 857713e3295c..419fc8e82be6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -339,9 +339,9 @@ fn select_inherent_assoc_candidates( // Check whether the impl imposes obligations we have to worry about. let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_bounds); let impl_obligations = traits::predicates_for_generics( |_, _| ObligationCause::dummy(), + |pred| ocx.normalize(&ObligationCause::dummy(), self.param_env, pred), self.param_env, impl_bounds, ); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 6f8335f0cc82..3423f6b42bb2 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -144,8 +144,7 @@ fn confirm( ); self.unify_receivers(self_ty, method_sig_rcvr, pick); - let (method_sig, method_predicates) = - self.normalize(self.span, (method_sig, method_predicates)); + let method_sig = self.normalize(self.span, method_sig); // Make sure nobody calls `drop()` explicitly. self.check_for_illegal_method_calls(pick); @@ -626,6 +625,7 @@ fn add_obligations( ); self.cause(self.span, code) }, + |pred| self.normalize(self.call_expr.span, pred), self.param_env, method_predicates, ) { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 083e29bff04f..eef7f9ba495a 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -442,17 +442,21 @@ pub(super) fn lookup_method_for_operator( // any late-bound regions appearing in its bounds. let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args); - let InferOk { value: bounds, obligations: o } = - self.at(&obligation.cause, self.param_env).normalize(bounds); - obligations.extend(o); - assert!(!bounds.has_escaping_bound_vars()); - let predicates_cause = obligation.cause.clone(); + let mut normalization_obligations = PredicateObligations::new(); obligations.extend(traits::predicates_for_generics( move |_, _| predicates_cause.clone(), + |pred| { + let InferOk { value: pred, obligations: o } = + self.at(&obligation.cause, self.param_env).normalize(pred); + normalization_obligations.extend(o); + assert!(!pred.has_escaping_bound_vars()); + pred + }, self.param_env, bounds, )); + obligations.extend(normalization_obligations); // Also add an obligation for the method type being well-formed. debug!( diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c7442373353e..6cfa6e8d7517 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1989,7 +1989,6 @@ fn consider_probe( let impl_def_id = probe.item.container_id(self.tcx); let impl_bounds = self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args); - let impl_bounds = ocx.normalize(cause, self.param_env, impl_bounds); // Convert the bounds into obligations. ocx.register_obligations(traits::predicates_for_generics( |idx, span| { @@ -2001,6 +2000,7 @@ fn consider_probe( ); self.cause(self.span, code) }, + |pred| ocx.normalize(cause, self.param_env, pred), self.param_env, impl_bounds, )); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bc971d7a4370..a78e5096b2e5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -689,7 +689,7 @@ fn pack(self) -> Term<'tcx> { /// `[[], [U:Bar]]`. Now if there were some particular reference /// like `Foo`, then the `InstantiatedPredicates` would be `[[], /// [usize:Bar]]`. -#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug)] pub struct InstantiatedPredicates<'tcx> { pub predicates: Vec>, pub spans: Vec, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 94ce7631b3c8..89a6132b0dc7 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -34,8 +34,8 @@ use rustc_middle::span_bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast, + self, Clause, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast, }; use rustc_span::Span; use rustc_span::def_id::DefId; @@ -177,9 +177,10 @@ pub enum TraitQueryMode { } /// Creates predicate obligations from the generic bounds. -#[instrument(level = "debug", skip(cause, param_env))] +#[instrument(level = "debug", skip(cause, param_env, normalize_predicate))] pub fn predicates_for_generics<'tcx>( cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, + mut normalize_predicate: impl FnMut(Clause<'tcx>) -> Clause<'tcx>, param_env: ty::ParamEnv<'tcx>, generic_bounds: ty::InstantiatedPredicates<'tcx>, ) -> impl Iterator> { @@ -187,7 +188,7 @@ pub fn predicates_for_generics<'tcx>( cause: cause(idx, span), recursion_depth: 0, param_env, - predicate: clause.as_predicate(), + predicate: normalize_predicate(clause).as_predicate(), }) } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index fa9d617604e5..d6dcb97562d0 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -185,12 +185,13 @@ fn fulfill_implication<'tcx>( // Now check that the source trait ref satisfies all the where clauses of the target impl. // This is not just for correctness; we also need this to constrain any params that may // only be referenced via projection predicates. - let predicates = ocx.normalize( - cause, + let predicates = infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args); + let obligations = predicates_for_generics( + |_, _| cause.clone(), + |pred| ocx.normalize(cause, param_env, pred), param_env, - infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args), + predicates, ); - let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates); ocx.register_obligations(obligations); let errors = ocx.evaluate_obligations_error_on_ambiguity(); @@ -315,12 +316,14 @@ pub(super) fn specializes( // Now check that the source trait ref satisfies all the where clauses of the target impl. // This is not just for correctness; we also need this to constrain any params that may // only be referenced via projection predicates. - let predicates = ocx.normalize( - cause, + let predicates = + infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args); + let obligations = predicates_for_generics( + |_, _| cause.clone(), + |pred| ocx.normalize(cause, param_env, pred), param_env, - infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args), + predicates, ); - let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates); ocx.register_obligations(obligations); let errors = ocx.evaluate_obligations_error_on_ambiguity(); diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr index af94a33e4d7d..83e84938d74b 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -9,18 +9,6 @@ help: consider restricting type parameter `T` with trait `X` LL | impl X<'b, T>> X<'_, T> for (S,) { | ++++++++++++++++++ -error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied - --> $DIR/hr-associated-type-bound-param-6.rs:18:5 - | -LL | <(i32,) as X>::f("abc"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32` - | -help: the trait `X<'_, T>` is implemented for `(S,)` - --> $DIR/hr-associated-type-bound-param-6.rs:12:1 - | -LL | impl X<'_, T> for (S,) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:18:18 | @@ -41,6 +29,18 @@ LL | for<'b> T: X<'b, T>, LL | fn f(x: &>::U) { | - required by a bound in this associated function +error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:18:5 + | +LL | <(i32,) as X>::f("abc"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32` + | +help: the trait `X<'_, T>` is implemented for `(S,)` + --> $DIR/hr-associated-type-bound-param-6.rs:12:1 + | +LL | impl X<'_, T> for (S,) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `i32: X<'_, i32>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:18:27 |