privacy: Introduce some caching to type visiting in DefIdVisitorSkeleton

This commit is contained in:
Vadim Petrochenkov 2025-10-08 19:23:45 +03:00
parent 156499e561
commit f9464f827b

View file

@ -75,6 +75,9 @@ pub trait DefIdVisitor<'tcx> {
}
fn tcx(&self) -> TyCtxt<'tcx>;
/// NOTE: Def-id visiting should be idempotent (or at least produce duplicated errors),
/// because `DefIdVisitorSkeleton` will use caching and sometimes avoid visiting duplicate
/// def-ids. All the current visitors follow this rule.
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
-> Self::Result;
@ -82,7 +85,7 @@ pub trait DefIdVisitor<'tcx> {
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
DefIdVisitorSkeleton {
def_id_visitor: self,
visited_opaque_tys: Default::default(),
visited_tys: Default::default(),
dummy: Default::default(),
}
}
@ -102,7 +105,7 @@ pub trait DefIdVisitor<'tcx> {
pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
def_id_visitor: &'v mut V,
visited_opaque_tys: FxHashSet<DefId>,
visited_tys: FxHashSet<Ty<'tcx>>,
dummy: PhantomData<TyCtxt<'tcx>>,
}
@ -183,7 +186,8 @@ where
let tcx = self.def_id_visitor.tcx();
// GenericArgs are not visited here because they are visited below
// in `super_visit_with`.
match *ty.kind() {
let ty_kind = *ty.kind();
match ty_kind {
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
| ty::Foreign(def_id)
| ty::FnDef(def_id, ..)
@ -197,7 +201,7 @@ where
// Default type visitor doesn't visit signatures of fn types.
// Something like `fn() -> Priv {my_func}` is considered a private type even if
// `my_func` is public, so we need to visit signatures.
if let ty::FnDef(..) = ty.kind() {
if let ty::FnDef(..) = ty_kind {
// FIXME: this should probably use `args` from `FnDef`
try_visit!(tcx.fn_sig(def_id).instantiate_identity().visit_with(self));
}
@ -220,6 +224,12 @@ where
// free type aliases, but this isn't done yet.
return V::Result::output();
}
if !self.visited_tys.insert(ty) {
// Avoid repeatedly visiting alias types (including projections).
// This helps with special cases like #145741, but doesn't introduce
// too much overhead in general case, unlike caching for other types.
return V::Result::output();
}
try_visit!(self.def_id_visitor.visit_def_id(
data.def_id,
@ -259,7 +269,7 @@ where
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// Skip repeated `Opaque`s to avoid infinite recursion.
if self.visited_opaque_tys.insert(def_id) {
if self.visited_tys.insert(ty) {
// The intent is to treat `impl Trait1 + Trait2` identically to
// `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
// (it either has no visibility, or its visibility is insignificant, like