summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve/src/effective_visibilities.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_resolve/src/effective_visibilities.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_resolve/src/effective_visibilities.rs')
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs227
1 files changed, 144 insertions, 83 deletions
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index c40669ac9..85399385d 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -1,41 +1,120 @@
-use crate::{ImportKind, NameBindingKind, Resolver};
+use crate::{NameBinding, NameBindingKind, Resolver, ResolverTree};
use rustc_ast::ast;
use rustc_ast::visit;
use rustc_ast::visit::Visitor;
use rustc_ast::Crate;
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::Level;
+use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility};
+use rustc_middle::middle::privacy::{IntoDefIdTree, Level};
use rustc_middle::ty::{DefIdTree, Visibility};
+use std::mem;
+
+type ImportId<'a> = Interned<'a, NameBinding<'a>>;
+
+#[derive(Clone, Copy)]
+enum ParentId<'a> {
+ Def(LocalDefId),
+ Import(ImportId<'a>),
+}
+
+impl ParentId<'_> {
+ fn level(self) -> Level {
+ match self {
+ ParentId::Def(_) => Level::Direct,
+ ParentId::Import(_) => Level::Reexported,
+ }
+ }
+}
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.
+ import_effective_visibilities: EffectiveVisibilities<ImportId<'a>>,
+ // It's possible to recalculate this at any point, but it's relatively expensive.
+ current_private_vis: Visibility,
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()
+ }
+
+ fn private_vis_import(&mut self, binding: ImportId<'_>) -> Visibility {
+ let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
+ Visibility::Restricted(
+ import
+ .id()
+ .map(|id| self.nearest_normal_mod(self.local_def_id(id)))
+ .unwrap_or(CRATE_DEF_ID),
+ )
+ }
+
+ fn private_vis_def(&mut self, def_id: LocalDefId) -> Visibility {
+ // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent.
+ let normal_mod_id = self.nearest_normal_mod(def_id);
+ if normal_mod_id == def_id {
+ self.opt_local_parent(def_id).map_or(Visibility::Public, Visibility::Restricted)
+ } else {
+ Visibility::Restricted(normal_mod_id)
+ }
+ }
+}
+
+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
/// need access to a TyCtxt for that.
pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
- let mut visitor = EffectiveVisibilitiesVisitor { r, changed: false };
-
- visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, Level::Direct);
+ let mut visitor = EffectiveVisibilitiesVisitor {
+ r,
+ def_effective_visibilities: Default::default(),
+ import_effective_visibilities: Default::default(),
+ current_private_vis: Visibility::Public,
+ changed: false,
+ };
+
+ visitor.update(CRATE_DEF_ID, CRATE_DEF_ID);
+ visitor.current_private_vis = Visibility::Restricted(CRATE_DEF_ID);
visitor.set_bindings_effective_visibilities(CRATE_DEF_ID);
while visitor.changed {
- visitor.reset();
+ 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
+ // information, but are used by later passes. Effective visibility of an import def id
+ // is the maximum value among visibilities of bindings corresponding to that def id.
+ for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
+ let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
+ if let Some(node_id) = import.id() {
+ r.effective_visibilities.update_eff_vis(
+ r.local_def_id(node_id),
+ eff_vis,
+ ResolverTree(&r.definitions, &r.crate_loader),
+ )
+ }
+ }
info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
}
- fn reset(&mut self) {
- self.changed = false;
- }
-
/// Update effective visibilities of bindings in the given module,
/// including their whole reexport chains.
fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
@@ -48,73 +127,68 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
// Set the given effective visibility level to `Level::Direct` and
// sets the rest of the `use` chain to `Level::Reexported` until
// we hit the actual exported item.
+ let mut parent_id = ParentId::Def(module_id);
+ while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
+ let binding_id = ImportId::new_unchecked(binding);
+ self.update_import(binding_id, parent_id);
- // FIXME: tag and is_public() condition should be removed, but assertions occur.
- let tag = if binding.is_import() { Level::Reexported } else { Level::Direct };
- if binding.vis.is_public() {
- let mut prev_parent_id = module_id;
- let mut level = Level::Direct;
- while let NameBindingKind::Import { binding: nested_binding, import, .. } =
- binding.kind
- {
- let mut update = |node_id| self.update(
- self.r.local_def_id(node_id),
- binding.vis.expect_local(),
- prev_parent_id,
- level,
- );
- // In theory all the import IDs have individual visibilities and effective
- // visibilities, but in practice these IDs go straigth to HIR where all
- // their few uses assume that their (effective) visibility applies to the
- // whole syntactic `use` item. So we update them all to the maximum value
- // among the potential individual effective visibilities. Maybe HIR for
- // imports shouldn't use three IDs at all.
- update(import.id);
- if let ImportKind::Single { additional_ids, .. } = import.kind {
- update(additional_ids.0);
- update(additional_ids.1);
- }
-
- level = Level::Reexported;
- prev_parent_id = self.r.local_def_id(import.id);
- binding = nested_binding;
- }
+ parent_id = ParentId::Import(binding_id);
+ binding = nested_binding;
}
if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
- self.update(def_id, binding.vis.expect_local(), module_id, tag);
+ self.update_def(def_id, binding.vis.expect_local(), parent_id);
}
}
}
}
- fn update(
- &mut self,
- def_id: LocalDefId,
- nominal_vis: Visibility,
- parent_id: LocalDefId,
- tag: Level,
- ) {
- let module_id = self
- .r
- .get_nearest_non_block_module(def_id.to_def_id())
- .nearest_parent_mod()
- .expect_local();
- if nominal_vis == Visibility::Restricted(module_id)
- || self.r.visibilities[&parent_id] == Visibility::Restricted(module_id)
- {
- return;
+ fn cheap_private_vis(&self, parent_id: ParentId<'_>) -> Option<Visibility> {
+ matches!(parent_id, ParentId::Def(_)).then_some(self.current_private_vis)
+ }
+
+ fn effective_vis_or_private(&mut self, parent_id: ParentId<'a>) -> EffectiveVisibility {
+ // Private nodes are only added to the table for caching, they could be added or removed at
+ // any moment without consequences, so we don't set `changed` to true when adding them.
+ *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)),
}
- let mut effective_visibilities = std::mem::take(&mut self.r.effective_visibilities);
- self.changed |= effective_visibilities.update(
+ }
+
+ fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) {
+ let nominal_vis = binding.vis.expect_local();
+ let private_vis = self.cheap_private_vis(parent_id);
+ let inherited_eff_vis = self.effective_vis_or_private(parent_id);
+ self.changed |= self.import_effective_visibilities.update(
+ binding,
+ nominal_vis,
+ |r| (private_vis.unwrap_or_else(|| r.private_vis_import(binding)), r),
+ inherited_eff_vis,
+ parent_id.level(),
+ &mut *self.r,
+ );
+ }
+
+ fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) {
+ let private_vis = self.cheap_private_vis(parent_id);
+ let inherited_eff_vis = self.effective_vis_or_private(parent_id);
+ self.changed |= self.def_effective_visibilities.update(
def_id,
nominal_vis,
- || Visibility::Restricted(module_id),
- parent_id,
- tag,
- &*self.r,
+ |r| (private_vis.unwrap_or_else(|| r.private_vis_def(def_id)), r),
+ inherited_eff_vis,
+ parent_id.level(),
+ &mut *self.r,
);
- self.r.effective_visibilities = effective_visibilities;
+ }
+
+ fn update(&mut self, def_id: LocalDefId, parent_id: LocalDefId) {
+ self.update_def(def_id, self.r.visibilities[&def_id], ParentId::Def(parent_id));
}
}
@@ -132,22 +206,12 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
),
- // Foreign modules inherit level from parents.
- ast::ItemKind::ForeignMod(..) => {
- let parent_id = self.r.local_parent(def_id);
- self.update(def_id, Visibility::Public, parent_id, Level::Direct);
- }
-
- // Only exported `macro_rules!` items are public, but they always are
- ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
- let parent_id = self.r.local_parent(def_id);
- let vis = self.r.visibilities[&def_id];
- self.update(def_id, vis, parent_id, Level::Direct);
- }
-
ast::ItemKind::Mod(..) => {
+ let prev_private_vis =
+ mem::replace(&mut self.current_private_vis, Visibility::Restricted(def_id));
self.set_bindings_effective_visibilities(def_id);
visit::walk_item(self, item);
+ self.current_private_vis = prev_private_vis;
}
ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
@@ -155,18 +219,14 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
for variant in variants {
let variant_def_id = self.r.local_def_id(variant.id);
for field in variant.data.fields() {
- let field_def_id = self.r.local_def_id(field.id);
- let vis = self.r.visibilities[&field_def_id];
- self.update(field_def_id, vis, variant_def_id, Level::Direct);
+ self.update(self.r.local_def_id(field.id), variant_def_id);
}
}
}
ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
for field in def.fields() {
- let field_def_id = self.r.local_def_id(field.id);
- let vis = self.r.visibilities[&field_def_id];
- self.update(field_def_id, vis, def_id, Level::Direct);
+ self.update(self.r.local_def_id(field.id), def_id);
}
}
@@ -182,6 +242,7 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
| ast::ItemKind::TyAlias(..)
| ast::ItemKind::TraitAlias(..)
| ast::ItemKind::MacroDef(..)
+ | ast::ItemKind::ForeignMod(..)
| ast::ItemKind::Fn(..) => return,
}
}