effective visibility: Always add table entries for nodes used as parents

Previously if the parent was not in the table, and there was nothing to inherit from, the child's private visibility was used, but that's not correct - the parent may have a larger visibility so we should set it to at least the parent's private visibility.
That parent's private visibility is also inserted into the table for caching, so it's not recalculated later if used again.
This commit is contained in:
Vadim Petrochenkov 2022-11-23 20:31:35 +03:00
parent a45a302be5
commit 7e76d94a22
2 changed files with 51 additions and 40 deletions

View file

@ -213,14 +213,21 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
self.map.get(&id) self.map.get(&id)
} }
// `parent_id` is not necessarily a parent in source code tree, // FIXME: Share code with `fn update`.
// it is the node from which the maximum effective visibility is inherited. pub fn effective_vis_or_private(
&mut self,
id: Id,
lazy_private_vis: impl FnOnce() -> Visibility,
) -> &EffectiveVisibility {
self.map.entry(id).or_insert_with(|| EffectiveVisibility::from_vis(lazy_private_vis()))
}
pub fn update<T: IntoDefIdTree>( pub fn update<T: IntoDefIdTree>(
&mut self, &mut self,
id: Id, id: Id,
nominal_vis: Visibility, nominal_vis: Visibility,
lazy_private_vis: impl FnOnce(T) -> (Visibility, T), lazy_private_vis: impl FnOnce(T) -> (Visibility, T),
inherited_eff_vis: Option<EffectiveVisibility>, inherited_effective_vis: EffectiveVisibility,
level: Level, level: Level,
mut into_tree: T, mut into_tree: T,
) -> bool { ) -> bool {
@ -235,9 +242,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
}; };
let tree = into_tree.tree(); 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);
let mut inherited_effective_vis_at_prev_level =
*inherited_effective_vis.at_level(level);
let mut calculated_effective_vis = inherited_effective_vis_at_prev_level; let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
for l in Level::all_levels() { for l in Level::all_levels() {
if level >= l { if level >= l {
@ -258,8 +263,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
// effective visibility can't be decreased at next update call for the // effective visibility can't be decreased at next update call for the
// same id // same id
if *current_effective_vis_at_level != calculated_effective_vis if *current_effective_vis_at_level != calculated_effective_vis
&& calculated_effective_vis && calculated_effective_vis.is_at_least(*current_effective_vis_at_level, tree)
.is_at_least(*current_effective_vis_at_level, tree)
{ {
changed = true; changed = true;
*current_effective_vis_at_level = calculated_effective_vis; *current_effective_vis_at_level = calculated_effective_vis;
@ -267,7 +271,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
inherited_effective_vis_at_prev_level = inherited_effective_vis_at_level; inherited_effective_vis_at_prev_level = inherited_effective_vis_at_level;
} }
} }
}
self.map.insert(id, current_effective_vis); self.map.insert(id, current_effective_vis);
changed changed
} }

View file

@ -155,32 +155,39 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
} }
} }
fn effective_vis(&self, parent_id: ParentId<'a>) -> Option<EffectiveVisibility> { fn effective_vis_or_private(&mut self, parent_id: ParentId<'a>) -> EffectiveVisibility {
match parent_id { // Private nodes are only added to the table for caching, they could be added or removed at
ParentId::Def(def_id) => self.def_effective_visibilities.effective_vis(def_id), // any moment without consequences, so we don't set `changed` to true when adding them.
ParentId::Import(binding) => self.import_effective_visibilities.effective_vis(binding), *match parent_id {
ParentId::Def(def_id) => self
.def_effective_visibilities
.effective_vis_or_private(def_id, || self.r.private_vis_def(def_id)),
ParentId::Import(binding) => self
.import_effective_visibilities
.effective_vis_or_private(binding, || self.r.private_vis_import(binding)),
} }
.copied()
} }
fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) { fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) {
let nominal_vis = binding.vis.expect_local(); let nominal_vis = binding.vis.expect_local();
let inherited_eff_vis = self.effective_vis_or_private(parent_id);
self.changed |= self.import_effective_visibilities.update( self.changed |= self.import_effective_visibilities.update(
binding, binding,
nominal_vis, nominal_vis,
|r| (r.private_vis_import(binding), r), |r| (r.private_vis_import(binding), r),
self.effective_vis(parent_id), inherited_eff_vis,
parent_id.level(), parent_id.level(),
&mut *self.r, &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 inherited_eff_vis = self.effective_vis_or_private(parent_id);
self.changed |= self.def_effective_visibilities.update( self.changed |= self.def_effective_visibilities.update(
def_id, def_id,
nominal_vis, nominal_vis,
|r| (r.private_vis_def(def_id), r), |r| (r.private_vis_def(def_id), r),
self.effective_vis(parent_id), inherited_eff_vis,
parent_id.level(), parent_id.level(),
&mut *self.r, &mut *self.r,
); );