1
Fork 0

effective visibility: Satisfy borrow checker to use resolver lazily from a closure

This commit is contained in:
Vadim Petrochenkov 2022-11-19 01:52:49 +03:00
parent d121aa3b55
commit 3f20f4ac42
2 changed files with 46 additions and 23 deletions

View file

@ -142,13 +142,13 @@ impl EffectiveVisibilities {
pub fn set_public_at_level( pub fn set_public_at_level(
&mut self, &mut self,
id: LocalDefId, id: LocalDefId,
default_vis: impl FnOnce() -> Visibility, lazy_private_vis: impl FnOnce() -> Visibility,
level: Level, level: Level,
) { ) {
let mut effective_vis = self let mut effective_vis = self
.effective_vis(id) .effective_vis(id)
.copied() .copied()
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis())); .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis()));
for l in Level::all_levels() { for l in Level::all_levels() {
if l <= level { if l <= level {
*effective_vis.at_level_mut(l) = Visibility::Public; *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<Id: Eq + Hash> EffectiveVisibilities<Id> { impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> { pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
self.map.iter() self.map.iter()
@ -217,21 +222,26 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
// `parent_id` is not necessarily a parent in source code tree, // `parent_id` is not necessarily a parent in source code tree,
// it is the node from which the maximum effective visibility is inherited. // it is the node from which the maximum effective visibility is inherited.
pub fn update( pub fn update<T: IntoDefIdTree>(
&mut self, &mut self,
id: Id, id: Id,
nominal_vis: Visibility, nominal_vis: Visibility,
default_vis: Visibility, lazy_private_vis: impl FnOnce(T) -> (Visibility, T),
inherited_eff_vis: Option<EffectiveVisibility>, inherited_eff_vis: Option<EffectiveVisibility>,
level: Level, level: Level,
tree: impl DefIdTree, mut into_tree: T,
) -> bool { ) -> bool {
let mut changed = false; let mut changed = false;
let mut current_effective_vis = self let mut current_effective_vis = match self.map.get(&id).copied() {
.map Some(eff_vis) => eff_vis,
.get(&id) None => {
.copied() let private_vis;
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_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 { if let Some(inherited_effective_vis) = inherited_eff_vis {
let mut inherited_effective_vis_at_prev_level = let mut inherited_effective_vis_at_prev_level =
*inherited_effective_vis.at_level(level); *inherited_effective_vis.at_level(level);

View file

@ -7,7 +7,8 @@ use rustc_ast::EnumDef;
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::CRATE_DEF_ID; 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; use rustc_middle::ty::Visibility;
type ImportId<'a> = Interned<'a, NameBinding<'a>>; type ImportId<'a> = Interned<'a, NameBinding<'a>>;
@ -29,6 +30,7 @@ impl ParentId<'_> {
pub struct EffectiveVisibilitiesVisitor<'r, 'a> { pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
r: &'r mut Resolver<'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 /// 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 /// 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. /// 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, 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> { impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
/// Fills the `Resolver::effective_visibilities` table with public & exported items /// Fills the `Resolver::effective_visibilities` table with public & exported items
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we /// 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) { pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
let mut visitor = EffectiveVisibilitiesVisitor { let mut visitor = EffectiveVisibilitiesVisitor {
r, r,
def_effective_visibilities: Default::default(),
import_effective_visibilities: Default::default(), import_effective_visibilities: Default::default(),
changed: false, changed: false,
}; };
@ -54,6 +70,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
visitor.changed = false; visitor.changed = false;
visit::walk_crate(&mut visitor, krate); 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 // Update visibilities for import def ids. These are not used during the
// `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based // `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); 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, /// Update effective visibilities of bindings in the given module,
/// including their whole reexport chains. /// including their whole reexport chains.
fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { 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<EffectiveVisibility> { fn effective_vis(&self, parent_id: ParentId<'a>) -> Option<EffectiveVisibility> {
match parent_id { 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), ParentId::Import(binding) => self.import_effective_visibilities.effective_vis(binding),
} }
.copied() .copied()
@ -150,7 +163,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
let default_vis = Visibility::Restricted( let default_vis = Visibility::Restricted(
import import
.id() .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), .unwrap_or(CRATE_DEF_ID),
); );
if self.is_noop_update(parent_id, nominal_vis, default_vis) { 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( self.changed |= self.import_effective_visibilities.update(
binding, binding,
nominal_vis, nominal_vis,
default_vis, |r| (default_vis, r),
self.effective_vis(parent_id), self.effective_vis(parent_id),
parent_id.level(), 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>) { 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) { if self.is_noop_update(parent_id, nominal_vis, default_vis) {
return; return;
} }
self.changed |= self.r.effective_visibilities.update( self.changed |= self.def_effective_visibilities.update(
def_id, def_id,
nominal_vis, 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), self.effective_vis(parent_id),
parent_id.level(), parent_id.level(),
ResolverTree(&self.r.definitions, &self.r.crate_loader), &mut *self.r,
); );
} }