Skip to content

Commit d8dd9f1

Browse files
Rollup merge of #162461 - jdonszelmann:restrict-fold-predicate, r=BoxyUwU
limit the api of `fold_predicate` and `visit_predicate` r? @lcnr or anyone in @rust-lang/initiative-trait-system-refactor In the future, we may want to start compressing clauses in the `ParamEnv`. One major problem was that we are leaking too many implementation details in `fold_predicate` and `visit_predicate`. Almost no code actually cares about dealing with an actual predicate there. Instead, what really matters is the type flags on a predicate for example. As such, this PR majorly limits the API that is exposed to a folder, hiding the underlying predicate data structure used. As an example why this matters: in the case of compressed clauses, this will mean we won't need to "decompress" them. Instead, we can just fold over the self type, not telling folders whether the predicate was or was not compressed at all. > [!NOTE] > I've not used an LLM for any part of this PR, or any other PR I make. This includes any related work like research.
2 parents 9318843 + 8622679 commit d8dd9f1

21 files changed

Lines changed: 184 additions & 79 deletions

File tree

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
22
use rustc_hir as hir;
33
use rustc_infer::traits::util;
44
use rustc_middle::ty::{
5-
self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
6-
Upcast, shift_vars,
5+
self, GenericArgs, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
6+
TypeVisitableExt, Upcast, shift_vars,
77
};
88
use rustc_middle::{bug, span_bug};
99
use rustc_span::Span;
@@ -347,7 +347,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
347347
}
348348
}
349349

350-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
350+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
351351
if !p.has_bound_vars() { p } else { p.super_fold_with(self) }
352352
}
353353
}

compiler/rustc_hir_typeck/src/writeback.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ use rustc_infer::traits::solve::Goal;
2121
use rustc_middle::traits::ObligationCause;
2222
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
2323
use rustc_middle::ty::{
24-
self, DefiningScopeKind, DefinitionSiteHiddenType, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder,
25-
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
26-
Unnormalized, fold_regions,
24+
self, DefiningScopeKind, DefinitionSiteHiddenType, Flags, PredicateProxy, Ty, TyCtxt,
25+
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
26+
TypeVisitableExt, TypeVisitor, Unnormalized, fold_regions,
2727
};
2828
use rustc_span::Span;
2929
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
@@ -1032,7 +1032,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
10321032
self.handle_term(ct, ty::Const::outer_exclusive_binder, ty::Const::new_error)
10331033
}
10341034

1035-
fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
1035+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, predicate: P) -> P {
10361036
assert!(
10371037
!self.should_normalize,
10381038
"normalizing predicates in writeback is not generally sound"

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_middle::ty::{
1313
self, BoundVar, Flags, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable,
1414
TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypingModeEqWrapper,
1515
};
16+
use rustc_type_ir::PredicateProxy;
1617
use smallvec::SmallVec;
1718
use tracing::debug;
1819

@@ -483,7 +484,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
483484
}
484485
}
485486

486-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
487+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
487488
if p.flags().intersects(self.needs_canonical_flags) { p.super_fold_with(self) } else { p }
488489
}
489490

compiler/rustc_infer/src/infer/canonical/instantiate.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_middle::ty::{
1111
self, DelayedMap, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
1212
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
1313
};
14+
use rustc_type_ir::PredicateProxy;
1415

1516
use crate::infer::canonical::{Canonical, CanonicalVarValues};
1617

@@ -124,7 +125,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
124125
}
125126
}
126127

127-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
128+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
128129
if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p }
129130
}
130131

compiler/rustc_infer/src/infer/resolve.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_middle::ty::{
33
self, Const, DelayedMap, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder,
44
TypeSuperFoldable, TypeVisitableExt,
55
};
6+
use rustc_type_ir::PredicateProxy;
67

78
use super::{FixupError, FixupResult, InferCtxt};
89
use crate::infer::TyOrConstInferVar;
@@ -57,7 +58,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
5758
}
5859
}
5960

60-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
61+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
6162
if !p.has_non_region_infer() { p } else { p.super_fold_with(self) }
6263
}
6364

compiler/rustc_middle/src/ty/erase_regions.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_type_ir::PredicateProxy;
12
use tracing::debug;
23

34
use crate::query::Providers;
@@ -79,7 +80,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserAndAnonymizerVisitor<'tcx> {
7980
}
8081
}
8182

82-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
83+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
8384
if p.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) {
8485
p.super_fold_with(self)
8586
} else {

compiler/rustc_middle/src/ty/fold.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_data_structures::fx::FxIndexMap;
22
use rustc_hir::def_id::DefId;
3+
use rustc_type_ir::PredicateProxy;
34
use rustc_type_ir::data_structures::DelayedMap;
45

56
use crate::ty::{
@@ -180,7 +181,7 @@ where
180181
}
181182
}
182183

183-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
184+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
184185
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
185186
}
186187

compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ use rustc_abi::TyAndLayout;
99
use rustc_hir::def::Namespace;
1010
use rustc_hir::def_id::LocalDefId;
1111
use rustc_span::Spanned;
12-
use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit};
12+
use rustc_type_ir::{ConstKind, PredicateProxy, TypeFolder, Upcast, VisitorResult, try_visit};
1313

1414
use super::{GenericArg, GenericArgKind, Pattern};
1515
use crate::mir::PlaceElem;
1616
use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths};
1717
use crate::ty::{
18-
self, FallibleTypeFolder, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
19-
TypeSuperVisitable, TypeVisitable, TypeVisitor,
18+
self, Binder, FallibleTypeFolder, Lift, ProjectionClause, Term, TermKind, Ty, TyCtxt,
19+
TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
2020
};
2121

2222
impl fmt::Debug for ty::TraitDef {
@@ -491,17 +491,84 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
491491
}
492492
}
493493

494+
impl<'tcx> PredicateProxy<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
495+
fn allow_normalization(&self) -> bool {
496+
rustc_type_ir::inherent::Predicate::allow_normalization(*self)
497+
}
498+
499+
fn map_projection(
500+
self,
501+
tcx: TyCtxt<'tcx>,
502+
f: impl FnOnce(Binder<'tcx, ProjectionClause<'tcx>>) -> Binder<'tcx, ProjectionClause<'tcx>>,
503+
) -> Option<Self> {
504+
self.as_projection_clause().map(|kind| f(kind).upcast(tcx))
505+
}
506+
507+
fn clause_kind_unchecked(&self) -> Option<ty::Binder<'tcx, ty::ClauseKind<'tcx>>> {
508+
self.as_clause().map(|clause| clause.kind())
509+
}
510+
}
511+
494512
// FIXME(clause): This is wonky
495513
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clause<'tcx> {
496514
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
497515
self,
498516
folder: &mut F,
499517
) -> Result<Self, F::Error> {
500-
Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause())
518+
Ok(folder.try_fold_predicate(self)?)
501519
}
502520

503521
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
504-
folder.fold_predicate(self.as_predicate()).expect_clause()
522+
folder.fold_predicate(self)
523+
}
524+
}
525+
526+
// follow `Predicate`'s implementation (by deferring to it)
527+
impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Clause<'tcx> {
528+
fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
529+
self,
530+
folder: &mut F,
531+
) -> Result<Self, F::Error> {
532+
<ty::Predicate<'_> as TypeSuperFoldable<TyCtxt<'tcx>>>::try_super_fold_with(
533+
self.as_predicate(),
534+
folder,
535+
)
536+
.map(|i| i.expect_clause())
537+
}
538+
539+
fn super_fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
540+
<ty::Predicate<'_> as TypeSuperFoldable<TyCtxt<'tcx>>>::super_fold_with(
541+
self.as_predicate(),
542+
folder,
543+
)
544+
.expect_clause()
545+
}
546+
}
547+
548+
impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Clause<'tcx> {
549+
fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
550+
<ty::Predicate<'_> as TypeSuperVisitable<TyCtxt<'tcx>>>::super_visit_with(
551+
&self.as_predicate(),
552+
visitor,
553+
)
554+
}
555+
}
556+
557+
impl<'tcx> PredicateProxy<TyCtxt<'tcx>> for ty::Clause<'tcx> {
558+
fn allow_normalization(&self) -> bool {
559+
self.as_predicate().allow_normalization()
560+
}
561+
562+
fn map_projection(
563+
self,
564+
tcx: TyCtxt<'tcx>,
565+
f: impl FnOnce(Binder<'tcx, ProjectionClause<'tcx>>) -> Binder<'tcx, ProjectionClause<'tcx>>,
566+
) -> Option<Self> {
567+
self.as_projection_clause().map(|kind| f(kind).upcast(tcx))
568+
}
569+
570+
fn clause_kind_unchecked(&self) -> Option<ty::Binder<'tcx, ty::ClauseKind<'tcx>>> {
571+
Some(self.kind())
505572
}
506573
}
507574

compiler/rustc_middle/src/ty/util.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_index::bit_set::GrowableBitSet;
1515
use rustc_macros::{StableHash, TyDecodable, TyEncodable, extension};
1616
use rustc_span::sym;
1717
use rustc_structures::Limit;
18+
use rustc_type_ir::PredicateProxy;
1819
use rustc_type_ir::solve::SizedTraitKind;
1920
use smallvec::{SmallVec, smallvec};
2021
use tracing::{debug, instrument};
@@ -27,7 +28,7 @@ use crate::traits::ObligationCause;
2728
use crate::ty::layout::{FloatExt, IntegerExt};
2829
use crate::ty::{
2930
self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
30-
TypeFolder, TypeSuperFoldable, TypeVisitableExt, Unnormalized, Upcast,
31+
TypeFolder, TypeSuperFoldable, TypeVisitableExt, Unnormalized,
3132
};
3233

3334
#[derive(Copy, Clone, Debug)]
@@ -1037,24 +1038,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
10371038
}
10381039
}
10391040

1040-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
1041-
if let ty::PredicateKind::Clause(clause) = p.kind().skip_binder()
1042-
&& let ty::ClauseKind::Projection(projection_pred) = clause
1043-
{
1044-
p.kind()
1045-
.rebind(ty::ProjectionClause {
1046-
projection_term: projection_pred.projection_term.fold_with(self),
1047-
// Don't fold the term on the RHS of the projection predicate.
1048-
// This is because for default trait methods with RPITITs, we
1049-
// install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))`
1050-
// predicate, which would trivially cause a cycle when we do
1051-
// anything that requires `TypingEnv::with_post_analysis_normalized`.
1052-
term: projection_pred.term,
1053-
})
1054-
.upcast(self.tcx)
1055-
} else {
1056-
p.super_fold_with(self)
1057-
}
1041+
fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
1042+
// We use `map_projection` to execute the closure only if `p` is a projection clause,
1043+
// to implement the logic described below (i.e. avoid folding the `term`).
1044+
// In all other cases, fold recursively, as normal.
1045+
p.map_projection(self.tcx, |bound_clause| {
1046+
let projection_clause = bound_clause.skip_binder();
1047+
bound_clause.rebind(ty::ProjectionClause {
1048+
projection_term: projection_clause.projection_term.fold_with(self),
1049+
// Don't fold the term on the RHS of the projection predicate.
1050+
// This is because for default trait methods with RPITITs, we
1051+
// install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))`
1052+
// predicate, which would trivially cause a cycle when we do
1053+
// anything that requires `TypingEnv::with_post_analysis_normalized`.
1054+
term: projection_clause.term,
1055+
})
1056+
})
1057+
.unwrap_or_else(|| p.super_fold_with(self))
10581058
}
10591059
}
10601060

compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use rustc_type_ir::inherent::*;
55
use rustc_type_ir::solve::{Goal, QueryInput};
66
use rustc_type_ir::{
77
self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, CanonicalizerState,
8-
Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, Region, TypeFlags,
9-
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
8+
Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, PredicateProxy, Region,
9+
TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
1010
};
1111
use thin_vec::ThinVec;
1212

@@ -583,7 +583,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
583583
Const::new_canonical_bound(self.cx(), var)
584584
}
585585

586-
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
586+
fn fold_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> P {
587587
if !p.flags().intersects(NEEDS_CANONICAL) { p } else { p.super_fold_with(self) }
588588
}
589589

0 commit comments

Comments
 (0)