1
- use crate :: { ImportKind , NameBindingKind , Resolver } ;
1
+ use crate :: { ImportKind , NameBinding , NameBindingKind , Resolver , ResolverTree } ;
2
2
use rustc_ast:: ast;
3
3
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_data_structures:: intern:: Interned ;
7
8
use rustc_hir:: def_id:: LocalDefId ;
8
9
use 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
+ }
11
29
12
30
pub struct EffectiveVisibilitiesVisitor < ' r , ' a > {
13
31
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 > > ,
14
36
changed : bool ,
15
37
}
16
38
@@ -19,21 +41,57 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
19
41
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
20
42
/// need access to a TyCtxt for that.
21
43
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
+ } ;
23
49
24
- visitor. update ( CRATE_DEF_ID , Visibility :: Public , CRATE_DEF_ID , Level :: Direct ) ;
50
+ visitor. update ( CRATE_DEF_ID , CRATE_DEF_ID ) ;
25
51
visitor. set_bindings_effective_visibilities ( CRATE_DEF_ID ) ;
26
52
27
53
while visitor. changed {
28
- visitor. reset ( ) ;
54
+ visitor. changed = false ;
29
55
visit:: walk_crate ( & mut visitor, krate) ;
30
56
}
31
57
58
+ // Update visibilities for import def ids. These are not used during the
59
+ // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
60
+ // information, but are used by later passes. Effective visibility of an import def id
61
+ // is the maximum value among visibilities of bindings corresponding to that def id.
62
+ for ( binding, eff_vis) in visitor. import_effective_visibilities . iter ( ) {
63
+ let NameBindingKind :: Import { import, .. } = binding. kind else { unreachable ! ( ) } ;
64
+ if let Some ( node_id) = import. id ( ) {
65
+ let mut update = |node_id| {
66
+ r. effective_visibilities . update_eff_vis (
67
+ r. local_def_id ( node_id) ,
68
+ eff_vis,
69
+ ResolverTree ( & r. definitions , & r. crate_loader ) ,
70
+ )
71
+ } ;
72
+ update ( node_id) ;
73
+ if let ImportKind :: Single { additional_ids : ( id1, id2) , .. } = import. kind {
74
+ // In theory all the single import IDs have individual visibilities and
75
+ // effective visibilities, but in practice these IDs go straigth to HIR
76
+ // where all their few uses assume that their (effective) visibility
77
+ // applies to the whole syntactic `use` item. So they all get the same
78
+ // value which is the maximum of all bindings. Maybe HIR for imports
79
+ // shouldn't use three IDs at all.
80
+ if id1 != ast:: DUMMY_NODE_ID {
81
+ update ( id1) ;
82
+ }
83
+ if id2 != ast:: DUMMY_NODE_ID {
84
+ update ( id2) ;
85
+ }
86
+ }
87
+ }
88
+ }
89
+
32
90
info ! ( "resolve::effective_visibilities: {:#?}" , r. effective_visibilities) ;
33
91
}
34
92
35
- fn reset ( & mut self ) {
36
- self . changed = false ;
93
+ fn nearest_normal_mod ( & mut self , def_id : LocalDefId ) -> LocalDefId {
94
+ self . r . get_nearest_non_block_module ( def_id . to_def_id ( ) ) . nearest_parent_mod ( ) . expect_local ( )
37
95
}
38
96
39
97
/// Update effective visibilities of bindings in the given module,
@@ -48,92 +106,83 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
48
106
// Set the given effective visibility level to `Level::Direct` and
49
107
// sets the rest of the `use` chain to `Level::Reexported` until
50
108
// we hit the actual exported item.
109
+ let mut parent_id = ParentId :: Def ( module_id) ;
110
+ while let NameBindingKind :: Import { binding : nested_binding, .. } = binding. kind {
111
+ let binding_id = ImportId :: new_unchecked ( binding) ;
112
+ self . update_import ( binding_id, parent_id) ;
51
113
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
- {
60
- let mut update = |node_id| {
61
- self . update (
62
- self . r . local_def_id ( node_id) ,
63
- binding. vis . expect_local ( ) ,
64
- prev_parent_id,
65
- level,
66
- )
67
- } ;
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) ;
85
- }
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.
95
- }
96
- }
97
-
98
- level = Level :: Reexported ;
99
- binding = nested_binding;
100
- }
114
+ parent_id = ParentId :: Import ( binding_id) ;
115
+ binding = nested_binding;
101
116
}
102
117
103
118
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 ) ;
119
+ self . update_def ( def_id, binding. vis . expect_local ( ) , parent_id ) ;
105
120
}
106
121
}
107
122
}
108
123
}
109
124
110
- fn update (
111
- & mut self ,
112
- def_id : LocalDefId ,
125
+ fn effective_vis ( & self , parent_id : ParentId < ' a > ) -> Option < EffectiveVisibility > {
126
+ match parent_id {
127
+ ParentId :: Def ( def_id) => self . r . effective_visibilities . effective_vis ( def_id) ,
128
+ ParentId :: Import ( binding) => self . import_effective_visibilities . effective_vis ( binding) ,
129
+ }
130
+ . copied ( )
131
+ }
132
+
133
+ /// The update is guaranteed to not change the table and we can skip it.
134
+ fn is_noop_update (
135
+ & self ,
136
+ parent_id : ParentId < ' a > ,
113
137
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
- {
138
+ default_vis : Visibility ,
139
+ ) -> bool {
140
+ nominal_vis == default_vis
141
+ || match parent_id {
142
+ ParentId :: Def ( def_id) => self . r . visibilities [ & def_id] ,
143
+ ParentId :: Import ( binding) => binding. vis . expect_local ( ) ,
144
+ } == default_vis
145
+ }
146
+
147
+ fn update_import ( & mut self , binding : ImportId < ' a > , parent_id : ParentId < ' a > ) {
148
+ let NameBindingKind :: Import { import, .. } = binding. kind else { unreachable ! ( ) } ;
149
+ let nominal_vis = binding. vis . expect_local ( ) ;
150
+ let default_vis = Visibility :: Restricted (
151
+ import
152
+ . id ( )
153
+ . map ( |id| self . nearest_normal_mod ( self . r . local_def_id ( id) ) )
154
+ . unwrap_or ( CRATE_DEF_ID ) ,
155
+ ) ;
156
+ if self . is_noop_update ( parent_id, nominal_vis, default_vis) {
125
157
return ;
126
158
}
127
- let mut effective_visibilities = std:: mem:: take ( & mut self . r . effective_visibilities ) ;
128
- self . changed |= effective_visibilities. update (
159
+ self . changed |= self . import_effective_visibilities . update (
160
+ binding,
161
+ nominal_vis,
162
+ default_vis,
163
+ self . effective_vis ( parent_id) ,
164
+ parent_id. level ( ) ,
165
+ ResolverTree ( & self . r . definitions , & self . r . crate_loader ) ,
166
+ ) ;
167
+ }
168
+
169
+ fn update_def ( & mut self , def_id : LocalDefId , nominal_vis : Visibility , parent_id : ParentId < ' a > ) {
170
+ let default_vis = Visibility :: Restricted ( self . nearest_normal_mod ( def_id) ) ;
171
+ if self . is_noop_update ( parent_id, nominal_vis, default_vis) {
172
+ return ;
173
+ }
174
+ self . changed |= self . r . effective_visibilities . update (
129
175
def_id,
130
176
nominal_vis,
131
- || Visibility :: Restricted ( module_id ) ,
132
- parent_id,
133
- tag ,
134
- & * self . r ,
177
+ if def_id == CRATE_DEF_ID { Visibility :: Public } else { default_vis } ,
178
+ self . effective_vis ( parent_id) ,
179
+ parent_id . level ( ) ,
180
+ ResolverTree ( & self . r . definitions , & self . r . crate_loader ) ,
135
181
) ;
136
- self . r . effective_visibilities = effective_visibilities;
182
+ }
183
+
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) ) ;
137
186
}
138
187
}
139
188
@@ -151,12 +200,6 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
151
200
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
152
201
) ,
153
202
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
-
160
203
ast:: ItemKind :: Mod ( ..) => {
161
204
self . set_bindings_effective_visibilities ( def_id) ;
162
205
visit:: walk_item ( self , item) ;
@@ -167,18 +210,14 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
167
210
for variant in variants {
168
211
let variant_def_id = self . r . local_def_id ( variant. id ) ;
169
212
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 ) ;
213
+ self . update ( self . r . local_def_id ( field. id ) , variant_def_id) ;
173
214
}
174
215
}
175
216
}
176
217
177
218
ast:: ItemKind :: Struct ( ref def, _) | ast:: ItemKind :: Union ( ref def, _) => {
178
219
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 ) ;
220
+ self . update ( self . r . local_def_id ( field. id ) , def_id) ;
182
221
}
183
222
}
184
223
@@ -194,6 +233,7 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
194
233
| ast:: ItemKind :: TyAlias ( ..)
195
234
| ast:: ItemKind :: TraitAlias ( ..)
196
235
| ast:: ItemKind :: MacroDef ( ..)
236
+ | ast:: ItemKind :: ForeignMod ( ..)
197
237
| ast:: ItemKind :: Fn ( ..) => return ,
198
238
}
199
239
}
0 commit comments