1 use crate::{NameBinding, NameBindingKind, Resolver}
;
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
::Level
;
11 use rustc_middle
::middle
::privacy
::{EffectiveVisibilities, EffectiveVisibility}
;
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(crate) struct EffectiveVisibilitiesVisitor
<'r
, 'a
, 'tcx
> {
33 r
: &'r
mut Resolver
<'a
, 'tcx
>,
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
,
44 impl Resolver
<'_
, '_
> {
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<'r
, 'a
, 'tcx
> EffectiveVisibilitiesVisitor
<'r
, 'a
, 'tcx
> {
71 /// Fills the `Resolver::effective_visibilities` table with public & exported items
72 /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
73 /// need access to a TyCtxt for that.
74 pub(crate) fn compute_effective_visibilities
<'c
>(
75 r
: &'r
mut Resolver
<'a
, 'tcx
>,
78 let mut visitor
= EffectiveVisibilitiesVisitor
{
80 def_effective_visibilities
: Default
::default(),
81 import_effective_visibilities
: Default
::default(),
82 current_private_vis
: Visibility
::Public
,
86 visitor
.update(CRATE_DEF_ID
, CRATE_DEF_ID
);
87 visitor
.current_private_vis
= Visibility
::Restricted(CRATE_DEF_ID
);
88 visitor
.set_bindings_effective_visibilities(CRATE_DEF_ID
);
90 while visitor
.changed
{
91 visitor
.changed
= false;
92 visit
::walk_crate(&mut visitor
, krate
);
94 visitor
.r
.effective_visibilities
= visitor
.def_effective_visibilities
;
96 // Update visibilities for import def ids. These are not used during the
97 // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
98 // information, but are used by later passes. Effective visibility of an import def id
99 // is the maximum value among visibilities of bindings corresponding to that def id.
100 for (binding
, eff_vis
) in visitor
.import_effective_visibilities
.iter() {
101 let NameBindingKind
::Import { import, .. }
= binding
.kind
else { unreachable!() }
;
102 if let Some(node_id
) = import
.id() {
103 r
.effective_visibilities
.update_eff_vis(r
.local_def_id(node_id
), eff_vis
, r
.tcx
)
107 info
!("resolve::effective_visibilities: {:#?}", r
.effective_visibilities
);
110 /// Update effective visibilities of bindings in the given module,
111 /// including their whole reexport chains.
112 fn set_bindings_effective_visibilities(&mut self, module_id
: LocalDefId
) {
113 assert
!(self.r
.module_map
.contains_key(&&module_id
.to_def_id()));
114 let module
= self.r
.get_module(module_id
.to_def_id()).unwrap();
115 let resolutions
= self.r
.resolutions(module
);
117 for (_
, name_resolution
) in resolutions
.borrow().iter() {
118 if let Some(mut binding
) = name_resolution
.borrow().binding() && !binding
.is_ambiguity() {
119 // Set the given effective visibility level to `Level::Direct` and
120 // sets the rest of the `use` chain to `Level::Reexported` until
121 // we hit the actual exported item.
122 let mut parent_id
= ParentId
::Def(module_id
);
123 while let NameBindingKind
::Import { binding: nested_binding, .. }
= binding
.kind
{
124 let binding_id
= ImportId
::new_unchecked(binding
);
125 self.update_import(binding_id
, parent_id
);
127 parent_id
= ParentId
::Import(binding_id
);
128 binding
= nested_binding
;
131 if let Some(def_id
) = binding
.res().opt_def_id().and_then(|id
| id
.as_local()) {
132 self.update_def(def_id
, binding
.vis
.expect_local(), parent_id
);
138 fn cheap_private_vis(&self, parent_id
: ParentId
<'_
>) -> Option
<Visibility
> {
139 matches
!(parent_id
, ParentId
::Def(_
)).then_some(self.current_private_vis
)
142 fn effective_vis_or_private(&mut self, parent_id
: ParentId
<'a
>) -> EffectiveVisibility
{
143 // Private nodes are only added to the table for caching, they could be added or removed at
144 // any moment without consequences, so we don't set `changed` to true when adding them.
146 ParentId
::Def(def_id
) => self
147 .def_effective_visibilities
148 .effective_vis_or_private(def_id
, || self.r
.private_vis_def(def_id
)),
149 ParentId
::Import(binding
) => self
150 .import_effective_visibilities
151 .effective_vis_or_private(binding
, || self.r
.private_vis_import(binding
)),
155 fn update_import(&mut self, binding
: ImportId
<'a
>, parent_id
: ParentId
<'a
>) {
156 let nominal_vis
= binding
.vis
.expect_local();
157 let private_vis
= self.cheap_private_vis(parent_id
);
158 let inherited_eff_vis
= self.effective_vis_or_private(parent_id
);
159 let tcx
= self.r
.tcx
;
160 self.changed
|= self.import_effective_visibilities
.update(
163 || private_vis
.unwrap_or_else(|| self.r
.private_vis_import(binding
)),
170 fn update_def(&mut self, def_id
: LocalDefId
, nominal_vis
: Visibility
, parent_id
: ParentId
<'a
>) {
171 let private_vis
= self.cheap_private_vis(parent_id
);
172 let inherited_eff_vis
= self.effective_vis_or_private(parent_id
);
173 let tcx
= self.r
.tcx
;
174 self.changed
|= self.def_effective_visibilities
.update(
177 || private_vis
.unwrap_or_else(|| self.r
.private_vis_def(def_id
)),
184 fn update(&mut self, def_id
: LocalDefId
, parent_id
: LocalDefId
) {
185 self.update_def(def_id
, self.r
.visibilities
[&def_id
], ParentId
::Def(parent_id
));
189 impl<'r
, 'ast
, 'tcx
> Visitor
<'ast
> for EffectiveVisibilitiesVisitor
<'ast
, 'r
, 'tcx
> {
190 fn visit_item(&mut self, item
: &'ast ast
::Item
) {
191 let def_id
= self.r
.local_def_id(item
.id
);
192 // Update effective visibilities of nested items.
193 // If it's a mod, also make the visitor walk all of its items
195 // Resolved in rustc_privacy when types are available
196 ast
::ItemKind
::Impl(..) => return,
198 // Should be unreachable at this stage
199 ast
::ItemKind
::MacCall(..) => panic
!(
200 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
203 ast
::ItemKind
::Mod(..) => {
204 let prev_private_vis
=
205 mem
::replace(&mut self.current_private_vis
, Visibility
::Restricted(def_id
));
206 self.set_bindings_effective_visibilities(def_id
);
207 visit
::walk_item(self, item
);
208 self.current_private_vis
= prev_private_vis
;
211 ast
::ItemKind
::Enum(EnumDef { ref variants }
, _
) => {
212 self.set_bindings_effective_visibilities(def_id
);
213 for variant
in variants
{
214 let variant_def_id
= self.r
.local_def_id(variant
.id
);
215 for field
in variant
.data
.fields() {
216 self.update(self.r
.local_def_id(field
.id
), variant_def_id
);
221 ast
::ItemKind
::Struct(ref def
, _
) | ast
::ItemKind
::Union(ref def
, _
) => {
222 for field
in def
.fields() {
223 self.update(self.r
.local_def_id(field
.id
), def_id
);
227 ast
::ItemKind
::Trait(..) => {
228 self.set_bindings_effective_visibilities(def_id
);
231 ast
::ItemKind
::ExternCrate(..)
232 | ast
::ItemKind
::Use(..)
233 | ast
::ItemKind
::Static(..)
234 | ast
::ItemKind
::Const(..)
235 | ast
::ItemKind
::GlobalAsm(..)
236 | ast
::ItemKind
::TyAlias(..)
237 | ast
::ItemKind
::TraitAlias(..)
238 | ast
::ItemKind
::MacroDef(..)
239 | ast
::ItemKind
::ForeignMod(..)
240 | ast
::ItemKind
::Fn(..) => return,