Skip to content

Commit 086b2a4

Browse files
committed
Auto merge of #68031 - Marwes:fold_list, r=estebank
perf: Avoid creating a SmallVec if nothing changes during a fold Not sure if this helps but in theory it should be less work than what the current micro optimization does for `ty::Predicate` lists. (It would explain the overhead I am seeing from `perf`.)
2 parents 83beb0a + a1586f1 commit 086b2a4

File tree

1 file changed

+35
-17
lines changed

1 file changed

+35
-17
lines changed

src/librustc/ty/structural_impls.rs

+35-17
Original file line numberDiff line numberDiff line change
@@ -805,8 +805,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
805805

806806
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
807807
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
808-
let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
809-
folder.tcx().intern_existential_predicates(&v)
808+
fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v))
810809
}
811810

812811
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -816,8 +815,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>>
816815

817816
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
818817
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
819-
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
820-
folder.tcx().intern_type_list(&v)
818+
fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v))
821819
}
822820

823821
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -827,8 +825,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
827825

828826
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
829827
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
830-
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
831-
folder.tcx().intern_projs(&v)
828+
fold_list(*self, folder, |tcx, v| tcx.intern_projs(v))
832829
}
833830

834831
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -992,17 +989,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
992989

993990
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
994991
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
995-
// This code is hot enough that it's worth specializing for a list of
996-
// length 0. (No other length is common enough to be worth singling
997-
// out).
998-
if self.len() == 0 {
999-
self
1000-
} else {
1001-
// Don't bother interning if nothing changed, which is the common
1002-
// case.
1003-
let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
1004-
if v[..] == self[..] { self } else { folder.tcx().intern_predicates(&v) }
1005-
}
992+
fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v))
1006993
}
1007994

1008995
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -1075,3 +1062,34 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
10751062
false
10761063
}
10771064
}
1065+
1066+
// Does the equivalent of
1067+
// ```
1068+
// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
1069+
// folder.tcx().intern_*(&v)
1070+
// ```
1071+
fn fold_list<'tcx, F, T>(
1072+
list: &'tcx ty::List<T>,
1073+
folder: &mut F,
1074+
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
1075+
) -> &'tcx ty::List<T>
1076+
where
1077+
F: TypeFolder<'tcx>,
1078+
T: TypeFoldable<'tcx> + PartialEq + Copy,
1079+
{
1080+
let mut iter = list.iter();
1081+
// Look for the first element that changed
1082+
if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
1083+
let new_t = t.fold_with(folder);
1084+
if new_t == *t { None } else { Some((i, new_t)) }
1085+
}) {
1086+
// An element changed, prepare to intern the resulting list
1087+
let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
1088+
new_list.extend_from_slice(&list[..i]);
1089+
new_list.push(new_t);
1090+
new_list.extend(iter.map(|t| t.fold_with(folder)));
1091+
intern(folder.tcx(), &new_list)
1092+
} else {
1093+
list
1094+
}
1095+
}

0 commit comments

Comments
 (0)