@@ -68,24 +68,6 @@ pub struct ImportDirective<'a> {
6868}
6969
7070impl < ' 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-
8971 // Given the binding to which this directive resolves in a particular namespace,
9072 // this returns the binding for the name this directive defines in that namespace.
9173 fn import ( & self , binding : & ' a NameBinding < ' a > , privacy_error : Option < Box < PrivacyError < ' a > > > )
@@ -111,17 +93,52 @@ impl<'a> ImportDirective<'a> {
11193}
11294
11395#[ 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.
11597pub 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 > ,
120100 /// The least shadowable known binding for this name, or None if there are no known bindings.
121101 pub binding : Option < & ' a NameBinding < ' a > > ,
122102 duplicate_globs : Vec < & ' a NameBinding < ' a > > ,
123103}
124104
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+
125142impl < ' a > NameResolution < ' a > {
126143 fn try_define ( & mut self , binding : & ' a NameBinding < ' a > ) -> Result < ( ) , & ' a NameBinding < ' a > > {
127144 if let Some ( old_binding) = self . binding {
@@ -140,40 +157,43 @@ impl<'a> NameResolution<'a> {
140157 Ok ( ( ) )
141158 }
142159
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+
143169 // Returns Some(the resolution of the name), or None if the resolution depends
144170 // on whether more globs can define the name.
145171 fn try_result ( & self , allow_private_imports : bool )
146172 -> Option < ResolveResult < & ' a NameBinding < ' a > > > {
147173 match self . binding {
148174 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
171177 } ;
172178
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+ }
176194 }
195+
196+ self . binding . map ( Success )
177197 }
178198
179199 fn report_conflicts < F : FnMut ( & NameBinding , & NameBinding ) > ( & self , mut report : F ) {
@@ -245,35 +265,51 @@ impl<'a> ::ModuleS<'a> {
245265 } )
246266 }
247267
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+
250285 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+ }
252294 // We don't add prelude imports to the globs since they only affect lexical scopes,
253295 // 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) ,
257298 }
258299 }
259300
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-
265301 // Use `update` to mutate the resolution for the name.
266302 // If the resolution becomes a success, define it in the module's glob importers.
267303 fn update_resolution < T , F > ( & self , name : Name , ns : Namespace , update : F ) -> T
268304 where F : FnOnce ( & mut NameResolution < ' a > ) -> T
269305 {
270306 let mut resolutions = self . resolutions . borrow_mut ( ) ;
271307 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 ( ) ;
273309
274310 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 ( ) {
277313 self . define_in_glob_importers ( name, ns, binding) ;
278314 }
279315 }
@@ -454,12 +490,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
454490 // (as opposed to being indeterminate) when it can only be defined by the directive.
455491 if !determined {
456492 module_. resolutions . borrow_mut ( ) . get_mut ( & ( target, ns) ) . unwrap ( )
457- . decrement_outstanding_references ( directive . is_public ) ;
493+ . single_imports . directive_failed ( ) ;
458494 }
459495 let result =
460496 self . resolver . resolve_name_in_module ( target_module, source, ns, false , true ) ;
461497 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) ;
463500 }
464501 result
465502 } ;
@@ -491,11 +528,11 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
491528 let binding = & directive. import ( binding, None ) ;
492529 self . resolver . report_conflict ( module_, target, ns, binding, old_binding) ;
493530 }
531+ } else {
532+ module_. update_resolution ( target, ns, |resolution| {
533+ resolution. single_imports . directive_failed ( ) ;
534+ } ) ;
494535 }
495-
496- module_. update_resolution ( target, ns, |resolution| {
497- resolution. decrement_outstanding_references ( directive. is_public ) ;
498- } )
499536 }
500537
501538 match ( & value_result, & type_result) {
@@ -605,7 +642,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
605642 target_module. glob_importers . borrow_mut ( ) . push ( ( module_, directive) ) ;
606643
607644 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 ( ) {
609646 if binding. defined_with ( DefModifiers :: IMPORTABLE | DefModifiers :: PUBLIC ) {
610647 let _ = module_. try_define_child ( name, ns, directive. import ( binding, None ) ) ;
611648 }
0 commit comments