Skip to content

Commit b8b5cae

Browse files
committed
Auto merge of rust-lang#102026 - Bryanskiy:resolve_update, r=petrochenkov
Populate effective visibilities in 'rustc_resolve' Next part of RFC rust-lang#48054. previous: rust-lang#101713 `@rustbot` author r? `@petrochenkov`
2 parents bf286a8 + 496ccd9 commit b8b5cae

File tree

7 files changed

+240
-163
lines changed

7 files changed

+240
-163
lines changed

compiler/rustc_middle/src/middle/privacy.rs

+104-32
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! A pass that checks to make sure private fields and methods aren't used
22
//! outside their scopes. This pass will also generate a set of exported items
33
//! which are available for use externally when compiled as a library.
4-
use crate::ty::Visibility;
4+
use crate::ty::{DefIdTree, Visibility};
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
77
use rustc_macros::HashStable;
88
use rustc_query_system::ich::StableHashingContext;
9-
use rustc_span::def_id::LocalDefId;
9+
use rustc_span::def_id::{DefId, LocalDefId};
1010
use std::hash::Hash;
1111

1212
/// Represents the levels of accessibility an item can have.
@@ -27,26 +27,36 @@ pub enum AccessLevel {
2727
Public,
2828
}
2929

30-
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Default)]
30+
impl AccessLevel {
31+
pub fn all_levels() -> [AccessLevel; 4] {
32+
[
33+
AccessLevel::Public,
34+
AccessLevel::Exported,
35+
AccessLevel::Reachable,
36+
AccessLevel::ReachableFromImplTrait,
37+
]
38+
}
39+
}
40+
41+
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
3142
pub struct EffectiveVisibility {
32-
public: Option<Visibility>,
33-
exported: Option<Visibility>,
34-
reachable: Option<Visibility>,
35-
reachable_from_impl_trait: Option<Visibility>,
43+
public: Visibility,
44+
exported: Visibility,
45+
reachable: Visibility,
46+
reachable_from_impl_trait: Visibility,
3647
}
3748

3849
impl EffectiveVisibility {
39-
pub fn get(&self, tag: AccessLevel) -> Option<&Visibility> {
50+
pub fn get(&self, tag: AccessLevel) -> &Visibility {
4051
match tag {
4152
AccessLevel::Public => &self.public,
4253
AccessLevel::Exported => &self.exported,
4354
AccessLevel::Reachable => &self.reachable,
4455
AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
4556
}
46-
.as_ref()
4757
}
4858

49-
fn get_mut(&mut self, tag: AccessLevel) -> &mut Option<Visibility> {
59+
fn get_mut(&mut self, tag: AccessLevel) -> &mut Visibility {
5060
match tag {
5161
AccessLevel::Public => &mut self.public,
5262
AccessLevel::Exported => &mut self.exported,
@@ -56,7 +66,30 @@ impl EffectiveVisibility {
5666
}
5767

5868
pub fn is_public_at_level(&self, tag: AccessLevel) -> bool {
59-
self.get(tag).map_or(false, |vis| vis.is_public())
69+
self.get(tag).is_public()
70+
}
71+
72+
fn update(&mut self, vis: Visibility, tag: AccessLevel, tree: impl DefIdTree) -> bool {
73+
let mut changed = false;
74+
for level in AccessLevel::all_levels() {
75+
if level <= tag {
76+
let current_effective_vis = self.get_mut(level);
77+
if *current_effective_vis != vis && vis.is_at_least(*current_effective_vis, tree) {
78+
changed = true;
79+
*current_effective_vis = vis;
80+
}
81+
}
82+
}
83+
changed
84+
}
85+
86+
fn from_vis(vis: Visibility) -> EffectiveVisibility {
87+
EffectiveVisibility {
88+
public: vis,
89+
exported: vis,
90+
reachable: vis,
91+
reachable_from_impl_trait: vis,
92+
}
6093
}
6194
}
6295

@@ -89,12 +122,7 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
89122

90123
pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
91124
self.get_effective_vis(id).and_then(|effective_vis| {
92-
for level in [
93-
AccessLevel::Public,
94-
AccessLevel::Exported,
95-
AccessLevel::Reachable,
96-
AccessLevel::ReachableFromImplTrait,
97-
] {
125+
for level in AccessLevel::all_levels() {
98126
if effective_vis.is_public_at_level(level) {
99127
return Some(level);
100128
}
@@ -103,21 +131,6 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
103131
})
104132
}
105133

106-
pub fn set_access_level(&mut self, id: Id, tag: AccessLevel) {
107-
let mut effective_vis = self.get_effective_vis(id).copied().unwrap_or_default();
108-
for level in [
109-
AccessLevel::Public,
110-
AccessLevel::Exported,
111-
AccessLevel::Reachable,
112-
AccessLevel::ReachableFromImplTrait,
113-
] {
114-
if level <= tag {
115-
*effective_vis.get_mut(level) = Some(Visibility::Public);
116-
}
117-
}
118-
self.map.insert(id, effective_vis);
119-
}
120-
121134
pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
122135
self.map.get(&id)
123136
}
@@ -129,6 +142,65 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
129142
pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> {
130143
AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
131144
}
145+
146+
pub fn set_access_level(
147+
&mut self,
148+
id: Id,
149+
default_vis: impl FnOnce() -> Visibility,
150+
tag: AccessLevel,
151+
) {
152+
let mut effective_vis = self
153+
.get_effective_vis(id)
154+
.copied()
155+
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
156+
for level in AccessLevel::all_levels() {
157+
if level <= tag {
158+
*effective_vis.get_mut(level) = Visibility::Public;
159+
}
160+
}
161+
self.map.insert(id, effective_vis);
162+
}
163+
}
164+
165+
impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> {
166+
// `parent_id` is not necessarily a parent in source code tree,
167+
// it is the node from which the maximum effective visibility is inherited.
168+
pub fn update(
169+
&mut self,
170+
id: Id,
171+
nominal_vis: Visibility,
172+
default_vis: impl FnOnce() -> Visibility,
173+
parent_id: Id,
174+
tag: AccessLevel,
175+
tree: impl DefIdTree,
176+
) -> Result<bool, ()> {
177+
let mut changed = false;
178+
let mut current_effective_vis = self
179+
.get_effective_vis(id)
180+
.copied()
181+
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
182+
if let Some(inherited_effective_vis) = self.get_effective_vis(parent_id) {
183+
for level in AccessLevel::all_levels() {
184+
if tag >= level {
185+
let inherited_effective_vis_at_level = *inherited_effective_vis.get(level);
186+
let calculated_effective_vis =
187+
if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) {
188+
inherited_effective_vis_at_level
189+
} else {
190+
nominal_vis
191+
};
192+
changed |= current_effective_vis.update(calculated_effective_vis, level, tree);
193+
}
194+
}
195+
} else {
196+
if !id.into().is_crate_root() {
197+
return Err(());
198+
}
199+
changed |= current_effective_vis.update(Visibility::Public, AccessLevel::Public, tree);
200+
}
201+
self.map.insert(id, current_effective_vis);
202+
Ok(changed)
203+
}
132204
}
133205

134206
impl<Id> Default for AccessLevels<Id> {

compiler/rustc_privacy/src/lib.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,11 @@ impl<'tcx> EmbargoVisitor<'tcx> {
444444
let old_level = self.get(def_id);
445445
// Accessibility levels can only grow.
446446
if level > old_level {
447-
self.access_levels.set_access_level(def_id, level.unwrap());
447+
self.access_levels.set_access_level(
448+
def_id,
449+
|| ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
450+
level.unwrap(),
451+
);
448452
self.changed = true;
449453
level
450454
} else {
@@ -932,31 +936,30 @@ pub struct TestReachabilityVisitor<'tcx, 'a> {
932936

933937
impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
934938
fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
935-
let span = self.tcx.def_span(def_id.to_def_id());
936939
if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
937-
let mut error_msg = String::new();
938-
939-
let effective_vis =
940-
self.access_levels.get_effective_vis(def_id).copied().unwrap_or_default();
941-
for level in [
942-
AccessLevel::Public,
943-
AccessLevel::Exported,
944-
AccessLevel::Reachable,
945-
AccessLevel::ReachableFromImplTrait,
946-
] {
947-
let vis_str = match effective_vis.get(level) {
948-
Some(ty::Visibility::Restricted(restricted_id)) => {
949-
format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
940+
if let Some(effective_vis) = self.access_levels.get_effective_vis(def_id) {
941+
let mut error_msg = String::new();
942+
let span = self.tcx.def_span(def_id.to_def_id());
943+
for level in AccessLevel::all_levels() {
944+
let vis_str = match effective_vis.get(level) {
945+
ty::Visibility::Restricted(restricted_id) => {
946+
if restricted_id.is_top_level_module() {
947+
"pub(crate)".to_string()
948+
} else if *restricted_id == self.tcx.parent_module_from_def_id(def_id) {
949+
"pub(self)".to_string()
950+
} else {
951+
format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
952+
}
953+
}
954+
ty::Visibility::Public => "pub".to_string(),
955+
};
956+
if level != AccessLevel::Public {
957+
error_msg.push_str(", ");
950958
}
951-
Some(ty::Visibility::Public) => "pub".to_string(),
952-
None => "pub(self)".to_string(),
953-
};
954-
if level != AccessLevel::Public {
955-
error_msg.push_str(", ");
959+
error_msg.push_str(&format!("{:?}: {}", level, vis_str));
956960
}
957-
error_msg.push_str(&format!("{:?}: {}", level, vis_str));
961+
self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
958962
}
959-
self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
960963
}
961964
}
962965
}

0 commit comments

Comments
 (0)