Skip to content

Commit f9464f8

Browse files
committed
privacy: Introduce some caching to type visiting in DefIdVisitorSkeleton
1 parent 156499e commit f9464f8

File tree

1 file changed

+15
-5
lines changed
  • compiler/rustc_privacy/src

1 file changed

+15
-5
lines changed

compiler/rustc_privacy/src/lib.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,17 @@ pub trait DefIdVisitor<'tcx> {
7575
}
7676

7777
fn tcx(&self) -> TyCtxt<'tcx>;
78+
/// NOTE: Def-id visiting should be idempotent (or at least produce duplicated errors),
79+
/// because `DefIdVisitorSkeleton` will use caching and sometimes avoid visiting duplicate
80+
/// def-ids. All the current visitors follow this rule.
7881
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
7982
-> Self::Result;
8083

8184
/// Not overridden, but used to actually visit types and traits.
8285
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
8386
DefIdVisitorSkeleton {
8487
def_id_visitor: self,
85-
visited_opaque_tys: Default::default(),
88+
visited_tys: Default::default(),
8689
dummy: Default::default(),
8790
}
8891
}
@@ -102,7 +105,7 @@ pub trait DefIdVisitor<'tcx> {
102105

103106
pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
104107
def_id_visitor: &'v mut V,
105-
visited_opaque_tys: FxHashSet<DefId>,
108+
visited_tys: FxHashSet<Ty<'tcx>>,
106109
dummy: PhantomData<TyCtxt<'tcx>>,
107110
}
108111

@@ -183,7 +186,8 @@ where
183186
let tcx = self.def_id_visitor.tcx();
184187
// GenericArgs are not visited here because they are visited below
185188
// in `super_visit_with`.
186-
match *ty.kind() {
189+
let ty_kind = *ty.kind();
190+
match ty_kind {
187191
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
188192
| ty::Foreign(def_id)
189193
| ty::FnDef(def_id, ..)
@@ -197,7 +201,7 @@ where
197201
// Default type visitor doesn't visit signatures of fn types.
198202
// Something like `fn() -> Priv {my_func}` is considered a private type even if
199203
// `my_func` is public, so we need to visit signatures.
200-
if let ty::FnDef(..) = ty.kind() {
204+
if let ty::FnDef(..) = ty_kind {
201205
// FIXME: this should probably use `args` from `FnDef`
202206
try_visit!(tcx.fn_sig(def_id).instantiate_identity().visit_with(self));
203207
}
@@ -220,6 +224,12 @@ where
220224
// free type aliases, but this isn't done yet.
221225
return V::Result::output();
222226
}
227+
if !self.visited_tys.insert(ty) {
228+
// Avoid repeatedly visiting alias types (including projections).
229+
// This helps with special cases like #145741, but doesn't introduce
230+
// too much overhead in general case, unlike caching for other types.
231+
return V::Result::output();
232+
}
223233

224234
try_visit!(self.def_id_visitor.visit_def_id(
225235
data.def_id,
@@ -259,7 +269,7 @@ where
259269
}
260270
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
261271
// Skip repeated `Opaque`s to avoid infinite recursion.
262-
if self.visited_opaque_tys.insert(def_id) {
272+
if self.visited_tys.insert(ty) {
263273
// The intent is to treat `impl Trait1 + Trait2` identically to
264274
// `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
265275
// (it either has no visibility, or its visibility is insignificant, like

0 commit comments

Comments
 (0)