Cleanup visibility.rs

This commit is contained in:
Lukas Wirth 2024-02-10 13:49:21 +01:00
parent dc69255b83
commit 36fb1409ed
4 changed files with 96 additions and 52 deletions

View File

@ -658,7 +658,7 @@ fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<
fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId { fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
let vis = let vis =
RawVisibility::from_ast_with_span_map(self.db, item.visibility(), self.span_map()); RawVisibility::from_opt_ast_with_span_map(self.db, item.visibility(), self.span_map());
self.data().vis.alloc(vis) self.data().vis.alloc(vis)
} }

View File

@ -248,6 +248,7 @@ pub fn resolve_visibility(
RawVisibility::Public => Some(Visibility::Public), RawVisibility::Public => Some(Visibility::Public),
} }
} }
pub fn resolve_path_in_value_ns( pub fn resolve_path_in_value_ns(
&self, &self,
db: &dyn DefDatabase, db: &dyn DefDatabase,

View File

@ -37,10 +37,14 @@ pub(crate) fn from_ast(
db: &dyn DefDatabase, db: &dyn DefDatabase,
node: InFile<Option<ast::Visibility>>, node: InFile<Option<ast::Visibility>>,
) -> RawVisibility { ) -> RawVisibility {
let node = match node.transpose() {
None => return RawVisibility::private(),
Some(node) => node,
};
Self::from_ast_with_span_map(db, node.value, db.span_map(node.file_id).as_ref()) Self::from_ast_with_span_map(db, node.value, db.span_map(node.file_id).as_ref())
} }
pub(crate) fn from_ast_with_span_map( pub(crate) fn from_opt_ast_with_span_map(
db: &dyn DefDatabase, db: &dyn DefDatabase,
node: Option<ast::Visibility>, node: Option<ast::Visibility>,
span_map: SpanMapRef<'_>, span_map: SpanMapRef<'_>,
@ -49,29 +53,28 @@ pub(crate) fn from_ast_with_span_map(
None => return RawVisibility::private(), None => return RawVisibility::private(),
Some(node) => node, Some(node) => node,
}; };
match node.kind() { Self::from_ast_with_span_map(db, node, span_map)
}
fn from_ast_with_span_map(
db: &dyn DefDatabase,
node: ast::Visibility,
span_map: SpanMapRef<'_>,
) -> RawVisibility {
let path = match node.kind() {
ast::VisibilityKind::In(path) => { ast::VisibilityKind::In(path) => {
let path = ModPath::from_src(db.upcast(), path, span_map); let path = ModPath::from_src(db.upcast(), path, span_map);
let path = match path { match path {
None => return RawVisibility::private(), None => return RawVisibility::private(),
Some(path) => path, Some(path) => path,
}; }
RawVisibility::Module(path, VisibilityExplicitness::Explicit)
} }
ast::VisibilityKind::PubCrate => { ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate),
let path = ModPath::from_kind(PathKind::Crate); ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)),
RawVisibility::Module(path, VisibilityExplicitness::Explicit) ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::Super(0)),
} ast::VisibilityKind::Pub => return RawVisibility::Public,
ast::VisibilityKind::PubSuper => { };
let path = ModPath::from_kind(PathKind::Super(1)); RawVisibility::Module(path, VisibilityExplicitness::Explicit)
RawVisibility::Module(path, VisibilityExplicitness::Explicit)
}
ast::VisibilityKind::PubSelf => {
let path = ModPath::from_kind(PathKind::Super(0));
RawVisibility::Module(path, VisibilityExplicitness::Explicit)
}
ast::VisibilityKind::Pub => RawVisibility::Public,
}
} }
pub fn resolve( pub fn resolve(
@ -94,6 +97,10 @@ pub enum Visibility {
} }
impl Visibility { impl Visibility {
pub(crate) fn is_visible_from_other_crate(self) -> bool {
matches!(self, Visibility::Public)
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
let to_module = match self { let to_module = match self {
@ -105,24 +112,33 @@ pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> boo
return false; return false;
} }
let def_map = from_module.def_map(db); let def_map = from_module.def_map(db);
self.is_visible_from_def_map(db, &def_map, from_module.local_id) Self::is_visible_from_def_map_(db, &def_map, to_module, from_module.local_id)
}
pub(crate) fn is_visible_from_other_crate(self) -> bool {
matches!(self, Visibility::Public)
} }
pub(crate) fn is_visible_from_def_map( pub(crate) fn is_visible_from_def_map(
self, self,
db: &dyn DefDatabase, db: &dyn DefDatabase,
def_map: &DefMap, def_map: &DefMap,
mut from_module: LocalModuleId, from_module: LocalModuleId,
) -> bool { ) -> bool {
let mut to_module = match self { let to_module = match self {
Visibility::Module(m, _) => m, Visibility::Module(m, _) => m,
Visibility::Public => return true, Visibility::Public => return true,
}; };
// if they're not in the same crate, it can't be visible
if def_map.krate() != to_module.krate {
return false;
}
Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
}
fn is_visible_from_def_map_(
db: &dyn DefDatabase,
def_map: &DefMap,
mut to_module: ModuleId,
mut from_module: LocalModuleId,
) -> bool {
debug_assert_eq!(to_module.krate, def_map.krate());
// `to_module` might be the root module of a block expression. Those have the same // `to_module` might be the root module of a block expression. Those have the same
// visibility as the containing module (even though no items are directly nameable from // visibility as the containing module (even though no items are directly nameable from
// there, getting this right is important for method resolution). // there, getting this right is important for method resolution).
@ -130,20 +146,25 @@ pub(crate) fn is_visible_from_def_map(
// Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're
// currently computing, so we must not call the `def_map` query for it. // currently computing, so we must not call the `def_map` query for it.
let mut arc; let def_map_block = def_map.block_id();
loop { loop {
let to_module_def_map = match (to_module.block, def_map_block) {
if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() { // to_module is not a block, so there is no parent def map to use
(None, _) => (),
(Some(a), Some(b)) if a == b => {
cov_mark::hit!(is_visible_from_same_block_def_map); cov_mark::hit!(is_visible_from_same_block_def_map);
def_map if let Some(parent) = def_map.parent() {
} else { to_module = parent;
arc = to_module.def_map(db); }
&arc }
}; _ => {
match to_module_def_map.parent() { if let Some(parent) = to_module.def_map(db).parent() {
Some(parent) => to_module = parent, to_module = parent;
None => break, continue;
}
}
} }
break;
} }
// from_module needs to be a descendant of to_module // from_module needs to be a descendant of to_module
@ -176,30 +197,25 @@ pub(crate) fn is_visible_from_def_map(
/// visible in unrelated modules). /// visible in unrelated modules).
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
match (self, other) { match (self, other) {
(Visibility::Module(_, _) | Visibility::Public, Visibility::Public) (_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public),
| (Visibility::Public, Visibility::Module(_, _)) => Some(Visibility::Public), (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
(Visibility::Module(mod_a, vis_a), Visibility::Module(mod_b, vis_b)) => {
if mod_a.krate != mod_b.krate { if mod_a.krate != mod_b.krate {
return None; return None;
} }
let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| { let mut a_ancestors =
let parent_id = def_map[m].parent?; iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
Some(parent_id) let mut b_ancestors =
}); iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
let mut b_ancestors = iter::successors(Some(mod_b.local_id), |&m| {
let parent_id = def_map[m].parent?;
Some(parent_id)
});
if a_ancestors.any(|m| m == mod_b.local_id) { if a_ancestors.any(|m| m == mod_b.local_id) {
// B is above A // B is above A
return Some(Visibility::Module(mod_b, vis_b)); return Some(Visibility::Module(mod_b, expl_b));
} }
if b_ancestors.any(|m| m == mod_a.local_id) { if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B // A is above B
return Some(Visibility::Module(mod_a, vis_a)); return Some(Visibility::Module(mod_a, expl_a));
} }
None None
@ -208,7 +224,8 @@ pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibilit
} }
} }
/// Whether the item was imported through `pub(crate) use` or just `use`. /// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without
/// visibility.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum VisibilityExplicitness { pub enum VisibilityExplicitness {
Explicit, Explicit,

View File

@ -83,6 +83,32 @@ pub struct Struct {
}; };
strukt.field; strukt.field;
} }
"#,
);
}
#[test]
fn block_module_madness2() {
check_diagnostics(
r#"
fn main() {
use crate as ForceParentBlockDefMap;
let strukt = {
use crate as ForceParentBlockDefMap;
{
pub struct Struct {
field: (),
}
{
use crate as ForceParentBlockDefMap;
{
Struct { field: () }
}
}
}
};
strukt.field;
}
"#, "#,
); );
} }