From 9ff4fefd35e2c948108cab6892bd3747fbfd2e9e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 May 2026 10:24:52 +1000 Subject: [PATCH 1/8] Fix a typo And insert some blank lines. --- compiler/rustc_type_ir/src/elaborate.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index be3661518d7d9..36865700dc7a6 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -53,14 +53,16 @@ pub trait Elaboratable { pub struct ClauseWithSupertraitSpan { pub clause: I::Clause, - // Span of the supertrait predicatae that lead to this clause. + // Span of the supertrait predicate that lead to this clause. pub supertrait_span: I::Span, } + impl ClauseWithSupertraitSpan { pub fn new(clause: I::Clause, span: I::Span) -> Self { ClauseWithSupertraitSpan { clause, supertrait_span: span } } } + impl Elaboratable for ClauseWithSupertraitSpan { fn predicate(&self) -> ::Predicate { self.clause.as_predicate() From 7d5a637274f335c0dd2a34d7ebcf6b4f5ce4ec7b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 May 2026 09:03:13 +1000 Subject: [PATCH 2/8] Eliminate three `as_predicate` calls `check_predicates` currently does the following. - Builds `impl2_predicates` by gathering some clauses and converting them into predicates. - Extends `impl2_predicates` with some actual predicates from `elaborate`. - Iterates over `impl1_predicates` (which are actually clauses), converting each clause to a predicate in order to look for a match with any predicate in `impl2_predicates`. After this commit it instead does the following. - Builds `impl2_clauses` by gathering some clauses. - Extends `impl2_clauses` with only the predicates from `elaborate` that are clauses (pre-filtering out non-clause predicates). - Iterates over `impl1_clauses` (now correctly named), to look for a match with any clause in `impl2_clauses`. I.e. instead of promoting clauses to predicates and doing some comparisons that can't succeed, we pre-filter any non-clause predicates before doing the comparisons. --- .../src/impl_wf_check/min_specialization.rs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 1fb126fe3d69f..5af4675a818a2 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -324,7 +324,7 @@ fn check_predicates<'tcx>( impl2_args: GenericArgsRef<'tcx>, span: Span, ) -> Result<(), ErrorGuaranteed> { - let impl1_predicates: Vec<_> = traits::elaborate( + let impl1_clauses: Vec<(ty::Clause<'_>, _)> = traits::elaborate( tcx, tcx.predicates_of(impl1_def_id) .instantiate(tcx, impl1_args) @@ -333,7 +333,7 @@ fn check_predicates<'tcx>( ) .collect(); - let mut impl2_predicates = if impl2_node.is_from_trait() { + let mut impl2_clauses: Vec> = if impl2_node.is_from_trait() { // Always applicable traits have to be always applicable without any // assumptions. Vec::new() @@ -343,11 +343,11 @@ fn check_predicates<'tcx>( tcx.predicates_of(impl2_node.def_id()) .instantiate(tcx, impl2_args) .into_iter() - .map(|(c, _s)| c.skip_norm_wip().as_predicate()), + .map(|(c, _s)| c.skip_norm_wip()), ) .collect() }; - debug!(?impl1_predicates, ?impl2_predicates); + debug!(?impl1_clauses, ?impl2_clauses); // Since impls of always applicable traits don't get to assume anything, we // can also assume their supertraits apply. @@ -364,7 +364,7 @@ fn check_predicates<'tcx>( // which is sound because we forbid impls like the following // // impl AlwaysApplicable for D { } - let always_applicable_traits = impl1_predicates + let always_applicable_traits = impl1_clauses .iter() .copied() .filter(|&(clause, _span)| { @@ -373,7 +373,7 @@ fn check_predicates<'tcx>( Some(TraitSpecializationKind::AlwaysApplicable) ) }) - .map(|(c, _span)| c.as_predicate()); + .map(|(c, _span)| c); // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).instantiate_identity().skip_norm_wip().args { @@ -386,15 +386,17 @@ fn check_predicates<'tcx>( .unwrap(); assert!(!obligations.has_infer()); - impl2_predicates - .extend(traits::elaborate(tcx, obligations).map(|obligation| obligation.predicate)) + impl2_clauses.extend( + traits::elaborate(tcx, obligations) + .filter_map(|obligation| obligation.predicate.as_clause()), + ) } - impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits)); + impl2_clauses.extend(traits::elaborate(tcx, always_applicable_traits)); let mut res = Ok(()); - for (clause, span) in impl1_predicates { - if !impl2_predicates.iter().any(|&pred2| clause.as_predicate() == pred2) { - res = res.and(check_specialization_on(tcx, clause, span)) + for (clause1, span) in impl1_clauses { + if !impl2_clauses.iter().any(|&clause2| clause1 == clause2) { + res = res.and(check_specialization_on(tcx, clause1, span)) } } res From 185cd70c0843fd56b138f24a34813eac33d10e18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 May 2026 09:09:59 +1000 Subject: [PATCH 3/8] Eliminate one `as_predicate` call `deduce_closure_signature_from_predicates` currently takes a `Predicate` iterator. But it ignores any predicates that are not clauses. This commit changes it to take a `Clause` iterator. The change requires one call site to pre-filter any non-clause predicates, but also lets another site avoid uselessly promoting clauses to predicates. --- compiler/rustc_hir_typeck/src/closure.rs | 29 +++++++++++------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 763d2a27e6cc0..93596ff9feed4 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -301,8 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx .explicit_item_self_bounds(def_id) .iter_instantiated_copied(self.tcx, args) - .map(Unnormalized::skip_norm_wip) - .map(|(c, s)| (c.as_predicate(), s)), + .map(Unnormalized::skip_norm_wip), ), ty::Dynamic(object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -319,7 +318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_kind, self.obligations_for_self_ty(vid) .into_iter() - .map(|obl| (obl.predicate, obl.cause.span)), + .filter_map(|obl| Some((obl.predicate.as_clause()?, obl.cause.span))), ), ty::FnPtr(sig_tys, hdr) => match closure_kind { hir::ClosureKind::Closure => { @@ -338,36 +337,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expected_ty: Ty<'tcx>, closure_kind: hir::ClosureKind, - predicates: impl DoubleEndedIterator, Span)>, + clauses: impl DoubleEndedIterator, Span)>, ) -> (Option>, Option) { let mut expected_sig = None; let mut expected_kind = None; - for (pred, span) in traits::elaborate( + for (clause, span) in traits::elaborate( self.tcx, // Reverse the obligations here, since `elaborate_*` uses a stack, // and we want to keep inference generally in the same order of // the registered obligations. - predicates.rev(), + clauses.rev(), ) // We only care about self bounds .filter_only_self() { - debug!(?pred); - let bound_predicate = pred.kind(); + debug!(?clause); + let bound_clause = clause.kind(); - // Given a Projection predicate, we can potentially infer - // the complete signature. + // Given a Projection clause, we can potentially infer the complete signature. if expected_sig.is_none() - && let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = - bound_predicate.skip_binder() + && let ty::ClauseKind::Projection(proj_clause) = bound_clause.skip_binder() { let inferred_sig = self.normalize( span, Unnormalized::new_wip(self.deduce_sig_from_projection( Some(span), closure_kind, - bound_predicate.rebind(proj_predicate), + bound_clause.rebind(proj_clause), )), ); @@ -434,11 +431,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // infer the kind. This can occur when we elaborate a predicate // like `F : Fn`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. - let trait_def_id = match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { + let trait_def_id = match bound_clause.skip_binder() { + ty::ClauseKind::Projection(data) => { Some(data.projection_term.trait_def_id(self.tcx)) } - ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()), + ty::ClauseKind::Trait(data) => Some(data.def_id()), _ => None, }; From 66651749e6748a9b0172434ca0ebb38eca3252b9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 May 2026 09:38:44 +1000 Subject: [PATCH 4/8] Eliminate another `as_predicate` call `get_future_output` takes a predicate, but can only succeed if the predicate is a clause. This commit changes it to take a clause. This requires changing one call site to pre-filter any non-clause predicates, but also lets another site avoid uselessly promoting clauses to predicates. --- compiler/rustc_hir_typeck/src/closure.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 93596ff9feed4..6c7d19e848e0a 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -961,21 +961,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.resolve_vars_with_obligations(ret_ty); - let get_future_output = |predicate: ty::Predicate<'tcx>, span| { + let get_future_output = |clause: ty::Clause<'tcx>, span| { // Search for a pending obligation like // // `::Output = T` // // where R is the return type we are expecting. This type `T` // will be our output. - let bound_predicate = predicate.kind(); - if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = - bound_predicate.skip_binder() - { - self.deduce_future_output_from_projection( - span, - bound_predicate.rebind(proj_predicate), - ) + let bound_clause = clause.kind(); + if let ty::ClauseKind::Projection(proj_clause) = bound_clause.skip_binder() { + self.deduce_future_output_from_projection(span, bound_clause.rebind(proj_clause)) } else { None } @@ -984,7 +979,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let output_ty = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => { self.obligations_for_self_ty(ret_vid).into_iter().find_map(|obligation| { - get_future_output(obligation.predicate, obligation.cause.span) + obligation + .predicate + .as_clause() + .and_then(|clause| get_future_output(clause, obligation.cause.span)) })? } ty::Alias(ty::AliasTy { kind: ty::Projection { .. }, .. }) => { @@ -999,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .explicit_item_self_bounds(def_id) .iter_instantiated_copied(self.tcx, args) .map(Unnormalized::skip_norm_wip) - .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, + .find_map(|(c, s)| get_future_output(c, s))?, ty::Error(_) => return Some(ret_ty), _ => { span_bug!(closure_span, "invalid async fn coroutine return type: {ret_ty:?}") From ebcf862e93888ef293168549024e29051523af80 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 May 2026 10:40:56 +1000 Subject: [PATCH 5/8] Eliminate two `as_predicate` calls `Predicate` already implements `Flags`. By adding an impl of `Flags` for `Clause`, we can call `flags` and `outer_exclusive_binder` directly on clauses, instead of having to convert them to predicates first. --- compiler/rustc_middle/src/ty/predicate.rs | 10 ++++++++++ compiler/rustc_type_ir/src/flags.rs | 4 ++-- compiler/rustc_type_ir/src/inherent.rs | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 26108f7be6964..811ed1e8784ad 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -155,6 +155,16 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for Clause<'tcx> { } } +impl<'tcx> rustc_type_ir::Flags for Clause<'tcx> { + fn flags(&self) -> TypeFlags { + self.0.flags + } + + fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { + self.0.outer_exclusive_binder + } +} + impl<'tcx> Clause<'tcx> { pub fn as_predicate(self) -> Predicate<'tcx> { Predicate(self.0) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 19c59df0604c3..86b9f04d5c35c 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -190,8 +190,8 @@ impl FlagComputation { pub fn for_clauses(clauses: &[I::Clause]) -> FlagComputation { let mut result = FlagComputation::new(); for c in clauses { - result.add_flags(c.as_predicate().flags()); - result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder()); + result.add_flags(c.flags()); + result.add_exclusive_binder(c.outer_exclusive_binder()); } result } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 8859ab7c037b0..32cb098d5bc7f 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -519,6 +519,7 @@ pub trait Clause>: + Hash + Eq + TypeFoldable + + Flags + UpcastFrom>> + UpcastFrom> + UpcastFrom>> From 743240e156aff15ce28fbda9490e52af798b7d43 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 May 2026 11:18:13 +1000 Subject: [PATCH 6/8] Adjust naming around `caller_bounds` calls `caller_bounds` returns a sequence of clauses, but all the call sites use variables as if it returns predicates. Similarly, `assemble_candidates_from_predicates` actually takes clauses, not predicates. This commit renames things appropriately, replacing name mixups like `tcx.mk_clauses(&predicates)` with `tcx.mk_clauses(&clauses)`. --- .../src/check/compare_impl_item.rs | 6 ++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 11 ++++--- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 6 ++-- compiler/rustc_hir_typeck/src/method/probe.rs | 8 ++--- .../src/error_reporting/traits/suggestions.rs | 8 ++--- .../src/traits/auto_trait.rs | 4 +-- .../src/traits/const_evaluatable.rs | 4 +-- .../rustc_trait_selection/src/traits/mod.rs | 30 +++++++++---------- .../src/traits/project.rs | 22 +++++++------- .../src/traits/select/candidate_assembly.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 4 +-- src/librustdoc/clean/auto_trait.rs | 17 +++++------ .../src/methods/needless_collect.rs | 4 +-- .../src/methods/unnecessary_to_owned.rs | 18 +++++------ .../src/needless_borrows_for_generic_args.rs | 22 +++++++------- .../src/needless_pass_by_value.rs | 6 ++-- src/tools/clippy/clippy_lints/src/ranges.rs | 4 +-- .../clippy_lints/src/useless_conversion.rs | 6 ++-- src/tools/clippy/clippy_utils/src/ty/mod.rs | 10 +++---- 19 files changed, 95 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 234231ed37fed..cab64c124f4a8 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2635,7 +2635,7 @@ fn param_env_with_gat_bounds<'tcx>( ) -> ty::ParamEnv<'tcx> { let param_env = tcx.param_env(impl_ty.def_id); let container_id = impl_ty.container_id(tcx); - let mut predicates = param_env.caller_bounds().to_vec(); + let mut clauses = param_env.caller_bounds().to_vec(); // for RPITITs, we should install predicates that allow us to project all // of the RPITITs associated with the same body. This is because checking @@ -2732,7 +2732,7 @@ fn param_env_with_gat_bounds<'tcx>( // // impl X for T where T: X { type Y = ::Y; } } - _ => predicates.push( + _ => clauses.push( ty::Binder::bind_with_vars( ty::ProjectionPredicate { projection_term: ty::AliasTerm::new_from_def_id( @@ -2749,7 +2749,7 @@ fn param_env_with_gat_bounds<'tcx>( }; } - ty::ParamEnv::new(tcx.mk_clauses(&predicates)) + ty::ParamEnv::new(tcx.mk_clauses(&clauses)) } /// Manually check here that `async fn foo()` wasn't matched against `fn foo()`, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index dd506dd2b7fc9..3d2143887d91b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -566,19 +566,18 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { fn augment_param_env<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - new_predicates: Option<&FxIndexSet>>, + new_clauses: Option<&FxIndexSet>>, ) -> ty::ParamEnv<'tcx> { - let Some(new_predicates) = new_predicates else { + let Some(new_clauses) = new_clauses else { return param_env; }; - if new_predicates.is_empty() { + if new_clauses.is_empty() { return param_env; } - let bounds = tcx.mk_clauses_from_iter( - param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()), - ); + let bounds = tcx + .mk_clauses_from_iter(param_env.caller_bounds().iter().chain(new_clauses.iter().copied())); // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this // i.e. traits::normalize_param_env_or_error ty::ParamEnv::new(bounds) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 5fea7454e57ea..236f156734af2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -311,10 +311,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { let span = tcx.def_span(def_id); ty::EarlyBinder::bind(tcx.arena.alloc_from_iter( - self.param_env.caller_bounds().iter().filter_map(|predicate| { - match predicate.kind().skip_binder() { + self.param_env.caller_bounds().iter().filter_map(|clause| { + match clause.kind().skip_binder() { ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => { - Some((predicate, span)) + Some((clause, span)) } _ => None, } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4258896deec70..445d3677b9874 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -995,12 +995,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // We use `DeepRejectCtxt` here which may return false positive on where clauses // with alias self types. We need to later on reject these as inherent candidates // in `consider_probe`. - let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { - let bound_predicate = predicate.kind(); - match bound_predicate.skip_binder() { + let bounds = self.param_env.caller_bounds().iter().filter_map(|clause| { + let bound_clause = clause.kind(); + match bound_clause.skip_binder() { ty::ClauseKind::Trait(trait_predicate) => DeepRejectCtxt::relate_rigid_rigid(tcx) .types_may_unify(param_ty, trait_predicate.trait_ref.self_ty()) - .then(|| bound_predicate.rebind(trait_predicate.trait_ref)), + .then(|| bound_clause.rebind(trait_predicate.trait_ref)), ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::Projection(_) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 26139926dae41..f2ac854a58177 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1533,8 +1533,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { DefIdOrName::Name("type parameter") }; - param_env.caller_bounds().iter().find_map(|pred| { - if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() + param_env.caller_bounds().iter().find_map(|clause| { + if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() && self .tcx .is_lang_item(proj.projection_term.def_id(), LangItem::FnOnceOutput) @@ -1544,8 +1544,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { Some(( name, - pred.kind().rebind(proj.term.expect_type()), - pred.kind().rebind(args.as_slice()), + clause.kind().rebind(proj.term.expect_type()), + clause.kind().rebind(args.as_slice()), )) } else { None diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index af104a56202b0..91ee04888ecab 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -228,8 +228,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { // Don't try to process any nested obligations involving predicates // that are already in the `ParamEnv` (modulo regions): we already // know that they must hold. - for predicate in param_env.caller_bounds() { - fresh_preds.insert(self.clean_pred(infcx, predicate.as_predicate())); + for clause in param_env.caller_bounds() { + fresh_preds.insert(self.clean_pred(infcx, clause.as_predicate())); } let mut select = SelectionContext::new(infcx); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 45f30cd14c672..17ea6df781af6 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -201,8 +201,8 @@ fn satisfied_from_param_env<'tcx>( let mut single_match: Option, ()>> = None; - for pred in param_env.caller_bounds() { - match pred.kind().skip_binder() { + for clause in param_env.caller_bounds() { + match clause.kind().skip_binder() { ty::ClauseKind::ConstEvaluatable(ce) => { let b_ct = tcx.expand_abstract_consts(ce); let mut v = Visitor { ct, infcx, param_env, single_match }; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a834dbd1604f8..7688251c479b0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -343,9 +343,9 @@ pub fn normalize_param_env_or_error<'tcx>( // can be sure that no errors should occur. let mut predicates: Vec<_> = util::elaborate( tcx, - unnormalized_env.caller_bounds().into_iter().map(|predicate| { + unnormalized_env.caller_bounds().into_iter().map(|clause| { if tcx.features().generic_const_exprs() || tcx.next_trait_solver_globally() { - return predicate; + return clause; } struct ConstNormalizer<'tcx>(TyCtxt<'tcx>); @@ -409,7 +409,7 @@ pub fn normalize_param_env_or_error<'tcx>( // compatibility. Eventually when lazy norm is implemented this can just be removed. // We do not normalize types here as there is no backwards compatibility requirement // for us to do so. - predicate.fold_with(&mut ConstNormalizer(tcx)) + clause.fold_with(&mut ConstNormalizer(tcx)) }), ) .collect(); @@ -493,12 +493,12 @@ pub fn deeply_normalize_param_env_ignoring_regions<'tcx>( unnormalized_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, ) -> ty::ParamEnv<'tcx> { - let predicates: Vec<_> = + let clauses: Vec<_> = util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); - debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); + debug!("normalize_param_env_or_error: elaborated-clauses={:?}", clauses); - let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates)); + let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&clauses)); if !elaborated_env.has_aliases() { return elaborated_env; } @@ -509,27 +509,27 @@ pub fn deeply_normalize_param_env_ignoring_regions<'tcx>( .with_next_trait_solver(true) .ignoring_regions() .build(TypingMode::non_body_analysis()); - let predicates = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>( + let clauses = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>( infcx.at(&cause, elaborated_env), - Unnormalized::new_wip(predicates), + Unnormalized::new_wip(clauses), ) { - Ok(predicates) => predicates, + Ok(clauses) => clauses, Err(errors) => { infcx.err_ctxt().report_fulfillment_errors(errors); // An unnormalized env is better than nothing. - debug!("normalize_param_env_or_error: errored resolving predicates"); + debug!("normalize_param_env_or_error: errored resolving clauses"); return elaborated_env; } }; - debug!("do_normalize_predicates: normalized predicates = {:?}", predicates); + debug!("do_normalize_predicates: normalized clauses = {:?}", clauses); // FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now. // There're placeholder constraints `leaking` out. // See the fixme in the enclosing function's docs for more. let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); - let predicates = match infcx.fully_resolve(predicates) { - Ok(predicates) => predicates, + let clauses = match infcx.fully_resolve(clauses) { + Ok(clauses) => clauses, Err(fixup_err) => { span_bug!( span, @@ -538,8 +538,8 @@ pub fn deeply_normalize_param_env_ignoring_regions<'tcx>( ) } }; - debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new(tcx.mk_clauses(&predicates)) + debug!("normalize_param_env_or_error: final clauses={:?}", clauses); + ty::ParamEnv::new(tcx.mk_clauses(&clauses)) } #[derive(Debug)] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 900d55cc556fc..fe51f7bac25b7 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -716,7 +716,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( obligation: &ProjectionTermObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { - assemble_candidates_from_predicates( + assemble_candidates_from_clauses( selcx, obligation, candidate_set, @@ -815,39 +815,39 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( } _ => return, }; - let env_predicates = data + let env_clauses = data .projection_bounds() .filter(|bound| bound.item_def_id() == obligation.predicate.def_id()) .map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx)); - assemble_candidates_from_predicates( + assemble_candidates_from_clauses( selcx, obligation, candidate_set, ProjectionCandidate::Object, - env_predicates, + env_clauses, false, ); } #[instrument( level = "debug", - skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates) + skip(selcx, candidate_set, ctor, env_clauses, potentially_unnormalized_candidates) )] -fn assemble_candidates_from_predicates<'cx, 'tcx>( +fn assemble_candidates_from_clauses<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, candidate_set: &mut ProjectionCandidateSet<'tcx>, ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>, - env_predicates: impl Iterator>, + env_clauses: impl Iterator>, potentially_unnormalized_candidates: bool, ) { let infcx = selcx.infcx; let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); - for predicate in env_predicates { - let bound_predicate = predicate.kind(); - if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() { - let data = bound_predicate.rebind(data); + for clause in env_clauses { + let bound_clause = clause.kind(); + if let ty::ClauseKind::Projection(data) = clause.kind().skip_binder() { + let data = bound_clause.rebind(data); if data.item_def_id() != obligation.predicate.def_id() { continue; } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3b599db8ff1c2..95dfac97d86e2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -277,7 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .param_env .caller_bounds() .iter() - .filter_map(|p| p.as_trait_clause()) + .filter_map(|c| c.as_trait_clause()) // Micro-optimization: filter out predicates with different polarities. .filter(|p| p.polarity() == stack.obligation.predicate.polarity()); diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 7957bacda5677..18b43cfb707b3 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -507,8 +507,8 @@ where Infcx: InferCtxtLike, { // Iterate through all goals in param_env to find the one that has the same symbol. - for pred in param_env.caller_bounds().iter() { - if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { + for clause in param_env.caller_bounds().iter() { + if let ty::ClauseKind::UnstableFeature(sym) = clause.kind().skip_binder() { if sym == symbol { return true; } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 554b81b14cd3d..e1e37abceda94 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -170,20 +170,19 @@ fn clean_param_env<'tcx>( .collect(); // FIXME(#111101): Incorporate the explicit predicates of the item here... - let item_predicates: FxIndexSet<_> = - tcx.param_env(item_def_id).caller_bounds().iter().collect(); + let item_clauses: FxIndexSet<_> = tcx.param_env(item_def_id).caller_bounds().iter().collect(); let where_predicates = param_env .caller_bounds() .iter() // FIXME: ...which hopefully allows us to simplify this: - .filter(|pred| { - !item_predicates.contains(pred) - || pred + .filter(|clause| { + !item_clauses.contains(clause) + || clause .as_trait_clause() - .is_some_and(|pred| tcx.lang_items().sized_trait() == Some(pred.def_id())) + .is_some_and(|clause| tcx.lang_items().sized_trait() == Some(clause.def_id())) }) - .map(|pred| { - fold_regions(tcx, pred, |r, _| match r.kind() { + .map(|clause| { + fold_regions(tcx, clause, |r, _| match r.kind() { // FIXME: Don't `unwrap_or`, I think we should panic if we encounter an infer var that // we can't map to a concrete region. However, `AutoTraitFinder` *does* leak those kinds // of `ReVar`s for some reason at the time of writing. See `rustdoc-ui/` tests. @@ -197,7 +196,7 @@ fn clean_param_env<'tcx>( } }) }) - .flat_map(|pred| clean_predicate(pred, cx)) + .flat_map(|clause| clean_predicate(clause, cx)) .chain(clean_region_outlives_constraints(®ion_data, generics)) .collect(); diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 4f281d745a94e..53f5df0443b8e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -205,8 +205,8 @@ fn check_collect_into_intoiterator<'tcx>( .param_env(id) .caller_bounds() .into_iter() - .filter_map(|p| { - if let ClauseKind::Trait(t) = p.kind().skip_binder() + .filter_map(|c| { + if let ClauseKind::Trait(t) = c.kind().skip_binder() && cx.tcx.is_diagnostic_item(sym::IntoIterator, t.trait_ref.def_id) { Some(t.self_ty()) diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index a56dcd894b6aa..5b27d9e212782 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -480,8 +480,8 @@ fn get_input_traits_and_projections<'tcx>( ) -> (Vec>, Vec>) { let mut trait_predicates = Vec::new(); let mut projection_predicates = Vec::new(); - for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() { - match predicate.kind().skip_binder() { + for clause in cx.tcx.param_env(callee_def_id).caller_bounds() { + match clause.kind().skip_binder() { ClauseKind::Trait(trait_predicate) if trait_predicate.trait_ref.self_ty() == input => { trait_predicates.push(trait_predicate); }, @@ -543,13 +543,13 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< return false; } - let mut trait_predicates = + let mut trait_clauses = cx.tcx .param_env(callee_def_id) .caller_bounds() .iter() - .filter(|predicate| { - if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + .filter(|clause| { + if let ClauseKind::Trait(trait_predicate) = clause.kind().skip_binder() && trait_predicate.trait_ref.self_ty() == param_ty { true @@ -568,12 +568,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< } })); - if trait_predicates.any(|predicate| { - let predicate = bound_fn_sig - .rebind(predicate) + if trait_clauses.any(|clause| { + let clause = bound_fn_sig + .rebind(clause) .instantiate(cx.tcx, new_subst) .skip_norm_wip(); - let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); + let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, clause); !cx.tcx .infer_ctxt() .build(cx.typing_mode()) diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index 40db810c12840..3e7ae285cab26 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -185,11 +185,11 @@ fn needless_borrow_count<'tcx>( .instantiate_identity() .skip_norm_wip() .skip_binder(); - let predicates = cx.tcx.param_env(fn_id).caller_bounds(); - let projection_predicates = predicates + let clauses = cx.tcx.param_env(fn_id).caller_bounds(); + let projection_predicates = clauses .iter() - .filter_map(|predicate| { - if let ClauseKind::Projection(projection_predicate) = predicate.kind().skip_binder() { + .filter_map(|clause| { + if let ClauseKind::Projection(projection_predicate) = clause.kind().skip_binder() { Some(projection_predicate) } else { None @@ -200,10 +200,10 @@ fn needless_borrow_count<'tcx>( let mut trait_with_ref_mut_self_method = false; // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return. - if predicates + if clauses .iter() - .filter_map(|predicate| { - if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + .filter_map(|clause| { + if let ClauseKind::Trait(trait_predicate) = clause.kind().skip_binder() && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx) { Some(trait_predicate.trait_ref.def_id) @@ -272,8 +272,8 @@ fn needless_borrow_count<'tcx>( return false; } - predicates.iter().all(|predicate| { - if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + clauses.iter().all(|clause| { + if let ClauseKind::Trait(trait_predicate) = clause.kind().skip_binder() && cx .tcx .is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) @@ -285,10 +285,10 @@ fn needless_borrow_count<'tcx>( return false; } - let predicate = EarlyBinder::bind(predicate) + let clause = EarlyBinder::bind(clause) .instantiate(cx.tcx, &args_with_referent_ty[..]) .skip_norm_wip(); - let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); + let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, clause); let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); infcx.predicate_must_hold_modulo_regions(&obligation) }) diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 4ff5b0b0b3c39..6047c5d95c240 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -121,10 +121,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let meta_sized_trait = need!(cx.tcx.lang_items().meta_sized_trait()); let preds = traits::elaborate(cx.tcx, cx.param_env.caller_bounds().iter()) - .filter(|p| !p.is_global()) - .filter_map(|pred| { + .filter(|c| !c.is_global()) + .filter_map(|clause| { // Note that we do not want to deal with qualified predicates here. - match pred.kind().no_bound_vars() { + match clause.kind().no_bound_vars() { Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait => { diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index aa840f400d42e..93677b9153d47 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -417,8 +417,8 @@ fn can_switch_ranges<'tcx>( .param_env(id) .caller_bounds() .into_iter() - .any(|p| { - if let ClauseKind::Trait(t) = p.kind().skip_binder() + .any(|c| { + if let ClauseKind::Trait(t) = c.kind().skip_binder() && t.polarity == PredicatePolarity::Positive && matches!( cx.tcx.get_diagnostic_name(t.trait_ref.def_id), diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index d6db088ba76c0..1167c82d90cad 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -343,9 +343,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { && let Some(self_ty) = inputs.first() && let ty::Ref(_, _, Mutability::Mut) = self_ty.kind() && let Some(second_ty) = inputs.get(1) - && let predicates = cx.tcx.param_env(def_id).caller_bounds() - && predicates.iter().any(|pred| { - if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() { + && let clauses = cx.tcx.param_env(def_id).caller_bounds() + && clauses.iter().any(|clause| { + if let ty::ClauseKind::Trait(trait_pred) = clause.kind().skip_binder() { trait_pred.self_ty() == *second_ty && cx.tcx.lang_items().fn_mut_trait() == Some(trait_pred.def_id()) } else { diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index b384d58a02f83..67dbb32cd9857 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -687,22 +687,22 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option( cx: &LateContext<'tcx>, ty: Ty<'tcx>, - predicates: impl IntoIterator>, + clauses: impl IntoIterator>, predicates_id: Option, ) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); - for pred in predicates { - match pred.kind().skip_binder() { + for clause in clauses { + match clause.kind().skip_binder() { ty::ClauseKind::Trait(p) if (lang_items.fn_trait() == Some(p.def_id()) || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) && p.self_ty() == ty => { - let i = pred.kind().rebind(p.trait_ref.args.type_at(1)); + let i = clause.kind().rebind(p.trait_ref.args.type_at(1)); if inputs.is_some_and(|inputs| i != inputs) { // Multiple different fn trait impls. Is this even allowed? return None; @@ -717,7 +717,7 @@ fn sig_from_bounds<'tcx>( // Multiple different fn trait impls. Is this even allowed? return None; } - output = Some(pred.kind().rebind(p.term.expect_type())); + output = Some(clause.kind().rebind(p.term.expect_type())); }, _ => (), } From bc0ad2b8fdceafd6dedd6ef296bf362aacc4982c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 29 May 2026 18:31:54 +1000 Subject: [PATCH 7/8] Eliminate two `as_predicate` and two `as_clause` calls `evaluate_predicates` creates some predicate lists from clauses, and then later converts them back to clauses. This commit avoids this back and forth. The only tricky part is the addition of an `expect_clause` call in `evaluate_nested_obligations` to extract a clause from a predicate that we've already matched as a clause. --- .../src/traits/auto_trait.rs | 56 +++++++++---------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 91ee04888ecab..c81efa6d4f511 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -243,9 +243,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { polarity: ty::PredicatePolarity::Positive, })); - let computed_preds = param_env.caller_bounds().iter().map(|c| c.as_predicate()); - let mut user_computed_preds: FxIndexSet<_> = - user_env.caller_bounds().iter().map(|c| c.as_predicate()).collect(); + let computed_clauses = param_env.caller_bounds().iter(); + let mut user_computed_clauses: FxIndexSet<_> = user_env.caller_bounds().iter().collect(); let mut new_env = param_env; let dummy_cause = ObligationCause::dummy(); @@ -290,7 +289,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { if !self.evaluate_nested_obligations( ty, obligations, - &mut user_computed_preds, + &mut user_computed_clauses, fresh_preds, &mut predicates, &mut select, @@ -302,7 +301,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { Err(SelectionError::Unimplemented) => { if self.is_param_no_infer(pred.skip_binder().trait_ref.args) { already_visited.remove(&pred); - self.add_user_pred(&mut user_computed_preds, pred.upcast(self.tcx)); + self.add_user_clause(&mut user_computed_clauses, pred.upcast(self.tcx)); predicates.push_back(pred); } else { debug!( @@ -318,16 +317,15 @@ impl<'tcx> AutoTraitFinder<'tcx> { _ => panic!("Unexpected error for '{ty:?}': {result:?}"), }; - let normalized_preds = - elaborate(tcx, computed_preds.clone().chain(user_computed_preds.iter().cloned())); - new_env = ty::ParamEnv::new( - tcx.mk_clauses_from_iter(normalized_preds.filter_map(|p| p.as_clause())), + let normalized_preds = elaborate( + tcx, + computed_clauses.clone().chain(user_computed_clauses.iter().cloned()), ); + new_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(normalized_preds)); } - let final_user_env = ty::ParamEnv::new( - tcx.mk_clauses_from_iter(user_computed_preds.into_iter().filter_map(|p| p.as_clause())), - ); + let final_user_env = + ty::ParamEnv::new(tcx.mk_clauses_from_iter(user_computed_clauses.into_iter())); debug!( "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ '{:?}'", @@ -360,17 +358,15 @@ impl<'tcx> AutoTraitFinder<'tcx> { /// under which a type implements an auto trait. A trait predicate involving /// a HRTB means that the type needs to work with any choice of lifetime, /// not just one specific lifetime (e.g., `'static`). - fn add_user_pred( + fn add_user_clause( &self, - user_computed_preds: &mut FxIndexSet>, - new_pred: ty::Predicate<'tcx>, + user_computed_clauses: &mut FxIndexSet>, + new_clause: ty::Clause<'tcx>, ) { let mut should_add_new = true; - user_computed_preds.retain(|&old_pred| { - if let ( - ty::PredicateKind::Clause(ty::ClauseKind::Trait(new_trait)), - ty::PredicateKind::Clause(ty::ClauseKind::Trait(old_trait)), - ) = (new_pred.kind().skip_binder(), old_pred.kind().skip_binder()) + user_computed_clauses.retain(|&old_clause| { + if let (ty::ClauseKind::Trait(new_trait), ty::ClauseKind::Trait(old_trait)) = + (new_clause.kind().skip_binder(), old_clause.kind().skip_binder()) { if new_trait.def_id() == old_trait.def_id() { let new_args = new_trait.trait_ref.args; @@ -378,7 +374,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { if !new_args.types().eq(old_args.types()) { // We can't compare lifetimes if the types are different, - // so skip checking `old_pred`. + // so skip checking `old_clause`. return true; } @@ -407,13 +403,13 @@ impl<'tcx> AutoTraitFinder<'tcx> { // variable). // // In both cases, we want to remove the old predicate, - // from `user_computed_preds`, and replace it with the new + // from `user_computed_clauses`, and replace it with the new // one. Having both the old and the new // predicate in a `ParamEnv` would confuse `SelectionContext`. // // We're currently in the predicate passed to 'retain', // so we return `false` to remove the old predicate from - // `user_computed_preds`. + // `user_computed_clauses`. return false; } (_, ty::ReBound(_, _)) | (ty::ReVar(_), _) => { @@ -429,8 +425,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { // predicate has some other type of region. // // We want to leave the old - // predicate in `user_computed_preds`, and skip adding - // new_pred to `user_computed_params`. + // predicate in `user_computed_clauses`, and skip adding + // new_clause to `user_computed_params`. should_add_new = false } _ => {} @@ -442,7 +438,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { }); if should_add_new { - user_computed_preds.insert(new_pred); + user_computed_clauses.insert(new_clause); } } @@ -571,7 +567,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { &self, ty: Ty<'_>, nested: impl Iterator>, - computed_preds: &mut FxIndexSet>, + computed_clauses: &mut FxIndexSet>, fresh_preds: &mut FxIndexSet>, predicates: &mut VecDeque>, selcx: &mut SelectionContext<'_, 'tcx>, @@ -625,7 +621,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { { debug!( "evaluate_nested_obligations: adding projection predicate \ - to computed_preds: {:?}", + to computed_clauses: {:?}", predicate ); @@ -645,7 +641,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { predicate equating a type with itself! Skipping" ); } else { - self.add_user_pred(computed_preds, predicate); + self.add_user_clause(computed_clauses, predicate.expect_clause()); } } @@ -714,7 +710,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { if !self.evaluate_nested_obligations( ty, v.into_iter(), - computed_preds, + computed_clauses, fresh_preds, predicates, selcx, From 7c8173c0a3443d468794de06068d0f3ceb1ca9dc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 May 2026 15:35:54 +1000 Subject: [PATCH 8/8] Adjust `prove_predicates`/`prove_predicate` Currently they both take arguments that can be upcast into a predicate. But in practice the arguments at all call sites are things that can be upcast to a clause. So this commits changes their names and types to work with clauses, which are more specific. --- .../src/type_check/canonical.rs | 28 +++++++++-------- compiler/rustc_borrowck/src/type_check/mod.rs | 31 +++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 56c800dcf7c7e..f4e345dbba9bc 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -130,10 +130,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) { - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait( - ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive }, - ))), + self.prove_clause( + ty::ClauseKind::Trait(ty::TraitPredicate { + trait_ref, + polarity: ty::PredicatePolarity::Positive, + }), locations, category, ); @@ -151,31 +152,32 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { for (predicate, span) in instantiated_predicates { debug!(?span, ?predicate); let category = ConstraintCategory::Predicate(span); - let predicate = self.normalize_with_category(predicate, locations, category); - self.prove_predicate(predicate, locations, category); + let clause = self.normalize_with_category(predicate, locations, category); + self.prove_clause(clause, locations, category); } } - pub(super) fn prove_predicates( + pub(super) fn prove_clauses( &mut self, - predicates: impl IntoIterator, ty::Predicate<'tcx>> + std::fmt::Debug>, + clauses: impl IntoIterator, ty::Clause<'tcx>> + std::fmt::Debug>, locations: Locations, category: ConstraintCategory<'tcx>, ) { - for predicate in predicates { - self.prove_predicate(predicate, locations, category); + for clause in clauses { + self.prove_clause(clause, locations, category); } } #[instrument(skip(self), level = "debug")] - pub(super) fn prove_predicate( + pub(super) fn prove_clause( &mut self, - predicate: impl Upcast, ty::Predicate<'tcx>> + std::fmt::Debug, + clause: impl Upcast, ty::Clause<'tcx>> + std::fmt::Debug, locations: Locations, category: ConstraintCategory<'tcx>, ) { let param_env = self.infcx.param_env; - let predicate = predicate.upcast(self.tcx()); + // Upcast to a `Clause`, then to a `Predicate`. + let predicate = clause.upcast(self.tcx()).upcast(self.tcx()); let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( locations, category, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 13983f349d6a5..fb4fae7aa223e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -820,12 +820,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // don't have to check it twice. // // See #91068 for an example. - self.prove_predicates( - unnormalized_sig.inputs_and_output.iter().map(|ty| { - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - ty.into(), - ))) - }), + self.prove_clauses( + unnormalized_sig + .inputs_and_output + .iter() + .map(|ty| ty::ClauseKind::WellFormed(ty.into())), term_location.to_locations(), ConstraintCategory::Boring, ); @@ -835,12 +834,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // with built-in `Fn` implementations, since the impl may not be // well-formed itself. if sig != unnormalized_sig { - self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| { - ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::WellFormed(ty.into()), - )) - }), + self.prove_clauses( + sig.inputs_and_output + .iter() + .map(|ty| ty::ClauseKind::WellFormed(ty.into())), term_location.to_locations(), ConstraintCategory::Boring, ); @@ -996,8 +993,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Repeat(operand, len) => { let array_ty = rvalue.ty(self.body.local_decls(), tcx); - self.prove_predicate( - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())), + self.prove_clause( + ty::ClauseKind::WellFormed(array_ty.into()), Locations::Single(location), ConstraintCategory::Boring, ); @@ -1082,7 +1079,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { src_sig, ); let src_ty = Ty::new_fn_ptr(self.tcx(), ty::Binder::dummy(src_sig)); - self.prove_predicate( + self.prove_clause( ty::ClauseKind::WellFormed(src_ty.into()), location.to_locations(), ConstraintCategory::Cast { @@ -1120,7 +1117,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // well-formed, because we don't enforce that via the WF of FnDef // types normally. This should be removed when we improve the tracking // of implied bounds of fn signatures. - self.prove_predicate( + self.prove_clause( ty::ClauseKind::WellFormed(src_ty.into()), location.to_locations(), ConstraintCategory::Cast { @@ -1833,7 +1830,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); assert_eq!(tcx.trait_impl_of_assoc(def_id), None); - self.prove_predicates( + self.prove_clauses( args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())), locations, ConstraintCategory::Boring,