@@ -68,24 +68,6 @@ pub struct ImportDirective<'a> {
68
68
}
69
69
70
70
impl < ' a > ImportDirective < ' a > {
71
- pub fn new ( module_path : Vec < Name > ,
72
- subclass : ImportDirectiveSubclass ,
73
- span : Span ,
74
- id : NodeId ,
75
- is_public : bool ,
76
- is_prelude : bool )
77
- -> Self {
78
- ImportDirective {
79
- module_path : module_path,
80
- target_module : Cell :: new ( None ) ,
81
- subclass : subclass,
82
- span : span,
83
- id : id,
84
- is_public : is_public,
85
- is_prelude : is_prelude,
86
- }
87
- }
88
-
89
71
// Given the binding to which this directive resolves in a particular namespace,
90
72
// this returns the binding for the name this directive defines in that namespace.
91
73
fn import ( & self , binding : & ' a NameBinding < ' a > , privacy_error : Option < Box < PrivacyError < ' a > > > )
@@ -111,17 +93,52 @@ impl<'a> ImportDirective<'a> {
111
93
}
112
94
113
95
#[ derive( Clone , Default ) ]
114
- /// Records information about the resolution of a name in a module.
96
+ /// Records information about the resolution of a name in a namespace of a module.
115
97
pub struct NameResolution < ' a > {
116
- /// The number of unresolved single imports of any visibility that could define the name.
117
- outstanding_references : u32 ,
118
- /// The number of unresolved `pub` single imports that could define the name.
119
- pub_outstanding_references : u32 ,
98
+ /// The single imports that define the name in the namespace.
99
+ single_imports : SingleImports < ' a > ,
120
100
/// The least shadowable known binding for this name, or None if there are no known bindings.
121
101
pub binding : Option < & ' a NameBinding < ' a > > ,
122
102
duplicate_globs : Vec < & ' a NameBinding < ' a > > ,
123
103
}
124
104
105
+ #[ derive( Clone , Debug ) ]
106
+ enum SingleImports < ' a > {
107
+ /// No single imports can define the name in the namespace.
108
+ None ,
109
+ /// Only the given single import can define the name in the namespace.
110
+ MaybeOne ( & ' a ImportDirective < ' a > ) ,
111
+ /// At least one single import will define the name in the namespace.
112
+ AtLeastOne ,
113
+ }
114
+
115
+ impl < ' a > Default for SingleImports < ' a > {
116
+ fn default ( ) -> Self {
117
+ SingleImports :: None
118
+ }
119
+ }
120
+
121
+ impl < ' a > SingleImports < ' a > {
122
+ fn add_directive ( & mut self , directive : & ' a ImportDirective < ' a > ) {
123
+ match * self {
124
+ SingleImports :: None => * self = SingleImports :: MaybeOne ( directive) ,
125
+ // If two single imports can define the name in the namespace, we can assume that at
126
+ // least one of them will define it since otherwise both would have to define only one
127
+ // namespace, leading to a duplicate error.
128
+ SingleImports :: MaybeOne ( _) => * self = SingleImports :: AtLeastOne ,
129
+ SingleImports :: AtLeastOne => { }
130
+ } ;
131
+ }
132
+
133
+ fn directive_failed ( & mut self ) {
134
+ match * self {
135
+ SingleImports :: None => unreachable ! ( ) ,
136
+ SingleImports :: MaybeOne ( _) => * self = SingleImports :: None ,
137
+ SingleImports :: AtLeastOne => { }
138
+ }
139
+ }
140
+ }
141
+
125
142
impl < ' a > NameResolution < ' a > {
126
143
fn try_define ( & mut self , binding : & ' a NameBinding < ' a > ) -> Result < ( ) , & ' a NameBinding < ' a > > {
127
144
if let Some ( old_binding) = self . binding {
@@ -140,40 +157,43 @@ impl<'a> NameResolution<'a> {
140
157
Ok ( ( ) )
141
158
}
142
159
160
+ // Returns the binding for the name if it is known or None if it not known.
161
+ fn binding ( & self ) -> Option < & ' a NameBinding < ' a > > {
162
+ self . binding . and_then ( |binding| match self . single_imports {
163
+ SingleImports :: None => Some ( binding) ,
164
+ _ if !binding. defined_with ( DefModifiers :: GLOB_IMPORTED ) => Some ( binding) ,
165
+ _ => None , // The binding could be shadowed by a single import, so it is not known.
166
+ } )
167
+ }
168
+
143
169
// Returns Some(the resolution of the name), or None if the resolution depends
144
170
// on whether more globs can define the name.
145
171
fn try_result ( & self , allow_private_imports : bool )
146
172
-> Option < ResolveResult < & ' a NameBinding < ' a > > > {
147
173
match self . binding {
148
174
Some ( binding) if !binding. defined_with ( DefModifiers :: GLOB_IMPORTED ) =>
149
- Some ( Success ( binding) ) ,
150
- // If (1) we don't allow private imports, (2) no public single import can define the
151
- // name, and (3) no public glob has defined the name, the resolution depends on globs.
152
- _ if !allow_private_imports && self . pub_outstanding_references == 0 &&
153
- !self . binding . map ( NameBinding :: is_public) . unwrap_or ( false ) => None ,
154
- _ if self . outstanding_references > 0 => Some ( Indeterminate ) ,
155
- Some ( binding) => Some ( Success ( binding) ) ,
156
- None => None ,
157
- }
158
- }
159
-
160
- fn increment_outstanding_references ( & mut self , is_public : bool ) {
161
- self . outstanding_references += 1 ;
162
- if is_public {
163
- self . pub_outstanding_references += 1 ;
164
- }
165
- }
166
-
167
- fn decrement_outstanding_references ( & mut self , is_public : bool ) {
168
- let decrement_references = |count : & mut _ | {
169
- assert ! ( * count > 0 ) ;
170
- * count -= 1 ;
175
+ return Some ( Success ( binding) ) ,
176
+ _ => { } // Items and single imports are not shadowable
171
177
} ;
172
178
173
- decrement_references ( & mut self . outstanding_references ) ;
174
- if is_public {
175
- decrement_references ( & mut self . pub_outstanding_references ) ;
179
+ // Check if a single import can still define the name.
180
+ match self . single_imports {
181
+ SingleImports :: None => { } ,
182
+ SingleImports :: AtLeastOne => return Some ( Indeterminate ) ,
183
+ SingleImports :: MaybeOne ( directive) => {
184
+ // If (1) we don't allow private imports, (2) no public single import can define
185
+ // the name, and (3) no public glob has defined the name, the resolution depends
186
+ // on whether more globs can define the name.
187
+ if !allow_private_imports && !directive. is_public &&
188
+ !self . binding . map ( NameBinding :: is_public) . unwrap_or ( false ) {
189
+ return None ;
190
+ }
191
+
192
+ return Indeterminate ;
193
+ }
176
194
}
195
+
196
+ self . binding . map ( Success )
177
197
}
178
198
179
199
fn report_conflicts < F : FnMut ( & NameBinding , & NameBinding ) > ( & self , mut report : F ) {
@@ -245,35 +265,51 @@ impl<'a> ::ModuleS<'a> {
245
265
} )
246
266
}
247
267
248
- pub fn add_import_directive ( & self , directive : ImportDirective < ' a > ) {
249
- let directive = self . arenas . alloc_import_directive ( directive) ;
268
+ pub fn add_import_directive ( & self ,
269
+ module_path : Vec < Name > ,
270
+ subclass : ImportDirectiveSubclass ,
271
+ span : Span ,
272
+ id : NodeId ,
273
+ is_public : bool ,
274
+ is_prelude : bool ) {
275
+ let directive = self . arenas . alloc_import_directive ( ImportDirective {
276
+ module_path : module_path,
277
+ target_module : Cell :: new ( None ) ,
278
+ subclass : subclass,
279
+ span : span,
280
+ id : id,
281
+ is_public : is_public,
282
+ is_prelude : is_prelude,
283
+ } ) ;
284
+
250
285
self . unresolved_imports . borrow_mut ( ) . push ( directive) ;
251
- if let GlobImport = directive. subclass {
286
+ match directive. subclass {
287
+ SingleImport { target, .. } => {
288
+ let mut resolutions = self . resolutions . borrow_mut ( ) ;
289
+ for & ns in & [ ValueNS , TypeNS ] {
290
+ resolutions. entry ( ( target, ns) ) . or_insert_with ( Default :: default)
291
+ . single_imports . add_directive ( directive) ;
292
+ }
293
+ }
252
294
// We don't add prelude imports to the globs since they only affect lexical scopes,
253
295
// which are not relevant to import resolution.
254
- if !directive. is_prelude {
255
- self . globs . borrow_mut ( ) . push ( directive) ;
256
- }
296
+ GlobImport if directive. is_prelude => { }
297
+ GlobImport => self . globs . borrow_mut ( ) . push ( directive) ,
257
298
}
258
299
}
259
300
260
- pub fn increment_outstanding_references_for ( & self , name : Name , ns : Namespace , is_public : bool ) {
261
- self . resolutions . borrow_mut ( ) . entry ( ( name, ns) ) . or_insert_with ( Default :: default)
262
- . increment_outstanding_references ( is_public) ;
263
- }
264
-
265
301
// Use `update` to mutate the resolution for the name.
266
302
// If the resolution becomes a success, define it in the module's glob importers.
267
303
fn update_resolution < T , F > ( & self , name : Name , ns : Namespace , update : F ) -> T
268
304
where F : FnOnce ( & mut NameResolution < ' a > ) -> T
269
305
{
270
306
let mut resolutions = self . resolutions . borrow_mut ( ) ;
271
307
let resolution = resolutions. entry ( ( name, ns) ) . or_insert_with ( Default :: default) ;
272
- let was_success = resolution. try_result ( false ) . and_then ( ResolveResult :: success ) . is_some ( ) ;
308
+ let was_known = resolution. binding ( ) . is_some ( ) ;
273
309
274
310
let t = update ( resolution) ;
275
- if !was_success {
276
- if let Some ( Success ( binding) ) = resolution. try_result ( false ) {
311
+ if !was_known {
312
+ if let Some ( binding) = resolution. binding ( ) {
277
313
self . define_in_glob_importers ( name, ns, binding) ;
278
314
}
279
315
}
@@ -454,12 +490,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
454
490
// (as opposed to being indeterminate) when it can only be defined by the directive.
455
491
if !determined {
456
492
module_. resolutions . borrow_mut ( ) . get_mut ( & ( target, ns) ) . unwrap ( )
457
- . decrement_outstanding_references ( directive . is_public ) ;
493
+ . single_imports . directive_failed ( ) ;
458
494
}
459
495
let result =
460
496
self . resolver . resolve_name_in_module ( target_module, source, ns, false , true ) ;
461
497
if !determined {
462
- module_. increment_outstanding_references_for ( target, ns, directive. is_public )
498
+ module_. resolutions . borrow_mut ( ) . get_mut ( & ( target, ns) ) . unwrap ( )
499
+ . single_imports . add_directive ( directive) ;
463
500
}
464
501
result
465
502
} ;
@@ -491,11 +528,11 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
491
528
let binding = & directive. import ( binding, None ) ;
492
529
self . resolver . report_conflict ( module_, target, ns, binding, old_binding) ;
493
530
}
531
+ } else {
532
+ module_. update_resolution ( target, ns, |resolution| {
533
+ resolution. single_imports . directive_failed ( ) ;
534
+ } ) ;
494
535
}
495
-
496
- module_. update_resolution ( target, ns, |resolution| {
497
- resolution. decrement_outstanding_references ( directive. is_public ) ;
498
- } )
499
536
}
500
537
501
538
match ( & value_result, & type_result) {
@@ -605,7 +642,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
605
642
target_module. glob_importers . borrow_mut ( ) . push ( ( module_, directive) ) ;
606
643
607
644
for ( & ( name, ns) , resolution) in target_module. resolutions . borrow ( ) . iter ( ) {
608
- if let Some ( Success ( binding) ) = resolution. try_result ( false ) {
645
+ if let Some ( binding) = resolution. binding ( ) {
609
646
if binding. defined_with ( DefModifiers :: IMPORTABLE | DefModifiers :: PUBLIC ) {
610
647
let _ = module_. try_define_child ( name, ns, directive. import ( binding, None ) ) ;
611
648
}
0 commit comments