Skip to content

Commit 1c8e978

Browse files
committed
access_levels.rs refactor
1 parent 8556e66 commit 1c8e978

File tree

3 files changed

+80
-123
lines changed

3 files changed

+80
-123
lines changed
+53-105
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
1+
use crate::imports::ImportKind;
2+
use crate::NameBinding;
3+
use crate::NameBindingKind;
4+
use crate::Resolver;
15
use rustc_ast::ast;
26
use rustc_ast::visit;
37
use rustc_ast::visit::Visitor;
48
use rustc_ast::Crate;
59
use rustc_ast::EnumDef;
6-
use rustc_ast::ForeignMod;
710
use rustc_ast::NodeId;
811
use rustc_hir::def_id::LocalDefId;
912
use rustc_hir::def_id::CRATE_DEF_ID;
1013
use rustc_middle::middle::privacy::AccessLevel;
11-
use rustc_middle::ty::Visibility;
14+
use rustc_middle::ty::DefIdTree;
1215
use rustc_span::sym;
1316

14-
use crate::imports::ImportKind;
15-
use crate::BindingKey;
16-
use crate::NameBinding;
17-
use crate::NameBindingKind;
18-
use crate::Resolver;
19-
2017
pub struct AccessLevelsVisitor<'r, 'a> {
2118
r: &'r mut Resolver<'a>,
22-
prev_level: Option<AccessLevel>,
2319
changed: bool,
2420
}
2521

@@ -28,11 +24,10 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
2824
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
2925
/// need access to a TyCtxt for that.
3026
pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
31-
let mut visitor =
32-
AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) };
27+
let mut visitor = AccessLevelsVisitor { r, changed: false };
3328

3429
visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
35-
visitor.set_exports_access_level(CRATE_DEF_ID);
30+
visitor.set_bindings_access_level(CRATE_DEF_ID);
3631

3732
while visitor.changed {
3833
visitor.reset();
@@ -44,15 +39,17 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
4439

4540
fn reset(&mut self) {
4641
self.changed = false;
47-
self.prev_level = Some(AccessLevel::Public);
4842
}
4943

50-
/// Update the access level of the exports of the given module accordingly. The module access
44+
/// Update the access level of the bindings in the given module accordingly. The module access
5145
/// level has to be Exported or Public.
5246
/// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
53-
fn set_exports_access_level(&mut self, module_id: LocalDefId) {
47+
fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
5448
assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
55-
49+
let module_level = self.r.access_levels.map.get(&module_id).copied();
50+
if !module_level.is_some() {
51+
return;
52+
}
5653
// Set the given binding access level to `AccessLevel::Public` and
5754
// sets the rest of the `use` chain to `AccessLevel::Exported` until
5855
// we hit the actual exported item.
@@ -72,28 +69,20 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
7269
}
7370
};
7471

75-
let module_level = self.r.access_levels.map.get(&module_id).copied();
76-
assert!(module_level >= Some(AccessLevel::Exported));
77-
78-
if let Some(exports) = self.r.reexport_map.get(&module_id) {
79-
let pub_exports = exports
80-
.iter()
81-
.filter(|ex| ex.vis == Visibility::Public)
82-
.cloned()
83-
.collect::<Vec<_>>();
84-
85-
let module = self.r.get_module(module_id.to_def_id()).unwrap();
86-
for export in pub_exports.into_iter() {
87-
if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) {
88-
self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported));
89-
}
90-
91-
if let Some(ns) = export.res.ns() {
92-
let key = BindingKey { ident: export.ident, ns, disambiguator: 0 };
93-
let name_res = self.r.resolution(module, key);
94-
if let Some(binding) = name_res.borrow().binding() {
95-
set_import_binding_access_level(self, binding, module_level)
96-
}
72+
let module = self.r.get_module(module_id.to_def_id()).unwrap();
73+
let resolutions = self.r.resolutions(module);
74+
75+
for (.., name_resolution) in resolutions.borrow().iter() {
76+
if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() {
77+
let access_level = match self.r.is_reexport(binding) {
78+
Some(_) => {
79+
set_import_binding_access_level(self, binding, module_level);
80+
Some(AccessLevel::Exported)
81+
},
82+
None => module_level,
83+
};
84+
if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
85+
self.set_access_level_def_id(def_id, access_level);
9786
}
9887
}
9988
}
@@ -127,97 +116,59 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
127116

128117
impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
129118
fn visit_item(&mut self, item: &'ast ast::Item) {
130-
let inherited_item_level = match item.kind {
119+
let def_id = self.r.local_def_id(item.id);
120+
// Set access level of nested items.
121+
// If it's a mod, also make the visitor walk all of its items
122+
match item.kind {
131123
// Resolved in rustc_privacy when types are available
132124
ast::ItemKind::Impl(..) => return,
133125

134-
// Only exported `macro_rules!` items are public, but they always are
135-
ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
136-
let is_macro_export =
137-
item.attrs.iter().any(|attr| attr.has_name(sym::macro_export));
138-
if is_macro_export { Some(AccessLevel::Public) } else { None }
139-
}
140-
141-
// Foreign modules inherit level from parents.
142-
ast::ItemKind::ForeignMod(..) => self.prev_level,
143-
144-
// Other `pub` items inherit levels from parents.
145-
ast::ItemKind::ExternCrate(..)
146-
| ast::ItemKind::Use(..)
147-
| ast::ItemKind::Static(..)
148-
| ast::ItemKind::Const(..)
149-
| ast::ItemKind::Fn(..)
150-
| ast::ItemKind::Mod(..)
151-
| ast::ItemKind::GlobalAsm(..)
152-
| ast::ItemKind::TyAlias(..)
153-
| ast::ItemKind::Enum(..)
154-
| ast::ItemKind::Struct(..)
155-
| ast::ItemKind::Union(..)
156-
| ast::ItemKind::Trait(..)
157-
| ast::ItemKind::TraitAlias(..)
158-
| ast::ItemKind::MacroDef(..) => {
159-
if item.vis.kind.is_pub() {
160-
self.prev_level
161-
} else {
162-
None
163-
}
164-
}
165-
166126
// Should be unreachable at this stage
167127
ast::ItemKind::MacCall(..) => panic!(
168128
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
169129
),
170-
};
171130

172-
let access_level = self.set_access_level(item.id, inherited_item_level);
131+
// Foreign modules inherit level from parents.
132+
ast::ItemKind::ForeignMod(..) => {
133+
let parent_level =
134+
self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied();
135+
self.set_access_level(item.id, parent_level);
136+
}
173137

174-
// Set access level of nested items.
175-
// If it's a mod, also make the visitor walk all of its items
176-
match item.kind {
177-
ast::ItemKind::Mod(..) => {
178-
if access_level.is_some() {
179-
self.set_exports_access_level(self.r.local_def_id(item.id));
138+
// Only exported `macro_rules!` items are public, but they always are
139+
ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
140+
if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) {
141+
self.set_access_level(item.id, Some(AccessLevel::Public));
180142
}
143+
}
181144

182-
let orig_level = std::mem::replace(&mut self.prev_level, access_level);
145+
ast::ItemKind::Mod(..) => {
146+
self.set_bindings_access_level(def_id);
183147
visit::walk_item(self, item);
184-
self.prev_level = orig_level;
185148
}
186149

187-
ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => {
188-
for nested in items {
189-
if nested.vis.kind.is_pub() {
190-
self.set_access_level(nested.id, access_level);
191-
}
192-
}
193-
}
194150
ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
151+
self.set_bindings_access_level(def_id);
195152
for variant in variants {
196-
let variant_level = self.set_access_level(variant.id, access_level);
197-
if let Some(ctor_id) = variant.data.ctor_id() {
198-
self.set_access_level(ctor_id, access_level);
199-
}
200-
153+
let variant_def_id = self.r.local_def_id(variant.id);
154+
let variant_level = self.r.access_levels.map.get(&variant_def_id).copied();
201155
for field in variant.data.fields() {
202156
self.set_access_level(field.id, variant_level);
203157
}
204158
}
205159
}
206-
ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
207-
if let Some(ctor_id) = def.ctor_id() {
208-
self.set_access_level(ctor_id, access_level);
209-
}
210160

161+
ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
162+
let inherited_level = self.r.access_levels.map.get(&def_id).copied();
211163
for field in def.fields() {
212164
if field.vis.kind.is_pub() {
213-
self.set_access_level(field.id, access_level);
165+
self.set_access_level(field.id, inherited_level);
214166
}
215167
}
216168
}
217-
ast::ItemKind::Trait(ref trait_kind) => {
218-
for nested in trait_kind.items.iter() {
219-
self.set_access_level(nested.id, access_level);
220-
}
169+
170+
ast::ItemKind::Trait(..) => {
171+
self.set_bindings_access_level(def_id);
221172
}
222173

223174
ast::ItemKind::ExternCrate(..)
@@ -229,9 +180,6 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
229180
| ast::ItemKind::TraitAlias(..)
230181
| ast::ItemKind::MacroDef(..)
231182
| ast::ItemKind::Fn(..) => return,
232-
233-
// Unreachable kinds
234-
ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(),
235183
}
236184
}
237185
}

compiler/rustc_resolve/src/imports.rs

+9-18
Original file line numberDiff line numberDiff line change
@@ -1091,24 +1091,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
10911091
if let Some(def_id) = module.opt_def_id() {
10921092
let mut reexports = Vec::new();
10931093

1094-
module.for_each_child(self.r, |_, ident, _, binding| {
1095-
// FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
1096-
// into the crate root to actual `NameBindingKind::Import`.
1097-
if binding.is_import()
1098-
|| matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
1099-
{
1100-
let res = binding.res().expect_non_local();
1101-
// Ambiguous imports are treated as errors at this point and are
1102-
// not exposed to other crates (see #36837 for more details).
1103-
if res != def::Res::Err && !binding.is_ambiguity() {
1104-
reexports.push(ModChild {
1105-
ident,
1106-
res,
1107-
vis: binding.vis,
1108-
span: binding.span,
1109-
macro_rules: false,
1110-
});
1111-
}
1094+
module.for_each_child(self.r, |this, ident, _, binding| {
1095+
if let Some(res) = this.is_reexport(binding) {
1096+
reexports.push(ModChild {
1097+
ident,
1098+
res,
1099+
vis: binding.vis,
1100+
span: binding.span,
1101+
macro_rules: false,
1102+
});
11121103
}
11131104
});
11141105

compiler/rustc_resolve/src/lib.rs

+18
Original file line numberDiff line numberDiff line change
@@ -2014,6 +2014,24 @@ impl<'a> Resolver<'a> {
20142014
}
20152015
self.main_def = Some(MainDefinition { res, is_import, span });
20162016
}
2017+
2018+
// Items that go to reexport table encoded to metadata and visible through it to other crates.
2019+
fn is_reexport(&self, binding: &NameBinding<'a>) -> Option<def::Res<!>> {
2020+
// FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
2021+
// into the crate root to actual `NameBindingKind::Import`.
2022+
if binding.is_import()
2023+
|| matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
2024+
{
2025+
let res = binding.res().expect_non_local();
2026+
// Ambiguous imports are treated as errors at this point and are
2027+
// not exposed to other crates (see #36837 for more details).
2028+
if res != def::Res::Err && !binding.is_ambiguity() {
2029+
return Some(res);
2030+
}
2031+
}
2032+
2033+
return None;
2034+
}
20172035
}
20182036

20192037
fn names_to_string(names: &[Symbol]) -> String {

0 commit comments

Comments
 (0)