From f9464f827bd409476799b3efcbd2840098f38a0d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Oct 2025 19:23:45 +0300 Subject: [PATCH] privacy: Introduce some caching to type visiting in `DefIdVisitorSkeleton` --- compiler/rustc_privacy/src/lib.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index cb91a3257e24..e87bac6114dd 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -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, + visited_tys: FxHashSet>, dummy: PhantomData>, } @@ -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