@@ -18,8 +18,7 @@ use crate::{
1818/// *from where* you're referring to the item, hence the `from` parameter.
1919pub fn find_path ( db : & dyn DefDatabase , item : ItemInNs , from : ModuleId ) -> Option < ModPath > {
2020 let _p = profile:: span ( "find_path" ) ;
21- let mut visited_modules = FxHashSet :: default ( ) ;
22- find_path_inner ( db, item, from, MAX_PATH_LEN , None , & mut visited_modules)
21+ find_path_inner ( db, item, from, None )
2322}
2423
2524pub fn find_path_prefixed (
@@ -29,8 +28,7 @@ pub fn find_path_prefixed(
2928 prefix_kind : PrefixKind ,
3029) -> Option < ModPath > {
3130 let _p = profile:: span ( "find_path_prefixed" ) ;
32- let mut visited_modules = FxHashSet :: default ( ) ;
33- find_path_inner ( db, item, from, MAX_PATH_LEN , Some ( prefix_kind) , & mut visited_modules)
31+ find_path_inner ( db, item, from, Some ( prefix_kind) )
3432}
3533
3634const MAX_PATH_LEN : usize = 15 ;
@@ -56,12 +54,12 @@ impl ModPathExt for ModPath {
5654fn check_self_super ( def_map : & DefMap , item : ItemInNs , from : ModuleId ) -> Option < ModPath > {
5755 if item == ItemInNs :: Types ( from. into ( ) ) {
5856 // - if the item is the module we're in, use `self`
59- Some ( ModPath :: from_segments ( PathKind :: Super ( 0 ) , Vec :: new ( ) ) )
57+ Some ( ModPath :: from_segments ( PathKind :: Super ( 0 ) , None ) )
6058 } else if let Some ( parent_id) = def_map[ from. local_id ] . parent {
6159 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
6260 let parent_id = def_map. module_id ( parent_id) ;
6361 if item == ItemInNs :: Types ( ModuleDefId :: ModuleId ( parent_id) ) {
64- Some ( ModPath :: from_segments ( PathKind :: Super ( 1 ) , Vec :: new ( ) ) )
62+ Some ( ModPath :: from_segments ( PathKind :: Super ( 1 ) , None ) )
6563 } else {
6664 None
6765 }
@@ -97,12 +95,25 @@ impl PrefixKind {
9795 self == & PrefixKind :: ByCrate
9896 }
9997}
100-
10198/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
10299fn find_path_inner (
103100 db : & dyn DefDatabase ,
104101 item : ItemInNs ,
105102 from : ModuleId ,
103+ prefixed : Option < PrefixKind > ,
104+ ) -> Option < ModPath > {
105+ // FIXME: Do fast path for std/core libs?
106+
107+ let mut visited_modules = FxHashSet :: default ( ) ;
108+ let def_map = from. def_map ( db) ;
109+ find_path_inner_ ( db, & def_map, from, item, MAX_PATH_LEN , prefixed, & mut visited_modules)
110+ }
111+
112+ fn find_path_inner_ (
113+ db : & dyn DefDatabase ,
114+ def_map : & DefMap ,
115+ from : ModuleId ,
116+ item : ItemInNs ,
106117 max_len : usize ,
107118 mut prefixed : Option < PrefixKind > ,
108119 visited_modules : & mut FxHashSet < ModuleId > ,
@@ -114,19 +125,24 @@ fn find_path_inner(
114125 // Base cases:
115126
116127 // - if the item is already in scope, return the name under which it is
117- let def_map = from. def_map ( db) ;
118128 let scope_name = def_map. with_ancestor_maps ( db, from. local_id , & mut |def_map, local_id| {
119129 def_map[ local_id] . scope . name_of ( item) . map ( |( name, _) | name. clone ( ) )
120130 } ) ;
121- if prefixed. is_none ( ) && scope_name. is_some ( ) {
122- return scope_name
123- . map ( |scope_name| ModPath :: from_segments ( PathKind :: Plain , vec ! [ scope_name] ) ) ;
131+ if prefixed. is_none ( ) {
132+ if let Some ( scope_name) = scope_name {
133+ return Some ( ModPath :: from_segments ( PathKind :: Plain , Some ( scope_name) ) ) ;
134+ }
135+ }
136+
137+ // - if the item is a builtin, it's in scope
138+ if let ItemInNs :: Types ( ModuleDefId :: BuiltinType ( builtin) ) = item {
139+ return Some ( ModPath :: from_segments ( PathKind :: Plain , Some ( builtin. as_name ( ) ) ) ) ;
124140 }
125141
126142 // - if the item is the crate root, return `crate`
127- let root = def_map. crate_root ( db) ;
128- if item == ItemInNs :: Types ( ModuleDefId :: ModuleId ( root ) ) {
129- return Some ( ModPath :: from_segments ( PathKind :: Crate , Vec :: new ( ) ) ) ;
143+ let crate_root = def_map. crate_root ( db) ;
144+ if item == ItemInNs :: Types ( ModuleDefId :: ModuleId ( crate_root ) ) {
145+ return Some ( ModPath :: from_segments ( PathKind :: Crate , None ) ) ;
130146 }
131147
132148 if prefixed. filter ( PrefixKind :: is_absolute) . is_none ( ) {
@@ -136,46 +152,43 @@ fn find_path_inner(
136152 }
137153
138154 // - if the item is the crate root of a dependency crate, return the name from the extern prelude
139- let root_def_map = root. def_map ( db) ;
140- for ( name, def_id) in root_def_map. extern_prelude ( ) {
141- if item == ItemInNs :: Types ( * def_id) {
142- let name = scope_name. unwrap_or_else ( || name. clone ( ) ) ;
143-
144- let name_already_occupied_in_type_ns = def_map
145- . with_ancestor_maps ( db, from. local_id , & mut |def_map, local_id| {
146- def_map[ local_id] . scope . get ( & name) . take_types ( ) . filter ( |& id| id != * def_id)
147- } )
148- . is_some ( ) ;
149- return Some ( ModPath :: from_segments (
150- if name_already_occupied_in_type_ns {
155+ let root_def_map = crate_root. def_map ( db) ;
156+ if let ItemInNs :: Types ( ModuleDefId :: ModuleId ( item) ) = item {
157+ for ( name, & def_id) in root_def_map. extern_prelude ( ) {
158+ if item == def_id {
159+ let name = scope_name. unwrap_or_else ( || name. clone ( ) ) ;
160+
161+ let name_already_occupied_in_type_ns = def_map
162+ . with_ancestor_maps ( db, from. local_id , & mut |def_map, local_id| {
163+ def_map[ local_id]
164+ . scope
165+ . type_ ( & name)
166+ . filter ( |& ( id, _) | id != ModuleDefId :: ModuleId ( def_id) )
167+ } )
168+ . is_some ( ) ;
169+ let kind = if name_already_occupied_in_type_ns {
151170 cov_mark:: hit!( ambiguous_crate_start) ;
152171 PathKind :: Abs
153172 } else {
154173 PathKind :: Plain
155- } ,
156- vec ! [ name ] ,
157- ) ) ;
174+ } ;
175+ return Some ( ModPath :: from_segments ( kind , Some ( name ) ) ) ;
176+ }
158177 }
159178 }
160179
161180 // - if the item is in the prelude, return the name from there
162181 if let Some ( prelude_module) = root_def_map. prelude ( ) {
163182 // Preludes in block DefMaps are ignored, only the crate DefMap is searched
164183 let prelude_def_map = prelude_module. def_map ( db) ;
165- let prelude_scope: & crate :: item_scope:: ItemScope =
166- & prelude_def_map[ prelude_module. local_id ] . scope ;
184+ let prelude_scope = & prelude_def_map[ prelude_module. local_id ] . scope ;
167185 if let Some ( ( name, vis) ) = prelude_scope. name_of ( item) {
168186 if vis. is_visible_from ( db, from) {
169- return Some ( ModPath :: from_segments ( PathKind :: Plain , vec ! [ name. clone( ) ] ) ) ;
187+ return Some ( ModPath :: from_segments ( PathKind :: Plain , Some ( name. clone ( ) ) ) ) ;
170188 }
171189 }
172190 }
173191
174- // - if the item is a builtin, it's in scope
175- if let ItemInNs :: Types ( ModuleDefId :: BuiltinType ( builtin) ) = item {
176- return Some ( ModPath :: from_segments ( PathKind :: Plain , vec ! [ builtin. as_name( ) ] ) ) ;
177- }
178-
179192 // Recursive case:
180193 // - if the item is an enum variant, refer to it via the enum
181194 if let Some ( ModuleDefId :: EnumVariantId ( variant) ) = item. as_module_def_id ( ) {
@@ -190,25 +203,24 @@ fn find_path_inner(
190203 }
191204
192205 // - otherwise, look for modules containing (reexporting) it and import it from one of those
193-
194- let crate_root = def_map. crate_root ( db) ;
195- let crate_attrs = db. attrs ( crate_root. into ( ) ) ;
196- let prefer_no_std = crate_attrs. by_key ( "no_std" ) . exists ( ) ;
206+ let prefer_no_std = db. attrs ( crate_root. into ( ) ) . by_key ( "no_std" ) . exists ( ) ;
197207 let mut best_path = None ;
198208 let mut best_path_len = max_len;
199209
200210 if item. krate ( db) == Some ( from. krate ) {
201211 // Item was defined in the same crate that wants to import it. It cannot be found in any
202212 // dependency in this case.
213+ // FIXME: this should have a fast path that doesn't look through the prelude again?
203214 for ( module_id, name) in find_local_import_locations ( db, item, from) {
204215 if !visited_modules. insert ( module_id) {
205216 cov_mark:: hit!( recursive_imports) ;
206217 continue ;
207218 }
208- if let Some ( mut path) = find_path_inner (
219+ if let Some ( mut path) = find_path_inner_ (
209220 db,
210- ItemInNs :: Types ( ModuleDefId :: ModuleId ( module_id ) ) ,
221+ def_map ,
211222 from,
223+ ItemInNs :: Types ( ModuleDefId :: ModuleId ( module_id) ) ,
212224 best_path_len - 1 ,
213225 prefixed,
214226 visited_modules,
@@ -233,16 +245,18 @@ fn find_path_inner(
233245 let import_map = db. import_map ( dep. crate_id ) ;
234246 import_map. import_info_for ( item) . and_then ( |info| {
235247 // Determine best path for containing module and append last segment from `info`.
236- let mut path = find_path_inner (
248+ // FIXME: we should guide this to look up the path locally, or from the same crate again?
249+ let mut path = find_path_inner_ (
237250 db,
238- ItemInNs :: Types ( ModuleDefId :: ModuleId ( info . container ) ) ,
251+ def_map ,
239252 from,
253+ ItemInNs :: Types ( ModuleDefId :: ModuleId ( info. container ) ) ,
240254 best_path_len - 1 ,
241255 prefixed,
242256 visited_modules,
243257 ) ?;
244258 cov_mark:: hit!( partially_imported) ;
245- path. push_segment ( info. path . segments . last ( ) . unwrap ( ) . clone ( ) ) ;
259+ path. push_segment ( info. path . segments . last ( ) ? . clone ( ) ) ;
246260 Some ( path)
247261 } )
248262 } ) ;
@@ -267,7 +281,7 @@ fn find_path_inner(
267281
268282 match prefixed. map ( PrefixKind :: prefix) {
269283 Some ( prefix) => best_path. or_else ( || {
270- scope_name. map ( |scope_name| ModPath :: from_segments ( prefix, vec ! [ scope_name] ) )
284+ scope_name. map ( |scope_name| ModPath :: from_segments ( prefix, Some ( scope_name) ) )
271285 } ) ,
272286 None => best_path,
273287 }
@@ -370,8 +384,8 @@ fn find_local_import_locations(
370384 }
371385
372386 // Descend into all modules visible from `from`.
373- for ( _ , per_ns ) in data. scope . entries ( ) {
374- if let Some ( ( ModuleDefId :: ModuleId ( module) , vis ) ) = per_ns . take_types_vis ( ) {
387+ for ( ty , vis ) in data. scope . types ( ) {
388+ if let ModuleDefId :: ModuleId ( module) = ty {
375389 if vis. is_visible_from ( db, from) {
376390 worklist. push ( module) ;
377391 }
@@ -415,15 +429,7 @@ mod tests {
415429 . take_types ( )
416430 . unwrap ( ) ;
417431
418- let mut visited_modules = FxHashSet :: default ( ) ;
419- let found_path = find_path_inner (
420- & db,
421- ItemInNs :: Types ( resolved) ,
422- module,
423- MAX_PATH_LEN ,
424- prefix_kind,
425- & mut visited_modules,
426- ) ;
432+ let found_path = find_path_inner ( & db, ItemInNs :: Types ( resolved) , module, prefix_kind) ;
427433 assert_eq ! ( found_path, Some ( mod_path) , "{:?}" , prefix_kind) ;
428434 }
429435
0 commit comments