diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 4874eacd79b63..b3fbdc03e8478 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::{ - self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, - Upcast, shift_vars, + self, GenericArgs, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, Upcast, shift_vars, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; @@ -347,7 +347,7 @@ impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if !p.has_bound_vars() { p } else { p.super_fold_with(self) } } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 7b1f38f882747..b71290b658744 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -21,9 +21,9 @@ use rustc_infer::traits::solve::Goal; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::{ - self, DefiningScopeKind, DefinitionSiteHiddenType, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - Unnormalized, fold_regions, + self, DefiningScopeKind, DefinitionSiteHiddenType, Flags, PredicateProxy, Ty, TyCtxt, + TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, Unnormalized, fold_regions, }; use rustc_span::Span; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; @@ -1032,7 +1032,7 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { self.handle_term(ct, ty::Const::outer_exclusive_binder, ty::Const::new_error) } - fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, predicate: P) -> P { assert!( !self.should_normalize, "normalizing predicates in writeback is not generally sound" diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 770520413c666..9b3deac32222b 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{ self, BoundVar, Flags, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypingModeEqWrapper, }; +use rustc_type_ir::PredicateProxy; use smallvec::SmallVec; use tracing::debug; @@ -483,7 +484,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.flags().intersects(self.needs_canonical_flags) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index 7e670cc233752..2bc7e269efc9d 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::{ self, DelayedMap, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_type_ir::PredicateProxy; use crate::infer::canonical::{Canonical, CanonicalVarValues}; @@ -124,7 +125,7 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 13df23a39b967..db4f313903a5a 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -3,6 +3,7 @@ use rustc_middle::ty::{ self, Const, DelayedMap, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +use rustc_type_ir::PredicateProxy; use super::{FixupError, FixupResult, InferCtxt}; use crate::infer::TyOrConstInferVar; @@ -57,7 +58,7 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if !p.has_non_region_infer() { p } else { p.super_fold_with(self) } } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 74b4adda7fdd4..e1e138374209c 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -1,3 +1,4 @@ +use rustc_type_ir::PredicateProxy; use tracing::debug; use crate::query::Providers; @@ -79,7 +80,7 @@ impl<'tcx> TypeFolder> for RegionEraserAndAnonymizerVisitor<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { p.super_fold_with(self) } else { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 3d9148d6ed7ba..c19cda4f3edea 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; +use rustc_type_ir::PredicateProxy; use rustc_type_ir::data_structures::DelayedMap; use crate::ty::{ @@ -180,7 +181,7 @@ where } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index eb3a53d8fa968..0ea7e403ee111 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -9,14 +9,14 @@ use rustc_abi::TyAndLayout; use rustc_hir::def::Namespace; use rustc_hir::def_id::LocalDefId; use rustc_span::Spanned; -use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit}; +use rustc_type_ir::{ConstKind, PredicateProxy, TypeFolder, Upcast, VisitorResult, try_visit}; use super::{GenericArg, GenericArgKind, Pattern}; use crate::mir::PlaceElem; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; use crate::ty::{ - self, FallibleTypeFolder, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, Binder, FallibleTypeFolder, Lift, ProjectionClause, Term, TermKind, Ty, TyCtxt, + TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; impl fmt::Debug for ty::TraitDef { @@ -491,17 +491,84 @@ impl<'tcx> TypeFoldable> for ty::Predicate<'tcx> { } } +impl<'tcx> PredicateProxy> for ty::Predicate<'tcx> { + fn allow_normalization(&self) -> bool { + rustc_type_ir::inherent::Predicate::allow_normalization(*self) + } + + fn map_projection( + self, + tcx: TyCtxt<'tcx>, + f: impl FnOnce(Binder<'tcx, ProjectionClause<'tcx>>) -> Binder<'tcx, ProjectionClause<'tcx>>, + ) -> Option { + self.as_projection_clause().map(|kind| f(kind).upcast(tcx)) + } + + fn clause_kind_unchecked(&self) -> Option>> { + self.as_clause().map(|clause| clause.kind()) + } +} + // FIXME(clause): This is wonky impl<'tcx> TypeFoldable> for ty::Clause<'tcx> { fn try_fold_with>>( self, folder: &mut F, ) -> Result { - Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) + Ok(folder.try_fold_predicate(self)?) } fn fold_with>>(self, folder: &mut F) -> Self { - folder.fold_predicate(self.as_predicate()).expect_clause() + folder.fold_predicate(self) + } +} + +// follow `Predicate`'s implementation (by deferring to it) +impl<'tcx> TypeSuperFoldable> for ty::Clause<'tcx> { + fn try_super_fold_with>>( + self, + folder: &mut F, + ) -> Result { + as TypeSuperFoldable>>::try_super_fold_with( + self.as_predicate(), + folder, + ) + .map(|i| i.expect_clause()) + } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + as TypeSuperFoldable>>::super_fold_with( + self.as_predicate(), + folder, + ) + .expect_clause() + } +} + +impl<'tcx> TypeSuperVisitable> for ty::Clause<'tcx> { + fn super_visit_with>>(&self, visitor: &mut V) -> V::Result { + as TypeSuperVisitable>>::super_visit_with( + &self.as_predicate(), + visitor, + ) + } +} + +impl<'tcx> PredicateProxy> for ty::Clause<'tcx> { + fn allow_normalization(&self) -> bool { + self.as_predicate().allow_normalization() + } + + fn map_projection( + self, + tcx: TyCtxt<'tcx>, + f: impl FnOnce(Binder<'tcx, ProjectionClause<'tcx>>) -> Binder<'tcx, ProjectionClause<'tcx>>, + ) -> Option { + self.as_projection_clause().map(|kind| f(kind).upcast(tcx)) + } + + fn clause_kind_unchecked(&self) -> Option>> { + Some(self.kind()) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 622086b56c638..5361d9268f6a6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -15,6 +15,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_macros::{StableHash, TyDecodable, TyEncodable, extension}; use rustc_span::sym; use rustc_structures::Limit; +use rustc_type_ir::PredicateProxy; use rustc_type_ir::solve::SizedTraitKind; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -27,7 +28,7 @@ use crate::traits::ObligationCause; use crate::ty::layout::{FloatExt, IntegerExt}; use crate::ty::{ self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable, - TypeFolder, TypeSuperFoldable, TypeVisitableExt, Unnormalized, Upcast, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, Unnormalized, }; #[derive(Copy, Clone, Debug)] @@ -1037,24 +1038,23 @@ impl<'tcx> TypeFolder> for OpaqueTypeExpander<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if let ty::PredicateKind::Clause(clause) = p.kind().skip_binder() - && let ty::ClauseKind::Projection(projection_pred) = clause - { - p.kind() - .rebind(ty::ProjectionClause { - projection_term: projection_pred.projection_term.fold_with(self), - // Don't fold the term on the RHS of the projection predicate. - // This is because for default trait methods with RPITITs, we - // install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))` - // predicate, which would trivially cause a cycle when we do - // anything that requires `TypingEnv::with_post_analysis_normalized`. - term: projection_pred.term, - }) - .upcast(self.tcx) - } else { - p.super_fold_with(self) - } + fn fold_predicate>>(&mut self, p: P) -> P { + // We use `map_projection` to execute the closure only if `p` is a projection clause, + // to implement the logic described below (i.e. avoid folding the `term`). + // In all other cases, fold recursively, as normal. + p.map_projection(self.tcx, |bound_clause| { + let projection_clause = bound_clause.skip_binder(); + bound_clause.rebind(ty::ProjectionClause { + projection_term: projection_clause.projection_term.fold_with(self), + // Don't fold the term on the RHS of the projection predicate. + // This is because for default trait methods with RPITITs, we + // install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))` + // predicate, which would trivially cause a cycle when we do + // anything that requires `TypingEnv::with_post_analysis_normalized`. + term: projection_clause.term, + }) + }) + .unwrap_or_else(|| p.super_fold_with(self)) } } diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index cf36b1922b8c1..6047966248bb2 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -5,8 +5,8 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::{ self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, CanonicalizerState, - Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, Region, TypeFlags, - TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, PredicateProxy, Region, + TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use thin_vec::ThinVec; @@ -583,7 +583,7 @@ impl, I: Interner> TypeFolder for Canonicaliz Const::new_canonical_bound(self.cx(), var) } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if !p.flags().intersects(NEEDS_CANONICAL) { p } else { p.super_fold_with(self) } } diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index ff9ed6cb06cfd..1fd62213b735a 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -2,8 +2,8 @@ use std::fmt::Debug; use rustc_type_ir::inherent::*; use rustc_type_ir::{ - self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, TypeFoldable, - TypeSuperFoldable, TypeVisitableExt, UniverseIndex, eager_resolve_vars, + self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, PredicateProxy, + TypeFoldable, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, eager_resolve_vars, }; use tracing::instrument; @@ -197,7 +197,7 @@ where Ok(normalized) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { + fn try_fold_predicate>(&mut self, p: P) -> Result { if p.allow_normalization() { p.try_super_fold_with(self) } else { Ok(p) } } } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index 83b2eb6ac6295..e24037e2da7cd 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -4,7 +4,7 @@ use rustc_type_ir::data_structures::IndexMap; use rustc_type_ir::inherent::*; use rustc_type_ir::{ self as ty, InferCtxtLike, Interner, PlaceholderConst, PlaceholderRegion, PlaceholderType, - Region, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + PredicateProxy, Region, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use tracing::debug; @@ -183,7 +183,7 @@ where } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 697a7ad53464b..ae5cf61aac91e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -18,8 +18,9 @@ use rustc_type_ir::solve::{ }; use rustc_type_ir::{ self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased, - OpaqueTypeKey, PredicateKind, Region, RegionVid, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, eager_resolve_vars, max_universe, + OpaqueTypeKey, PredicateKind, PredicateProxy, Region, RegionVid, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + eager_resolve_vars, max_universe, }; use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; @@ -1177,7 +1178,7 @@ where } } - fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, p: P) -> Self::Result { if p.has_non_region_infer() || p.has_placeholders() { p.super_visit_with(self) } else { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9f1ff3fa6bc6b..5eea894c19c37 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -31,8 +31,8 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, use rustc_middle::query::Providers; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, AssocContainer, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitor, + self, AssocContainer, Const, GenericParamDefKind, PredicateProxy, TraitRef, Ty, TyCtxt, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_span::{Ident, Span, Symbol, sym}; @@ -130,8 +130,8 @@ where } } - fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> V::Result { - match clause.kind().skip_binder() { + fn visit_clause(&mut self, clause: ty::Binder<'tcx, ty::ClauseKind<'tcx>>) -> V::Result { + match clause.skip_binder() { ty::ClauseKind::Trait(ty::TraitClause { trait_ref, polarity: _ }) => { self.visit_trait(trait_ref) } @@ -160,7 +160,7 @@ where fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> V::Result { for &(clause, _) in clauses { - try_visit!(self.visit_clause(clause)); + try_visit!(self.visit_clause(clause.kind())); } V::Result::output() } @@ -172,8 +172,8 @@ where { type Result = V::Result; - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> Self::Result { - self.visit_clause(p.as_clause().unwrap()) + fn visit_predicate>>(&mut self, p: P) -> Self::Result { + self.visit_clause(p.clause_kind_unchecked().unwrap()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 56df5d917e108..2d2c4ff38acee 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -10,8 +10,8 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ - self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, - TypeVisitableExt, TypingMode, Unnormalized, + self, AliasTerm, PredicateProxy, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitable, TypeVisitableExt, TypingMode, Unnormalized, }; use thin_vec::ThinVec; use tracing::{debug, instrument}; @@ -512,7 +512,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } #[inline] - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) { p.super_fold_with(self) } else { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 96e41f89be573..c4994fa5c4b7a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::PredicateObligations; use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; use rustc_middle::ty::{ - self, FallibleTypeFolder, Flags, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + self, FallibleTypeFolder, Flags, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized, }; use rustc_span::DUMMY_SP; @@ -290,10 +290,10 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } #[inline] - fn try_fold_predicate( + fn try_fold_predicate>>( &mut self, - p: ty::Predicate<'tcx>, - ) -> Result, Self::Error> { + p: P, + ) -> Result { if p.allow_normalization() && needs_normalization(self.infcx, &p) { p.try_super_fold_with(self) } else { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5fc9e57795b72..1dc5470d58af7 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -10,8 +10,8 @@ use rustc_hir::attrs::lang_items::LangItem; use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, PredicateObligations}; use rustc_middle::bug; use rustc_middle::ty::{ - self, DelayedSet, GenericArgsRef, Term, TermKind, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + self, DelayedSet, GenericArgsRef, PredicateProxy, Term, TermKind, Ty, TyCtxt, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_session::diagnostics::feature_err; use rustc_span::def_id::{DefId, LocalDefId}; @@ -1240,7 +1240,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { c.super_visit_with(self) } - fn visit_predicate(&mut self, _p: ty::Predicate<'tcx>) -> Self::Result { + fn visit_predicate>>(&mut self, _p: P) -> Self::Result { bug!("predicate should not be checked for well-formedness"); } } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 7fc29cd8ebcf1..a16610a520406 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -15,7 +15,9 @@ use crate::data_structures::SsoHashSet; use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::inherent::*; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, DebruijnIndex, Interner, Region, UniverseIndex, Unnormalized}; +use crate::{ + self as ty, DebruijnIndex, Interner, PredicateProxy, Region, UniverseIndex, Unnormalized, +}; /// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -747,7 +749,7 @@ impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_param() { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index f57a9aba69302..2b25de4132e62 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -55,7 +55,10 @@ use tracing::{debug, instrument}; use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; -use crate::{self as ty, BoundVarIndexKind, Interner, Region}; +use crate::{ + self as ty, Binder, BoundVarIndexKind, ClauseKind, Flags, Interner, ProjectionClause, Region, + TypeSuperVisitable, +}; /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. @@ -145,7 +148,7 @@ pub trait TypeFolder: Sized { c.super_fold_with(self) } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { p.super_fold_with(self) } @@ -154,6 +157,33 @@ pub trait TypeFolder: Sized { } } +/// [Fold predicate](TypeFolder::fold_predicate) deliberately doesn't get access +/// to an actual predicate. This way, we can compress lists of predicates, and hide +/// this detail to folders. Instead, some type implementing this trait, [`PredicateProxy`] +/// is passed, with its limited API. +/// +/// Most [`TypeFolder`]s only use `fold_predicate` to inspect type flags. +pub trait PredicateProxy: + TypeSuperFoldable + TypeSuperVisitable + Flags + Copy +{ + fn allow_normalization(&self) -> bool; + + /// Gets the underlying clause kind (if this predicate is a clause, otherwise `None`). + /// The fact that it's `unchecked`, is because no attempt is made to hide implementation + /// details. For example, in the future we may compress clauses together. Code calling + /// `clause_kind_unchecked` will have to correctly deal with these implementation details, + /// and have code handling any edgecase arising as a result. + fn clause_kind_unchecked(&self) -> Option>>; + + /// If self is a projection clause, call `f` with it. The result will be rebound and returned as `Some`. + /// Otherwise, when self is not a projection clause, `None` is returned. + fn map_projection( + self, + cx: I, + f: impl FnOnce(Binder>) -> Binder>, + ) -> Option; +} + /// This trait is implemented for every folding traversal. There is a fold /// method defined for every type of interest. Each such method has a default /// that does an "identity" fold. @@ -187,7 +217,7 @@ pub trait FallibleTypeFolder: Sized { c.try_super_fold_with(self) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { + fn try_fold_predicate>(&mut self, p: P) -> Result { p.try_super_fold_with(self) } @@ -430,7 +460,7 @@ impl TypeFolder for Shifter { } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } @@ -546,7 +576,7 @@ where if ct.has_regions() { ct.super_fold_with(self) } else { ct } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_regions() { p.super_fold_with(self) } else { p } } @@ -692,7 +722,7 @@ impl TypeFolder for RigidnessFolder { } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if self.mode.needs_change(&p) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 31fe3cf99d88c..8d1d3372fac69 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -11,8 +11,8 @@ use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; use crate::solve::{TyOrConstInferVar, VisibleForLeakCheck}; use crate::{ - self as ty, Interner, Region, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, + self as ty, Interner, PredicateProxy, Region, TyVid, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, }; mod private { @@ -717,7 +717,7 @@ impl, I: Interner> TypeFolder for EagerRes } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_infer() { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 360687f530690..1138d8cf9edad 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -52,7 +52,7 @@ use smallvec::SmallVec; use thin_vec::ThinVec; use crate::inherent::*; -use crate::{self as ty, Interner, Region, TypeFlags}; +use crate::{self as ty, Interner, PredicateProxy, Region, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -116,7 +116,7 @@ pub trait TypeVisitor: Sized { c.super_visit_with(self) } - fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, p: P) -> Self::Result { p.super_visit_with(self) } @@ -485,7 +485,7 @@ impl TypeVisitor for HasTypeFlagsVisitor { } #[inline] - fn visit_predicate(&mut self, predicate: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, predicate: P) -> Self::Result { // Note: no `super_visit_with` call. if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) @@ -597,7 +597,7 @@ impl TypeVisitor for HasEscapingVarsVisitor { } #[inline] - fn visit_predicate(&mut self, predicate: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, predicate: P) -> Self::Result { if predicate.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else {