@@ -4,13 +4,17 @@ use rustc_ast::visit;
4
4
use rustc_ast:: visit:: Visitor ;
5
5
use rustc_ast:: Crate ;
6
6
use rustc_ast:: EnumDef ;
7
+ use rustc_hir:: def:: { DefKind , Res } ;
7
8
use rustc_hir:: def_id:: LocalDefId ;
8
9
use rustc_hir:: def_id:: CRATE_DEF_ID ;
9
10
use rustc_middle:: middle:: privacy:: Level ;
10
11
use rustc_middle:: ty:: { DefIdTree , Visibility } ;
12
+ use std:: mem;
11
13
12
14
pub struct EffectiveVisibilitiesVisitor < ' r , ' a > {
13
15
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 ,
14
18
changed : bool ,
15
19
}
16
20
@@ -19,21 +23,22 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
19
23
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
20
24
/// need access to a TyCtxt for that.
21
25
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 } ;
23
28
24
- visitor. update ( CRATE_DEF_ID , Visibility :: Public , CRATE_DEF_ID , Level :: Direct ) ;
29
+ visitor. update ( CRATE_DEF_ID , CRATE_DEF_ID ) ;
25
30
visitor. set_bindings_effective_visibilities ( CRATE_DEF_ID ) ;
26
31
27
32
while visitor. changed {
28
- visitor. reset ( ) ;
33
+ visitor. changed = false ;
29
34
visit:: walk_crate ( & mut visitor, krate) ;
30
35
}
31
36
32
37
info ! ( "resolve::effective_visibilities: {:#?}" , r. effective_visibilities) ;
33
38
}
34
39
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 ( )
37
42
}
38
43
39
44
/// Update effective visibilities of bindings in the given module,
@@ -49,20 +54,30 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
49
54
// sets the rest of the `use` chain to `Level::Reexported` until
50
55
// we hit the actual exported item.
51
56
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 ;
54
60
if binding. vis . is_public ( ) {
55
61
let mut prev_parent_id = module_id;
56
62
let mut level = Level :: Direct ;
57
63
while let NameBindingKind :: Import { binding : nested_binding, import, .. } =
58
64
binding. kind
59
65
{
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
+ } ;
66
81
// In theory all the import IDs have individual visibilities and effective
67
82
// visibilities, but in practice these IDs go straigth to HIR where all
68
83
// their few uses assume that their (effective) visibility applies to the
@@ -76,46 +91,69 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
76
91
}
77
92
78
93
level = Level :: Reexported ;
79
- prev_parent_id = self . r . local_def_id ( import . id ) ;
94
+ prev_parent_id = def_id ;
80
95
binding = nested_binding;
81
96
}
82
97
}
83
98
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
+ ) ;
86
118
}
87
119
}
88
120
}
89
121
}
90
122
91
- fn update (
123
+ fn update_ext (
92
124
& mut self ,
93
125
def_id : LocalDefId ,
94
126
nominal_vis : Visibility ,
95
127
parent_id : LocalDefId ,
96
- tag : Level ,
128
+ normal_mod_id : LocalDefId ,
129
+ level : Level ,
97
130
) {
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)
105
133
{
106
134
return ;
107
135
}
108
136
let mut effective_visibilities = std:: mem:: take ( & mut self . r . effective_visibilities ) ;
109
137
self . changed |= effective_visibilities. update (
110
138
def_id,
111
139
nominal_vis,
112
- || Visibility :: Restricted ( module_id ) ,
140
+ || Visibility :: Restricted ( normal_mod_id ) ,
113
141
parent_id,
114
- tag ,
142
+ level ,
115
143
& * self . r ,
116
144
) ;
117
145
self . r . effective_visibilities = effective_visibilities;
118
146
}
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
+ }
119
157
}
120
158
121
159
impl < ' r , ' ast > Visitor < ' ast > for EffectiveVisibilitiesVisitor < ' ast , ' r > {
@@ -132,41 +170,31 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
132
170
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
133
171
) ,
134
172
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
-
141
173
// Only exported `macro_rules!` items are public, but they always are
142
174
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) ) ;
146
176
}
147
177
148
178
ast:: ItemKind :: Mod ( ..) => {
179
+ let prev_normal_mod = mem:: replace ( & mut self . current_normal_mod , def_id) ;
149
180
self . set_bindings_effective_visibilities ( def_id) ;
150
181
visit:: walk_item ( self , item) ;
182
+ self . current_normal_mod = prev_normal_mod;
151
183
}
152
184
153
185
ast:: ItemKind :: Enum ( EnumDef { ref variants } , _) => {
154
186
self . set_bindings_effective_visibilities ( def_id) ;
155
187
for variant in variants {
156
188
let variant_def_id = self . r . local_def_id ( variant. id ) ;
157
189
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) ;
161
191
}
162
192
}
163
193
}
164
194
165
195
ast:: ItemKind :: Struct ( ref def, _) | ast:: ItemKind :: Union ( ref def, _) => {
166
196
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) ;
170
198
}
171
199
}
172
200
@@ -182,6 +210,7 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
182
210
| ast:: ItemKind :: TyAlias ( ..)
183
211
| ast:: ItemKind :: TraitAlias ( ..)
184
212
| ast:: ItemKind :: MacroDef ( ..)
213
+ | ast:: ItemKind :: ForeignMod ( ..)
185
214
| ast:: ItemKind :: Fn ( ..) => return ,
186
215
}
187
216
}
0 commit comments