diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 3a91522d362..decd213763d 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -142,13 +142,13 @@ impl EffectiveVisibilities { pub fn set_public_at_level( &mut self, id: LocalDefId, - default_vis: impl FnOnce() -> Visibility, + lazy_private_vis: impl FnOnce() -> Visibility, level: Level, ) { let mut effective_vis = self .effective_vis(id) .copied() - .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis())); + .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis())); for l in Level::all_levels() { if l <= level { *effective_vis.at_level_mut(l) = Visibility::Public; @@ -206,6 +206,11 @@ impl EffectiveVisibilities { } } +pub trait IntoDefIdTree { + type Tree: DefIdTree; + fn tree(self) -> Self::Tree; +} + impl EffectiveVisibilities { pub fn iter(&self) -> impl Iterator { self.map.iter() @@ -217,21 +222,26 @@ impl EffectiveVisibilities { // `parent_id` is not necessarily a parent in source code tree, // it is the node from which the maximum effective visibility is inherited. - pub fn update( + pub fn update( &mut self, id: Id, nominal_vis: Visibility, - default_vis: Visibility, + lazy_private_vis: impl FnOnce(T) -> (Visibility, T), inherited_eff_vis: Option, level: Level, - tree: impl DefIdTree, + mut into_tree: T, ) -> bool { let mut changed = false; - let mut current_effective_vis = self - .map - .get(&id) - .copied() - .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis)); + let mut current_effective_vis = match self.map.get(&id).copied() { + Some(eff_vis) => eff_vis, + None => { + let private_vis; + (private_vis, into_tree) = lazy_private_vis(into_tree); + EffectiveVisibility::from_vis(private_vis) + } + }; + let tree = into_tree.tree(); + if let Some(inherited_effective_vis) = inherited_eff_vis { let mut inherited_effective_vis_at_prev_level = *inherited_effective_vis.at_level(level); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 82dcc7efb1b..57fb1fa9389 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -7,7 +7,8 @@ use rustc_ast::EnumDef; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; +use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility}; +use rustc_middle::middle::privacy::{IntoDefIdTree, Level}; use rustc_middle::ty::Visibility; type ImportId<'a> = Interned<'a, NameBinding<'a>>; @@ -29,6 +30,7 @@ impl ParentId<'_> { pub struct EffectiveVisibilitiesVisitor<'r, 'a> { r: &'r mut Resolver<'a>, + def_effective_visibilities: EffectiveVisibilities, /// While walking import chains we need to track effective visibilities per-binding, and def id /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple /// bindings can correspond to a single def id in imports. So we keep a separate table. @@ -36,6 +38,19 @@ pub struct EffectiveVisibilitiesVisitor<'r, 'a> { changed: bool, } +impl Resolver<'_> { + fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId { + self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() + } +} + +impl<'a, 'b> IntoDefIdTree for &'b mut Resolver<'a> { + type Tree = &'b Resolver<'a>; + fn tree(self) -> Self::Tree { + self + } +} + impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { /// Fills the `Resolver::effective_visibilities` table with public & exported items /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we @@ -43,6 +58,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { let mut visitor = EffectiveVisibilitiesVisitor { r, + def_effective_visibilities: Default::default(), import_effective_visibilities: Default::default(), changed: false, }; @@ -54,6 +70,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { visitor.changed = false; visit::walk_crate(&mut visitor, krate); } + visitor.r.effective_visibilities = visitor.def_effective_visibilities; // Update visibilities for import def ids. These are not used during the // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based @@ -90,10 +107,6 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities); } - fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId { - self.r.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() - } - /// Update effective visibilities of bindings in the given module, /// including their whole reexport chains. fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { @@ -124,7 +137,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { fn effective_vis(&self, parent_id: ParentId<'a>) -> Option { match parent_id { - ParentId::Def(def_id) => self.r.effective_visibilities.effective_vis(def_id), + ParentId::Def(def_id) => self.def_effective_visibilities.effective_vis(def_id), ParentId::Import(binding) => self.import_effective_visibilities.effective_vis(binding), } .copied() @@ -150,7 +163,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { let default_vis = Visibility::Restricted( import .id() - .map(|id| self.nearest_normal_mod(self.r.local_def_id(id))) + .map(|id| self.r.nearest_normal_mod(self.r.local_def_id(id))) .unwrap_or(CRATE_DEF_ID), ); if self.is_noop_update(parent_id, nominal_vis, default_vis) { @@ -159,25 +172,25 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { self.changed |= self.import_effective_visibilities.update( binding, nominal_vis, - default_vis, + |r| (default_vis, r), self.effective_vis(parent_id), parent_id.level(), - ResolverTree(&self.r.definitions, &self.r.crate_loader), + &mut *self.r, ); } fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) { - let default_vis = Visibility::Restricted(self.nearest_normal_mod(def_id)); + let default_vis = Visibility::Restricted(self.r.nearest_normal_mod(def_id)); if self.is_noop_update(parent_id, nominal_vis, default_vis) { return; } - self.changed |= self.r.effective_visibilities.update( + self.changed |= self.def_effective_visibilities.update( def_id, nominal_vis, - if def_id == CRATE_DEF_ID { Visibility::Public } else { default_vis }, + |r| (if def_id == CRATE_DEF_ID { Visibility::Public } else { default_vis }, r), self.effective_vis(parent_id), parent_id.level(), - ResolverTree(&self.r.definitions, &self.r.crate_loader), + &mut *self.r, ); }