1- use crate :: { ImportKind , NameBindingKind , Resolver } ;
1+ use crate :: { ImportKind , NameBinding , NameBindingKind , Resolver , ResolverTree } ;
22use rustc_ast:: ast;
33use rustc_ast:: visit;
44use rustc_ast:: visit:: Visitor ;
55use rustc_ast:: Crate ;
66use rustc_ast:: EnumDef ;
7+ use rustc_data_structures:: intern:: Interned ;
78use rustc_hir:: def_id:: LocalDefId ;
89use rustc_hir:: def_id:: CRATE_DEF_ID ;
9- use rustc_middle:: middle:: privacy:: Level ;
10- use rustc_middle:: ty:: { DefIdTree , Visibility } ;
10+ use rustc_middle:: middle:: privacy:: { EffectiveVisibilities , EffectiveVisibility , Level } ;
11+ use rustc_middle:: ty:: Visibility ;
12+
13+ type ImportId < ' a > = Interned < ' a , NameBinding < ' a > > ;
14+
15+ #[ derive( Clone , Copy ) ]
16+ enum ParentId < ' a > {
17+ Def ( LocalDefId ) ,
18+ Import ( ImportId < ' a > ) ,
19+ }
20+
21+ impl ParentId < ' _ > {
22+ fn level ( self ) -> Level {
23+ match self {
24+ ParentId :: Def ( _) => Level :: Direct ,
25+ ParentId :: Import ( _) => Level :: Reexported ,
26+ }
27+ }
28+ }
1129
1230pub struct EffectiveVisibilitiesVisitor < ' r , ' a > {
1331 r : & ' r mut Resolver < ' a > ,
32+ /// While walking import chains we need to track effective visibilities per-binding, and def id
33+ /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple
34+ /// bindings can correspond to a single def id in imports. So we keep a separate table.
35+ import_effective_visibilities : EffectiveVisibilities < ImportId < ' a > > ,
1436 changed : bool ,
1537}
1638
@@ -19,21 +41,25 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
1941 /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
2042 /// need access to a TyCtxt for that.
2143 pub fn compute_effective_visibilities < ' c > ( r : & ' r mut Resolver < ' a > , krate : & ' c Crate ) {
22- let mut visitor = EffectiveVisibilitiesVisitor { r, changed : false } ;
44+ let mut visitor = EffectiveVisibilitiesVisitor {
45+ r,
46+ import_effective_visibilities : Default :: default ( ) ,
47+ changed : false ,
48+ } ;
2349
24- visitor. update ( CRATE_DEF_ID , Visibility :: Public , CRATE_DEF_ID , Level :: Direct ) ;
50+ visitor. update ( CRATE_DEF_ID , CRATE_DEF_ID ) ;
2551 visitor. set_bindings_effective_visibilities ( CRATE_DEF_ID ) ;
2652
2753 while visitor. changed {
28- visitor. reset ( ) ;
54+ visitor. changed = false ;
2955 visit:: walk_crate ( & mut visitor, krate) ;
3056 }
3157
3258 info ! ( "resolve::effective_visibilities: {:#?}" , r. effective_visibilities) ;
3359 }
3460
35- fn reset ( & mut self ) {
36- self . changed = false ;
61+ fn nearest_normal_mod ( & mut self , def_id : LocalDefId ) -> LocalDefId {
62+ self . r . get_nearest_non_block_module ( def_id . to_def_id ( ) ) . nearest_parent_mod ( ) . expect_local ( )
3763 }
3864
3965 /// Update effective visibilities of bindings in the given module,
@@ -48,92 +74,114 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
4874 // Set the given effective visibility level to `Level::Direct` and
4975 // sets the rest of the `use` chain to `Level::Reexported` until
5076 // we hit the actual exported item.
51-
52- // FIXME: tag and is_public() condition should be removed, but assertions occur.
53- let tag = if binding. is_import ( ) { Level :: Reexported } else { Level :: Direct } ;
54- if binding. vis . is_public ( ) {
55- let mut prev_parent_id = module_id;
56- let mut level = Level :: Direct ;
57- while let NameBindingKind :: Import { binding : nested_binding, import, .. } =
58- binding. kind
59- {
77+ let mut parent_id = ParentId :: Def ( module_id) ;
78+ while let NameBindingKind :: Import { binding : nested_binding, import, .. } =
79+ binding. kind
80+ {
81+ let binding_id = ImportId :: new_unchecked ( binding) ;
82+ self . update_import ( binding_id, parent_id) ;
83+
84+ // Update visibilities for import ids. These are not used during this pass,
85+ // because we have more detailed binding-based information, but are used by
86+ // later passes. Effective visibility of an import def id is the maximum value
87+ // among visibilities of bindings corresponding to that def id.
88+ if let Some ( node_id) = import. id ( ) {
6089 let mut update = |node_id| {
61- self . update (
90+ self . update_def (
6291 self . r . local_def_id ( node_id) ,
6392 binding. vis . expect_local ( ) ,
64- prev_parent_id,
65- level,
93+ parent_id,
6694 )
6795 } ;
68- match import. kind {
69- ImportKind :: Single { id, additional_ids, .. } => {
70- // In theory all the import IDs have individual visibilities and
71- // effective visibilities, but in practice these IDs go straigth to
72- // HIR where all their few uses assume that their (effective)
73- // visibility applies to the whole syntactic `use` item. So we
74- // update them all to the maximum value among the potential
75- // individual effective visibilities. Maybe HIR for imports
76- // shouldn't use three IDs at all.
77- update ( id) ;
78- update ( additional_ids. 0 ) ;
79- update ( additional_ids. 1 ) ;
80- prev_parent_id = self . r . local_def_id ( id) ;
81- }
82- ImportKind :: Glob { id, .. } | ImportKind :: ExternCrate { id, .. } => {
83- update ( id) ;
84- prev_parent_id = self . r . local_def_id ( id) ;
96+ update ( node_id) ;
97+ if let ImportKind :: Single { additional_ids : ( id1, id2) , .. } = import. kind {
98+ // In theory all the single import IDs have individual visibilities and
99+ // effective visibilities, but in practice these IDs go straigth to HIR
100+ // where all their few uses assume that their (effective) visibility
101+ // applies to the whole syntactic `use` item. So they all get the same
102+ // value which is the maximum of all bindings. Maybe HIR for imports
103+ // shouldn't use three IDs at all.
104+ if id1 != ast:: DUMMY_NODE_ID {
105+ update ( id1) ;
85106 }
86- ImportKind :: MacroUse => {
87- // In theory we should reset the parent id to something private
88- // here, but `macro_use` imports always refer to external items,
89- // so it doesn't matter and we can just do nothing.
90- }
91- ImportKind :: MacroExport => {
92- // In theory we should reset the parent id to something public
93- // here, but it has the same effect as leaving the previous parent,
94- // so we can just do nothing.
107+ if id2 != ast:: DUMMY_NODE_ID {
108+ update ( id2) ;
95109 }
96110 }
97-
98- level = Level :: Reexported ;
99- binding = nested_binding;
100111 }
112+
113+ parent_id = ParentId :: Import ( binding_id) ;
114+ binding = nested_binding;
101115 }
102116
103117 if let Some ( def_id) = binding. res ( ) . opt_def_id ( ) . and_then ( |id| id. as_local ( ) ) {
104- self . update ( def_id, binding. vis . expect_local ( ) , module_id , tag ) ;
118+ self . update_def ( def_id, binding. vis . expect_local ( ) , parent_id ) ;
105119 }
106120 }
107121 }
108122 }
109123
110- fn update (
111- & mut self ,
112- def_id : LocalDefId ,
124+ fn effective_vis ( & self , parent_id : ParentId < ' a > ) -> Option < EffectiveVisibility > {
125+ match parent_id {
126+ ParentId :: Def ( def_id) => self . r . effective_visibilities . effective_vis ( def_id) ,
127+ ParentId :: Import ( binding) => self . import_effective_visibilities . effective_vis ( binding) ,
128+ }
129+ . copied ( )
130+ }
131+
132+ /// The update is guaranteed to not change the table and we can skip it.
133+ fn is_noop_update (
134+ & self ,
135+ parent_id : ParentId < ' a > ,
113136 nominal_vis : Visibility ,
114- parent_id : LocalDefId ,
115- tag : Level ,
116- ) {
117- let module_id = self
118- . r
119- . get_nearest_non_block_module ( def_id. to_def_id ( ) )
120- . nearest_parent_mod ( )
121- . expect_local ( ) ;
122- if nominal_vis == Visibility :: Restricted ( module_id)
123- || self . r . visibilities [ & parent_id] == Visibility :: Restricted ( module_id)
124- {
137+ default_vis : Visibility ,
138+ ) -> bool {
139+ nominal_vis == default_vis
140+ || match parent_id {
141+ ParentId :: Def ( def_id) => self . r . visibilities [ & def_id] ,
142+ ParentId :: Import ( binding) => binding. vis . expect_local ( ) ,
143+ } == default_vis
144+ }
145+
146+ fn update_import ( & mut self , binding : ImportId < ' a > , parent_id : ParentId < ' a > ) {
147+ let NameBindingKind :: Import { import, .. } = binding. kind else { unreachable ! ( ) } ;
148+ let nominal_vis = binding. vis . expect_local ( ) ;
149+ let default_vis = Visibility :: Restricted (
150+ import
151+ . id ( )
152+ . map ( |id| self . nearest_normal_mod ( self . r . local_def_id ( id) ) )
153+ . unwrap_or ( CRATE_DEF_ID ) ,
154+ ) ;
155+ if self . is_noop_update ( parent_id, nominal_vis, default_vis) {
156+ return ;
157+ }
158+ self . changed |= self . import_effective_visibilities . update (
159+ binding,
160+ nominal_vis,
161+ default_vis,
162+ self . effective_vis ( parent_id) ,
163+ parent_id. level ( ) ,
164+ ResolverTree ( & self . r . definitions , & self . r . crate_loader ) ,
165+ ) ;
166+ }
167+
168+ fn update_def ( & mut self , def_id : LocalDefId , nominal_vis : Visibility , parent_id : ParentId < ' a > ) {
169+ let default_vis = Visibility :: Restricted ( self . nearest_normal_mod ( def_id) ) ;
170+ if self . is_noop_update ( parent_id, nominal_vis, default_vis) {
125171 return ;
126172 }
127- let mut effective_visibilities = std:: mem:: take ( & mut self . r . effective_visibilities ) ;
128- self . changed |= effective_visibilities. update (
173+ self . changed |= self . r . effective_visibilities . update (
129174 def_id,
130175 nominal_vis,
131- || Visibility :: Restricted ( module_id ) ,
132- parent_id,
133- tag ,
134- & * self . r ,
176+ if def_id == CRATE_DEF_ID { Visibility :: Public } else { default_vis } ,
177+ self . effective_vis ( parent_id) ,
178+ parent_id . level ( ) ,
179+ ResolverTree ( & self . r . definitions , & self . r . crate_loader ) ,
135180 ) ;
136- self . r . effective_visibilities = effective_visibilities;
181+ }
182+
183+ fn update ( & mut self , def_id : LocalDefId , parent_id : LocalDefId ) {
184+ self . update_def ( def_id, self . r . visibilities [ & def_id] , ParentId :: Def ( parent_id) ) ;
137185 }
138186}
139187
@@ -151,12 +199,6 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
151199 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
152200 ) ,
153201
154- // Foreign modules inherit level from parents.
155- ast:: ItemKind :: ForeignMod ( ..) => {
156- let parent_id = self . r . local_parent ( def_id) ;
157- self . update ( def_id, Visibility :: Public , parent_id, Level :: Direct ) ;
158- }
159-
160202 ast:: ItemKind :: Mod ( ..) => {
161203 self . set_bindings_effective_visibilities ( def_id) ;
162204 visit:: walk_item ( self , item) ;
@@ -167,18 +209,14 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
167209 for variant in variants {
168210 let variant_def_id = self . r . local_def_id ( variant. id ) ;
169211 for field in variant. data . fields ( ) {
170- let field_def_id = self . r . local_def_id ( field. id ) ;
171- let vis = self . r . visibilities [ & field_def_id] ;
172- self . update ( field_def_id, vis, variant_def_id, Level :: Direct ) ;
212+ self . update ( self . r . local_def_id ( field. id ) , variant_def_id) ;
173213 }
174214 }
175215 }
176216
177217 ast:: ItemKind :: Struct ( ref def, _) | ast:: ItemKind :: Union ( ref def, _) => {
178218 for field in def. fields ( ) {
179- let field_def_id = self . r . local_def_id ( field. id ) ;
180- let vis = self . r . visibilities [ & field_def_id] ;
181- self . update ( field_def_id, vis, def_id, Level :: Direct ) ;
219+ self . update ( self . r . local_def_id ( field. id ) , def_id) ;
182220 }
183221 }
184222
@@ -194,6 +232,7 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
194232 | ast:: ItemKind :: TyAlias ( ..)
195233 | ast:: ItemKind :: TraitAlias ( ..)
196234 | ast:: ItemKind :: MacroDef ( ..)
235+ | ast:: ItemKind :: ForeignMod ( ..)
197236 | ast:: ItemKind :: Fn ( ..) => return ,
198237 }
199238 }
0 commit comments