@@ -4,13 +4,17 @@ use rustc_ast::visit;
44use rustc_ast:: visit:: Visitor ;
55use rustc_ast:: Crate ;
66use rustc_ast:: EnumDef ;
7+ use rustc_hir:: def:: { DefKind , Res } ;
78use rustc_hir:: def_id:: LocalDefId ;
89use rustc_hir:: def_id:: CRATE_DEF_ID ;
910use rustc_middle:: middle:: privacy:: Level ;
1011use rustc_middle:: ty:: { DefIdTree , Visibility } ;
12+ use std:: mem;
1113
1214pub struct EffectiveVisibilitiesVisitor < ' r , ' a > {
1315 r : & ' r mut Resolver < ' a > ,
16+ // It's possible to recalculate this at any point, but it's relatively expensive.
17+ current_normal_mod : LocalDefId ,
1418 changed : bool ,
1519}
1620
@@ -19,21 +23,22 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
1923 /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
2024 /// need access to a TyCtxt for that.
2125 pub fn compute_effective_visibilities < ' c > ( r : & ' r mut Resolver < ' a > , krate : & ' c Crate ) {
22- let mut visitor = EffectiveVisibilitiesVisitor { r, changed : false } ;
26+ let mut visitor =
27+ EffectiveVisibilitiesVisitor { r, current_normal_mod : CRATE_DEF_ID , changed : false } ;
2328
24- visitor. update ( CRATE_DEF_ID , Visibility :: Public , CRATE_DEF_ID , Level :: Direct ) ;
29+ visitor. update ( CRATE_DEF_ID , CRATE_DEF_ID ) ;
2530 visitor. set_bindings_effective_visibilities ( CRATE_DEF_ID ) ;
2631
2732 while visitor. changed {
28- visitor. reset ( ) ;
33+ visitor. changed = false ;
2934 visit:: walk_crate ( & mut visitor, krate) ;
3035 }
3136
3237 info ! ( "resolve::effective_visibilities: {:#?}" , r. effective_visibilities) ;
3338 }
3439
35- fn reset ( & mut self ) {
36- self . changed = false ;
40+ fn nearest_normal_mod ( & mut self , def_id : LocalDefId ) -> LocalDefId {
41+ self . r . get_nearest_non_block_module ( def_id . to_def_id ( ) ) . nearest_parent_mod ( ) . expect_local ( )
3742 }
3843
3944 /// Update effective visibilities of bindings in the given module,
@@ -49,20 +54,30 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
4954 // sets the rest of the `use` chain to `Level::Reexported` until
5055 // we hit the actual exported item.
5156
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 } ;
57+ // FIXME: level and is_public() condition should be removed, but assertions occur.
58+ let level = if binding. is_import ( ) { Level :: Reexported } else { Level :: Direct } ;
59+ let mut normal_mod_id = self . current_normal_mod ;
5460 if binding. vis . is_public ( ) {
5561 let mut prev_parent_id = module_id;
5662 let mut level = Level :: Direct ;
5763 while let NameBindingKind :: Import { binding : nested_binding, import, .. } =
5864 binding. kind
5965 {
60- let mut update = |node_id| self . update (
61- self . r . local_def_id ( node_id) ,
62- binding. vis . expect_local ( ) ,
63- prev_parent_id,
64- level,
65- ) ;
66+ let def_id = self . r . local_def_id ( import. id ) ;
67+ if level != Level :: Direct {
68+ // Not a first binding in the chain, recalculate parent module.
69+ normal_mod_id = self . nearest_normal_mod ( def_id) ;
70+ }
71+
72+ let mut update = |node_id| {
73+ self . update_ext (
74+ self . r . local_def_id ( node_id) ,
75+ binding. vis . expect_local ( ) ,
76+ prev_parent_id,
77+ normal_mod_id,
78+ level,
79+ )
80+ } ;
6681 // In theory all the import IDs have individual visibilities and effective
6782 // visibilities, but in practice these IDs go straigth to HIR where all
6883 // their few uses assume that their (effective) visibility applies to the
@@ -76,46 +91,69 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
7691 }
7792
7893 level = Level :: Reexported ;
79- prev_parent_id = self . r . local_def_id ( import . id ) ;
94+ prev_parent_id = def_id ;
8095 binding = nested_binding;
8196 }
8297 }
8398
84- if let Some ( def_id) = binding. res ( ) . opt_def_id ( ) . and_then ( |id| id. as_local ( ) ) {
85- self . update ( def_id, binding. vis . expect_local ( ) , module_id, tag) ;
99+ let res = binding. res ( ) ;
100+ if let Some ( def_id) = res. opt_def_id ( ) . and_then ( |id| id. as_local ( ) ) {
101+ if level != Level :: Direct
102+ || matches ! ( binding. kind, NameBindingKind :: Res ( _, _is_macro_export @ true ) )
103+ // FIXME: This condition is incorrect, but it preserves pre-existing logic.
104+ // Rewrite update logic to support parent nodes that are fully
105+ // private and not in the table (which makes sense for `mod` items).
106+ || matches ! ( res, Res :: Def ( DefKind :: Mod , _) )
107+ {
108+ // Not a first binding in the chain, recalculate parent module.
109+ normal_mod_id = self . nearest_normal_mod ( def_id) ;
110+ }
111+ self . update_ext (
112+ def_id,
113+ binding. vis . expect_local ( ) ,
114+ module_id,
115+ normal_mod_id,
116+ level,
117+ ) ;
86118 }
87119 }
88120 }
89121 }
90122
91- fn update (
123+ fn update_ext (
92124 & mut self ,
93125 def_id : LocalDefId ,
94126 nominal_vis : Visibility ,
95127 parent_id : LocalDefId ,
96- tag : Level ,
128+ normal_mod_id : LocalDefId ,
129+ level : Level ,
97130 ) {
98- let module_id = self
99- . r
100- . get_nearest_non_block_module ( def_id. to_def_id ( ) )
101- . nearest_parent_mod ( )
102- . expect_local ( ) ;
103- if nominal_vis == Visibility :: Restricted ( module_id)
104- || self . r . visibilities [ & parent_id] == Visibility :: Restricted ( module_id)
131+ if nominal_vis == Visibility :: Restricted ( normal_mod_id)
132+ || self . r . visibilities [ & parent_id] == Visibility :: Restricted ( normal_mod_id)
105133 {
106134 return ;
107135 }
108136 let mut effective_visibilities = std:: mem:: take ( & mut self . r . effective_visibilities ) ;
109137 self . changed |= effective_visibilities. update (
110138 def_id,
111139 nominal_vis,
112- || Visibility :: Restricted ( module_id ) ,
140+ || Visibility :: Restricted ( normal_mod_id ) ,
113141 parent_id,
114- tag ,
142+ level ,
115143 & * self . r ,
116144 ) ;
117145 self . r . effective_visibilities = effective_visibilities;
118146 }
147+
148+ fn update ( & mut self , def_id : LocalDefId , parent_id : LocalDefId ) {
149+ self . update_ext (
150+ def_id,
151+ self . r . visibilities [ & def_id] ,
152+ parent_id,
153+ self . current_normal_mod ,
154+ Level :: Direct ,
155+ ) ;
156+ }
119157}
120158
121159impl < ' r , ' ast > Visitor < ' ast > for EffectiveVisibilitiesVisitor < ' ast , ' r > {
@@ -132,41 +170,31 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
132170 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
133171 ) ,
134172
135- // Foreign modules inherit level from parents.
136- ast:: ItemKind :: ForeignMod ( ..) => {
137- let parent_id = self . r . local_parent ( def_id) ;
138- self . update ( def_id, Visibility :: Public , parent_id, Level :: Direct ) ;
139- }
140-
141173 // Only exported `macro_rules!` items are public, but they always are
142174 ast:: ItemKind :: MacroDef ( ref macro_def) if macro_def. macro_rules => {
143- let parent_id = self . r . local_parent ( def_id) ;
144- let vis = self . r . visibilities [ & def_id] ;
145- self . update ( def_id, vis, parent_id, Level :: Direct ) ;
175+ self . update ( def_id, self . r . local_parent ( def_id) ) ;
146176 }
147177
148178 ast:: ItemKind :: Mod ( ..) => {
179+ let prev_normal_mod = mem:: replace ( & mut self . current_normal_mod , def_id) ;
149180 self . set_bindings_effective_visibilities ( def_id) ;
150181 visit:: walk_item ( self , item) ;
182+ self . current_normal_mod = prev_normal_mod;
151183 }
152184
153185 ast:: ItemKind :: Enum ( EnumDef { ref variants } , _) => {
154186 self . set_bindings_effective_visibilities ( def_id) ;
155187 for variant in variants {
156188 let variant_def_id = self . r . local_def_id ( variant. id ) ;
157189 for field in variant. data . fields ( ) {
158- let field_def_id = self . r . local_def_id ( field. id ) ;
159- let vis = self . r . visibilities [ & field_def_id] ;
160- self . update ( field_def_id, vis, variant_def_id, Level :: Direct ) ;
190+ self . update ( self . r . local_def_id ( field. id ) , variant_def_id) ;
161191 }
162192 }
163193 }
164194
165195 ast:: ItemKind :: Struct ( ref def, _) | ast:: ItemKind :: Union ( ref def, _) => {
166196 for field in def. fields ( ) {
167- let field_def_id = self . r . local_def_id ( field. id ) ;
168- let vis = self . r . visibilities [ & field_def_id] ;
169- self . update ( field_def_id, vis, def_id, Level :: Direct ) ;
197+ self . update ( self . r . local_def_id ( field. id ) , def_id) ;
170198 }
171199 }
172200
@@ -182,6 +210,7 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
182210 | ast:: ItemKind :: TyAlias ( ..)
183211 | ast:: ItemKind :: TraitAlias ( ..)
184212 | ast:: ItemKind :: MacroDef ( ..)
213+ | ast:: ItemKind :: ForeignMod ( ..)
185214 | ast:: ItemKind :: Fn ( ..) => return ,
186215 }
187216 }
0 commit comments