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,25 @@ 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
32
58
info ! ( "resolve::effective_visibilities: {:#?}" , r. effective_visibilities) ;
33
59
}
34
60
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 ( )
37
63
}
38
64
39
65
/// Update effective visibilities of bindings in the given module,
@@ -48,92 +74,114 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
48
74
// Set the given effective visibility level to `Level::Direct` and
49
75
// sets the rest of the `use` chain to `Level::Reexported` until
50
76
// 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 ( ) {
60
89
let mut update = |node_id| {
61
- self . update (
90
+ self . update_def (
62
91
self . r . local_def_id ( node_id) ,
63
92
binding. vis . expect_local ( ) ,
64
- prev_parent_id,
65
- level,
93
+ parent_id,
66
94
)
67
95
} ;
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) ;
85
106
}
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) ;
95
109
}
96
110
}
97
-
98
- level = Level :: Reexported ;
99
- binding = nested_binding;
100
111
}
112
+
113
+ parent_id = ParentId :: Import ( binding_id) ;
114
+ binding = nested_binding;
101
115
}
102
116
103
117
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 ) ;
105
119
}
106
120
}
107
121
}
108
122
}
109
123
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 > ,
113
136
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) {
125
171
return ;
126
172
}
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 (
129
174
def_id,
130
175
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 ) ,
135
180
) ;
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) ) ;
137
185
}
138
186
}
139
187
@@ -151,12 +199,6 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
151
199
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
152
200
) ,
153
201
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
202
ast:: ItemKind :: Mod ( ..) => {
161
203
self . set_bindings_effective_visibilities ( def_id) ;
162
204
visit:: walk_item ( self , item) ;
@@ -167,18 +209,14 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
167
209
for variant in variants {
168
210
let variant_def_id = self . r . local_def_id ( variant. id ) ;
169
211
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) ;
173
213
}
174
214
}
175
215
}
176
216
177
217
ast:: ItemKind :: Struct ( ref def, _) | ast:: ItemKind :: Union ( ref def, _) => {
178
218
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) ;
182
220
}
183
221
}
184
222
@@ -194,6 +232,7 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
194
232
| ast:: ItemKind :: TyAlias ( ..)
195
233
| ast:: ItemKind :: TraitAlias ( ..)
196
234
| ast:: ItemKind :: MacroDef ( ..)
235
+ | ast:: ItemKind :: ForeignMod ( ..)
197
236
| ast:: ItemKind :: Fn ( ..) => return ,
198
237
}
199
238
}
0 commit comments