]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_resolve/src/access_levels.rs
Auto merge of #103062 - cuviper:dist-mips, r=Mark-Simulacrum
[rust.git] / compiler / rustc_resolve / src / access_levels.rs
1 use crate::{ImportKind, NameBindingKind, Resolver};
2 use rustc_ast::ast;
3 use rustc_ast::visit;
4 use rustc_ast::visit::Visitor;
5 use rustc_ast::Crate;
6 use rustc_ast::EnumDef;
7 use rustc_hir::def_id::LocalDefId;
8 use rustc_hir::def_id::CRATE_DEF_ID;
9 use rustc_middle::middle::privacy::AccessLevel;
10 use rustc_middle::ty::{DefIdTree, Visibility};
11
12 pub struct AccessLevelsVisitor<'r, 'a> {
13     r: &'r mut Resolver<'a>,
14     changed: bool,
15 }
16
17 impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
18     /// Fills the `Resolver::access_levels` table with public & exported items
19     /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
20     /// need access to a TyCtxt for that.
21     pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
22         let mut visitor = AccessLevelsVisitor { r, changed: false };
23
24         visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, AccessLevel::Public);
25         visitor.set_bindings_access_level(CRATE_DEF_ID);
26
27         while visitor.changed {
28             visitor.reset();
29             visit::walk_crate(&mut visitor, krate);
30         }
31
32         info!("resolve::access_levels: {:#?}", r.access_levels);
33     }
34
35     fn reset(&mut self) {
36         self.changed = false;
37     }
38
39     /// Update the access level of the bindings in the given module accordingly. The module access
40     /// level has to be Exported or Public.
41     /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
42     fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
43         assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
44         let module = self.r.get_module(module_id.to_def_id()).unwrap();
45         let resolutions = self.r.resolutions(module);
46
47         for (_, name_resolution) in resolutions.borrow().iter() {
48             if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
49                 // Set the given binding access level to `AccessLevel::Public` and
50                 // sets the rest of the `use` chain to `AccessLevel::Exported` until
51                 // we hit the actual exported item.
52
53                 // FIXME: tag and is_public() condition should be removed, but assertions occur.
54                 let tag = if binding.is_import() { AccessLevel::Exported } else { AccessLevel::Public };
55                 if binding.vis.is_public() {
56                     let mut prev_parent_id = module_id;
57                     let mut level = AccessLevel::Public;
58                     while let NameBindingKind::Import { binding: nested_binding, import, .. } =
59                         binding.kind
60                     {
61                         let mut update = |node_id| self.update(
62                             self.r.local_def_id(node_id),
63                             binding.vis.expect_local(),
64                             prev_parent_id,
65                             level,
66                         );
67                         // In theory all the import IDs have individual visibilities and effective
68                         // visibilities, but in practice these IDs go straigth to HIR where all
69                         // their few uses assume that their (effective) visibility applies to the
70                         // whole syntactic `use` item. So we update them all to the maximum value
71                         // among the potential individual effective visibilities. Maybe HIR for
72                         // imports shouldn't use three IDs at all.
73                         update(import.id);
74                         if let ImportKind::Single { additional_ids, .. } = import.kind {
75                             update(additional_ids.0);
76                             update(additional_ids.1);
77                         }
78
79                         level = AccessLevel::Exported;
80                         prev_parent_id = self.r.local_def_id(import.id);
81                         binding = nested_binding;
82                     }
83                 }
84
85                 if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
86                     self.update(def_id, binding.vis.expect_local(), module_id, tag);
87                 }
88             }
89         }
90     }
91
92     fn update(
93         &mut self,
94         def_id: LocalDefId,
95         nominal_vis: Visibility,
96         parent_id: LocalDefId,
97         tag: AccessLevel,
98     ) {
99         let mut access_levels = std::mem::take(&mut self.r.access_levels);
100         let module_id =
101             self.r.get_nearest_non_block_module(def_id.to_def_id()).def_id().expect_local();
102         let res = access_levels.update(
103             def_id,
104             nominal_vis,
105             || Visibility::Restricted(module_id),
106             parent_id,
107             tag,
108             &*self.r,
109         );
110         if let Ok(changed) = res {
111             self.changed |= changed;
112         } else {
113             self.r.session.delay_span_bug(
114                 self.r.opt_span(def_id.to_def_id()).unwrap(),
115                 "Can't update effective visibility",
116             );
117         }
118         self.r.access_levels = access_levels;
119     }
120 }
121
122 impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
123     fn visit_item(&mut self, item: &'ast ast::Item) {
124         let def_id = self.r.local_def_id(item.id);
125         // Set access level of nested items.
126         // If it's a mod, also make the visitor walk all of its items
127         match item.kind {
128             // Resolved in rustc_privacy when types are available
129             ast::ItemKind::Impl(..) => return,
130
131             // Should be unreachable at this stage
132             ast::ItemKind::MacCall(..) => panic!(
133                 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
134             ),
135
136             // Foreign modules inherit level from parents.
137             ast::ItemKind::ForeignMod(..) => {
138                 let parent_id = self.r.local_parent(def_id);
139                 self.update(def_id, Visibility::Public, parent_id, AccessLevel::Public);
140             }
141
142             // Only exported `macro_rules!` items are public, but they always are
143             ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
144                 let parent_id = self.r.local_parent(def_id);
145                 let vis = self.r.visibilities[&def_id];
146                 self.update(def_id, vis, parent_id, AccessLevel::Public);
147             }
148
149             ast::ItemKind::Mod(..) => {
150                 self.set_bindings_access_level(def_id);
151                 visit::walk_item(self, item);
152             }
153
154             ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
155                 self.set_bindings_access_level(def_id);
156                 for variant in variants {
157                     let variant_def_id = self.r.local_def_id(variant.id);
158                     for field in variant.data.fields() {
159                         let field_def_id = self.r.local_def_id(field.id);
160                         let vis = self.r.visibilities[&field_def_id];
161                         self.update(field_def_id, vis, variant_def_id, AccessLevel::Public);
162                     }
163                 }
164             }
165
166             ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
167                 for field in def.fields() {
168                     let field_def_id = self.r.local_def_id(field.id);
169                     let vis = self.r.visibilities[&field_def_id];
170                     self.update(field_def_id, vis, def_id, AccessLevel::Public);
171                 }
172             }
173
174             ast::ItemKind::Trait(..) => {
175                 self.set_bindings_access_level(def_id);
176             }
177
178             ast::ItemKind::ExternCrate(..)
179             | ast::ItemKind::Use(..)
180             | ast::ItemKind::Static(..)
181             | ast::ItemKind::Const(..)
182             | ast::ItemKind::GlobalAsm(..)
183             | ast::ItemKind::TyAlias(..)
184             | ast::ItemKind::TraitAlias(..)
185             | ast::ItemKind::MacroDef(..)
186             | ast::ItemKind::Fn(..) => return,
187         }
188     }
189 }