1 use crate::{NameBinding, NameBindingKind, Resolver, ResolverTree}
;
4 use rustc_ast
::visit
::Visitor
;
6 use rustc_ast
::EnumDef
;
7 use rustc_data_structures
::intern
::Interned
;
8 use rustc_hir
::def_id
::LocalDefId
;
9 use rustc_hir
::def_id
::CRATE_DEF_ID
;
10 use rustc_middle
::middle
::privacy
::{EffectiveVisibilities, EffectiveVisibility}
;
11 use rustc_middle
::middle
::privacy
::{IntoDefIdTree, Level}
;
12 use rustc_middle
::ty
::{DefIdTree, Visibility}
;
15 type ImportId
<'a
> = Interned
<'a
, NameBinding
<'a
>>;
17 #[derive(Clone, Copy)]
24 fn level(self) -> Level
{
26 ParentId
::Def(_
) => Level
::Direct
,
27 ParentId
::Import(_
) => Level
::Reexported
,
32 pub struct EffectiveVisibilitiesVisitor
<'r
, 'a
> {
33 r
: &'r
mut Resolver
<'a
>,
34 def_effective_visibilities
: EffectiveVisibilities
,
35 /// While walking import chains we need to track effective visibilities per-binding, and def id
36 /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple
37 /// bindings can correspond to a single def id in imports. So we keep a separate table.
38 import_effective_visibilities
: EffectiveVisibilities
<ImportId
<'a
>>,
39 // It's possible to recalculate this at any point, but it's relatively expensive.
40 current_private_vis
: Visibility
,
45 fn nearest_normal_mod(&mut self, def_id
: LocalDefId
) -> LocalDefId
{
46 self.get_nearest_non_block_module(def_id
.to_def_id()).nearest_parent_mod().expect_local()
49 fn private_vis_import(&mut self, binding
: ImportId
<'_
>) -> Visibility
{
50 let NameBindingKind
::Import { import, .. }
= binding
.kind
else { unreachable!() }
;
51 Visibility
::Restricted(
54 .map(|id
| self.nearest_normal_mod(self.local_def_id(id
)))
55 .unwrap_or(CRATE_DEF_ID
),
59 fn private_vis_def(&mut self, def_id
: LocalDefId
) -> Visibility
{
60 // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent.
61 let normal_mod_id
= self.nearest_normal_mod(def_id
);
62 if normal_mod_id
== def_id
{
63 self.opt_local_parent(def_id
).map_or(Visibility
::Public
, Visibility
::Restricted
)
65 Visibility
::Restricted(normal_mod_id
)
70 impl<'a
, 'b
> IntoDefIdTree
for &'b
mut Resolver
<'a
> {
71 type Tree
= &'b Resolver
<'a
>;
72 fn tree(self) -> Self::Tree
{
77 impl<'r
, 'a
> EffectiveVisibilitiesVisitor
<'r
, 'a
> {
78 /// Fills the `Resolver::effective_visibilities` table with public & exported items
79 /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
80 /// need access to a TyCtxt for that.
81 pub fn compute_effective_visibilities
<'c
>(r
: &'r
mut Resolver
<'a
>, krate
: &'c Crate
) {
82 let mut visitor
= EffectiveVisibilitiesVisitor
{
84 def_effective_visibilities
: Default
::default(),
85 import_effective_visibilities
: Default
::default(),
86 current_private_vis
: Visibility
::Public
,
90 visitor
.update(CRATE_DEF_ID
, CRATE_DEF_ID
);
91 visitor
.current_private_vis
= Visibility
::Restricted(CRATE_DEF_ID
);
92 visitor
.set_bindings_effective_visibilities(CRATE_DEF_ID
);
94 while visitor
.changed
{
95 visitor
.changed
= false;
96 visit
::walk_crate(&mut visitor
, krate
);
98 visitor
.r
.effective_visibilities
= visitor
.def_effective_visibilities
;
100 // Update visibilities for import def ids. These are not used during the
101 // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
102 // information, but are used by later passes. Effective visibility of an import def id
103 // is the maximum value among visibilities of bindings corresponding to that def id.
104 for (binding
, eff_vis
) in visitor
.import_effective_visibilities
.iter() {
105 let NameBindingKind
::Import { import, .. }
= binding
.kind
else { unreachable!() }
;
106 if let Some(node_id
) = import
.id() {
107 r
.effective_visibilities
.update_eff_vis(
108 r
.local_def_id(node_id
),
110 ResolverTree(&r
.untracked
),
115 info
!("resolve::effective_visibilities: {:#?}", r
.effective_visibilities
);
118 /// Update effective visibilities of bindings in the given module,
119 /// including their whole reexport chains.
120 fn set_bindings_effective_visibilities(&mut self, module_id
: LocalDefId
) {
121 assert
!(self.r
.module_map
.contains_key(&&module_id
.to_def_id()));
122 let module
= self.r
.get_module(module_id
.to_def_id()).unwrap();
123 let resolutions
= self.r
.resolutions(module
);
125 for (_
, name_resolution
) in resolutions
.borrow().iter() {
126 if let Some(mut binding
) = name_resolution
.borrow().binding() && !binding
.is_ambiguity() {
127 // Set the given effective visibility level to `Level::Direct` and
128 // sets the rest of the `use` chain to `Level::Reexported` until
129 // we hit the actual exported item.
130 let mut parent_id
= ParentId
::Def(module_id
);
131 while let NameBindingKind
::Import { binding: nested_binding, .. }
= binding
.kind
{
132 let binding_id
= ImportId
::new_unchecked(binding
);
133 self.update_import(binding_id
, parent_id
);
135 parent_id
= ParentId
::Import(binding_id
);
136 binding
= nested_binding
;
139 if let Some(def_id
) = binding
.res().opt_def_id().and_then(|id
| id
.as_local()) {
140 self.update_def(def_id
, binding
.vis
.expect_local(), parent_id
);
146 fn cheap_private_vis(&self, parent_id
: ParentId
<'_
>) -> Option
<Visibility
> {
147 matches
!(parent_id
, ParentId
::Def(_
)).then_some(self.current_private_vis
)
150 fn effective_vis_or_private(&mut self, parent_id
: ParentId
<'a
>) -> EffectiveVisibility
{
151 // Private nodes are only added to the table for caching, they could be added or removed at
152 // any moment without consequences, so we don't set `changed` to true when adding them.
154 ParentId
::Def(def_id
) => self
155 .def_effective_visibilities
156 .effective_vis_or_private(def_id
, || self.r
.private_vis_def(def_id
)),
157 ParentId
::Import(binding
) => self
158 .import_effective_visibilities
159 .effective_vis_or_private(binding
, || self.r
.private_vis_import(binding
)),
163 fn update_import(&mut self, binding
: ImportId
<'a
>, parent_id
: ParentId
<'a
>) {
164 let nominal_vis
= binding
.vis
.expect_local();
165 let private_vis
= self.cheap_private_vis(parent_id
);
166 let inherited_eff_vis
= self.effective_vis_or_private(parent_id
);
167 self.changed
|= self.import_effective_visibilities
.update(
170 |r
| (private_vis
.unwrap_or_else(|| r
.private_vis_import(binding
)), r
),
177 fn update_def(&mut self, def_id
: LocalDefId
, nominal_vis
: Visibility
, parent_id
: ParentId
<'a
>) {
178 let private_vis
= self.cheap_private_vis(parent_id
);
179 let inherited_eff_vis
= self.effective_vis_or_private(parent_id
);
180 self.changed
|= self.def_effective_visibilities
.update(
183 |r
| (private_vis
.unwrap_or_else(|| r
.private_vis_def(def_id
)), r
),
190 fn update(&mut self, def_id
: LocalDefId
, parent_id
: LocalDefId
) {
191 self.update_def(def_id
, self.r
.visibilities
[&def_id
], ParentId
::Def(parent_id
));
195 impl<'r
, 'ast
> Visitor
<'ast
> for EffectiveVisibilitiesVisitor
<'ast
, 'r
> {
196 fn visit_item(&mut self, item
: &'ast ast
::Item
) {
197 let def_id
= self.r
.local_def_id(item
.id
);
198 // Update effective visibilities of nested items.
199 // If it's a mod, also make the visitor walk all of its items
201 // Resolved in rustc_privacy when types are available
202 ast
::ItemKind
::Impl(..) => return,
204 // Should be unreachable at this stage
205 ast
::ItemKind
::MacCall(..) => panic
!(
206 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
209 ast
::ItemKind
::Mod(..) => {
210 let prev_private_vis
=
211 mem
::replace(&mut self.current_private_vis
, Visibility
::Restricted(def_id
));
212 self.set_bindings_effective_visibilities(def_id
);
213 visit
::walk_item(self, item
);
214 self.current_private_vis
= prev_private_vis
;
217 ast
::ItemKind
::Enum(EnumDef { ref variants }
, _
) => {
218 self.set_bindings_effective_visibilities(def_id
);
219 for variant
in variants
{
220 let variant_def_id
= self.r
.local_def_id(variant
.id
);
221 for field
in variant
.data
.fields() {
222 self.update(self.r
.local_def_id(field
.id
), variant_def_id
);
227 ast
::ItemKind
::Struct(ref def
, _
) | ast
::ItemKind
::Union(ref def
, _
) => {
228 for field
in def
.fields() {
229 self.update(self.r
.local_def_id(field
.id
), def_id
);
233 ast
::ItemKind
::Trait(..) => {
234 self.set_bindings_effective_visibilities(def_id
);
237 ast
::ItemKind
::ExternCrate(..)
238 | ast
::ItemKind
::Use(..)
239 | ast
::ItemKind
::Static(..)
240 | ast
::ItemKind
::Const(..)
241 | ast
::ItemKind
::GlobalAsm(..)
242 | ast
::ItemKind
::TyAlias(..)
243 | ast
::ItemKind
::TraitAlias(..)
244 | ast
::ItemKind
::MacroDef(..)
245 | ast
::ItemKind
::ForeignMod(..)
246 | ast
::ItemKind
::Fn(..) => return,