Skip to content

Optimize pub(crate) and pub(self) visibility resolution #20009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/hir-def/src/expr_store/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,11 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E
let FieldData { name, type_ref, visibility, is_unsafe } = data;
match visibility {
crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => {
w!(p, "{}", interned.display(db, p.edition))
w!(p, "pub(in {})", interned.display(db, p.edition))
}
crate::item_tree::RawVisibility::Public => w!(p, "pub "),
crate::item_tree::RawVisibility::PubCrate => w!(p, "pub(crate) "),
crate::item_tree::RawVisibility::PubSelf(_) => w!(p, "pub(self) "),
}
if *is_unsafe {
w!(p, "unsafe ");
Expand Down
2 changes: 0 additions & 2 deletions crates/hir-def/src/expr_store/tests/body/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,6 @@ fn main() {
fn underscore_import() {
// This used to panic, because the default (private) visibility inside block expressions would
// point into the containing `DefMap`, which visibilities should never be able to do.
cov_mark::check!(adjust_vis_in_block_def_map);
check_at(
r#"
mod m {
Expand Down Expand Up @@ -457,7 +456,6 @@ fn foo() {
#[test]
fn is_visible_from_same_def_map() {
// Regression test for https://github.com/rust-lang/rust-analyzer/issues/9481
cov_mark::check!(is_visible_from_same_block_def_map);
check_at(
r#"
fn outer() {
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/find_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ fn find_local_import_locations(
cov_mark::hit!(discount_private_imports);
false
}
Visibility::PubCrate(_) => true,
Visibility::Public => true,
};

Expand Down Expand Up @@ -1286,7 +1287,6 @@ $0

#[test]
fn explicit_private_imports_crate() {
cov_mark::check!(explicit_private_imports);
check_found_path(
r#"
//- /main.rs
Expand Down
22 changes: 4 additions & 18 deletions crates/hir-def/src/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
db::DefDatabase,
per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
visibility::{Visibility, VisibilityExplicitness},
visibility::Visibility,
};

#[derive(Debug, Default)]
Expand Down Expand Up @@ -720,33 +720,19 @@ impl ItemScope {
}

/// Marks everything that is not a procedural macro as private to `this_module`.
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
pub(crate) fn censor_non_proc_macros(&mut self, krate: Crate) {
self.types
.values_mut()
.map(|def| &mut def.vis)
.chain(self.values.values_mut().map(|def| &mut def.vis))
.chain(self.unnamed_trait_imports.iter_mut().map(|(_, def)| &mut def.vis))
.for_each(|vis| match vis {
&mut Visibility::Module(_, visibility_explicitness) => {
*vis = Visibility::Module(this_module, visibility_explicitness)
}
Visibility::Public => {
*vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
}
});
.for_each(|vis| *vis = Visibility::PubCrate(krate));

for mac in self.macros.values_mut() {
if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
continue;
}
match mac.vis {
Visibility::Module(_, visibility_explicitness) => {
mac.vis = Visibility::Module(this_module, visibility_explicitness)
}
Visibility::Public => {
mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
}
}
mac.vis = Visibility::PubCrate(krate)
}
}

Expand Down
33 changes: 12 additions & 21 deletions crates/hir-def/src/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,30 +414,17 @@ impl Index<RawVisibilityId> for ItemTree {
type Output = RawVisibility;
fn index(&self, index: RawVisibilityId) -> &Self::Output {
static VIS_PUB: RawVisibility = RawVisibility::Public;
static VIS_PRIV_IMPLICIT: OnceLock<RawVisibility> = OnceLock::new();
static VIS_PRIV_EXPLICIT: OnceLock<RawVisibility> = OnceLock::new();
static VIS_PUB_CRATE: OnceLock<RawVisibility> = OnceLock::new();
static VIS_PRIV_IMPLICIT: RawVisibility =
RawVisibility::PubSelf(VisibilityExplicitness::Implicit);
static VIS_PRIV_EXPLICIT: RawVisibility =
RawVisibility::PubSelf(VisibilityExplicitness::Explicit);
static VIS_PUB_CRATE: RawVisibility = RawVisibility::PubCrate;

match index {
RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| {
RawVisibility::Module(
Interned::new(ModPath::from_kind(PathKind::SELF)),
VisibilityExplicitness::Implicit,
)
}),
RawVisibilityId::PRIV_EXPLICIT => VIS_PRIV_EXPLICIT.get_or_init(|| {
RawVisibility::Module(
Interned::new(ModPath::from_kind(PathKind::SELF)),
VisibilityExplicitness::Explicit,
)
}),
RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
RawVisibilityId::PUB => &VIS_PUB,
RawVisibilityId::PUB_CRATE => VIS_PUB_CRATE.get_or_init(|| {
RawVisibility::Module(
Interned::new(ModPath::from_kind(PathKind::Crate)),
VisibilityExplicitness::Explicit,
)
}),
RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
_ => &self.vis.arena[index.0 as usize],
}
}
Expand Down Expand Up @@ -555,6 +542,10 @@ pub enum RawVisibility {
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
/// equivalent to `pub(self)`.
Module(Interned<ModPath>, VisibilityExplicitness),
/// `pub(self)`.
PubSelf(VisibilityExplicitness),
/// `pub(crate)`.
PubCrate,
/// `pub`.
Public,
}
Expand Down
4 changes: 3 additions & 1 deletion crates/hir-def/src/item_tree/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,11 @@ impl Printer<'_> {
fn print_visibility(&mut self, vis: RawVisibilityId) {
match &self.tree[vis] {
RawVisibility::Module(path, _expl) => {
w!(self, "pub({}) ", path.display(self.db, self.edition))
w!(self, "pub(in {}) ", path.display(self.db, self.edition))
}
RawVisibility::Public => w!(self, "pub "),
RawVisibility::PubCrate => w!(self, "pub(crate) "),
RawVisibility::PubSelf(_) => w!(self, "pub(self) "),
};
}

Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/item_tree/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use a::{c, d::{e}};
pub(self) extern crate self as renamed;

// AstId: ExternCrate[7E1C, 0]
pub(super) extern crate bli;
pub(in super) extern crate bli;

// AstId: Use[0000, 0]
pub use crate::path::{nested, items as renamed, Trait as _};
Expand Down
4 changes: 4 additions & 0 deletions crates/hir-def/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ impl<N: AstIdNode> HasModule for ItemLoc<N> {

#[derive(Debug)]
pub struct AssocItemLoc<N: AstIdNode> {
// FIXME: Store this as an erased `salsa::Id` to save space
pub container: ItemContainerId,
pub id: AstId<N>,
}
Expand Down Expand Up @@ -577,6 +578,7 @@ pub type LocalModuleId = Idx<nameres::ModuleData>;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FieldId {
// FIXME: Store this as an erased `salsa::Id` to save space
pub parent: VariantId,
pub local_id: LocalFieldId,
}
Expand All @@ -592,6 +594,7 @@ pub struct TupleFieldId {

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct TypeOrConstParamId {
// FIXME: Store this as an erased `salsa::Id` to save space
pub parent: GenericDefId,
pub local_id: LocalTypeOrConstParamId,
}
Expand Down Expand Up @@ -650,6 +653,7 @@ impl From<ConstParamId> for TypeOrConstParamId {

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LifetimeParamId {
// FIXME: Store this as an erased `salsa::Id` to save space
pub parent: GenericDefId,
pub local_id: LocalLifetimeParamId,
}
Expand Down
3 changes: 1 addition & 2 deletions crates/hir-def/src/nameres/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,9 +437,8 @@ impl<'db> DefCollector<'db> {
// Additionally, while the proc macro entry points must be `pub`, they are not publicly
// exported in type/value namespace. This function reduces the visibility of all items
// in the crate root that aren't proc macros.
let module_id = self.def_map.module_id(DefMap::ROOT);
let root = &mut self.def_map.modules[DefMap::ROOT];
root.scope.censor_non_proc_macros(module_id);
root.scope.censor_non_proc_macros(self.def_map.krate);
}
}

Expand Down
37 changes: 22 additions & 15 deletions crates/hir-def/src/nameres/path_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl DefMap {
visibility: &RawVisibility,
within_impl: bool,
) -> Option<Visibility> {
let mut vis = match visibility {
let vis = match visibility {
RawVisibility::Module(path, explicitness) => {
let (result, remaining) = self.resolve_path(
local_def_map,
Expand All @@ -120,29 +120,36 @@ impl DefMap {
return None;
}
let types = result.take_types()?;
match types {
let mut vis = match types {
ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicitness),
// error: visibility needs to refer to module
_ => {
return None;
}
};

// In block expressions, `self` normally refers to the containing non-block module, and
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
// DefMap they're written in, so we restrict them when that happens.
if let Visibility::Module(m, mv) = vis {
// ...unless we're resolving visibility for an associated item in an impl.
if self.block_id() != m.block && !within_impl {
vis = Visibility::Module(self.module_id(Self::ROOT), mv);
tracing::debug!(
"visibility {:?} points outside DefMap, adjusting to {:?}",
m,
vis
);
}
}
vis
}
RawVisibility::PubSelf(explicitness) => {
Visibility::Module(self.module_id(original_module), *explicitness)
}
RawVisibility::Public => Visibility::Public,
RawVisibility::PubCrate => Visibility::PubCrate(self.krate),
};

// In block expressions, `self` normally refers to the containing non-block module, and
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
// DefMap they're written in, so we restrict them when that happens.
if let Visibility::Module(m, mv) = vis {
// ...unless we're resolving visibility for an associated item in an impl.
if self.block_id() != m.block && !within_impl {
cov_mark::hit!(adjust_vis_in_block_def_map);
vis = Visibility::Module(self.module_id(Self::ROOT), mv);
tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
}
}

Some(vis)
}

Expand Down
4 changes: 4 additions & 0 deletions crates/hir-def/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ impl<'db> Resolver<'db> {
}),
)
}
RawVisibility::PubSelf(explicitness) => {
Some(Visibility::Module(self.module(), *explicitness))
}
RawVisibility::PubCrate => Some(Visibility::PubCrate(self.krate())),
RawVisibility::Public => Some(Visibility::Public),
}
}
Expand Down
Loading