@@ -18,8 +18,7 @@ use crate::{
18
18
/// *from where* you're referring to the item, hence the `from` parameter.
19
19
pub fn find_path ( db : & dyn DefDatabase , item : ItemInNs , from : ModuleId ) -> Option < ModPath > {
20
20
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 )
23
22
}
24
23
25
24
pub fn find_path_prefixed (
@@ -29,8 +28,7 @@ pub fn find_path_prefixed(
29
28
prefix_kind : PrefixKind ,
30
29
) -> Option < ModPath > {
31
30
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) )
34
32
}
35
33
36
34
const MAX_PATH_LEN : usize = 15 ;
@@ -56,12 +54,12 @@ impl ModPathExt for ModPath {
56
54
fn check_self_super ( def_map : & DefMap , item : ItemInNs , from : ModuleId ) -> Option < ModPath > {
57
55
if item == ItemInNs :: Types ( from. into ( ) ) {
58
56
// - 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 ) )
60
58
} else if let Some ( parent_id) = def_map[ from. local_id ] . parent {
61
59
// - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
62
60
let parent_id = def_map. module_id ( parent_id) ;
63
61
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 ) )
65
63
} else {
66
64
None
67
65
}
@@ -97,12 +95,25 @@ impl PrefixKind {
97
95
self == & PrefixKind :: ByCrate
98
96
}
99
97
}
100
-
101
98
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
102
99
fn find_path_inner (
103
100
db : & dyn DefDatabase ,
104
101
item : ItemInNs ,
105
102
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 ,
106
117
max_len : usize ,
107
118
mut prefixed : Option < PrefixKind > ,
108
119
visited_modules : & mut FxHashSet < ModuleId > ,
@@ -114,19 +125,24 @@ fn find_path_inner(
114
125
// Base cases:
115
126
116
127
// - if the item is already in scope, return the name under which it is
117
- let def_map = from. def_map ( db) ;
118
128
let scope_name = def_map. with_ancestor_maps ( db, from. local_id , & mut |def_map, local_id| {
119
129
def_map[ local_id] . scope . name_of ( item) . map ( |( name, _) | name. clone ( ) )
120
130
} ) ;
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 ( ) ) ) ) ;
124
140
}
125
141
126
142
// - 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 ) ) ;
130
146
}
131
147
132
148
if prefixed. filter ( PrefixKind :: is_absolute) . is_none ( ) {
@@ -136,46 +152,43 @@ fn find_path_inner(
136
152
}
137
153
138
154
// - 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 {
151
170
cov_mark:: hit!( ambiguous_crate_start) ;
152
171
PathKind :: Abs
153
172
} else {
154
173
PathKind :: Plain
155
- } ,
156
- vec ! [ name ] ,
157
- ) ) ;
174
+ } ;
175
+ return Some ( ModPath :: from_segments ( kind , Some ( name ) ) ) ;
176
+ }
158
177
}
159
178
}
160
179
161
180
// - if the item is in the prelude, return the name from there
162
181
if let Some ( prelude_module) = root_def_map. prelude ( ) {
163
182
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
164
183
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 ;
167
185
if let Some ( ( name, vis) ) = prelude_scope. name_of ( item) {
168
186
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 ( ) ) ) ) ;
170
188
}
171
189
}
172
190
}
173
191
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
-
179
192
// Recursive case:
180
193
// - if the item is an enum variant, refer to it via the enum
181
194
if let Some ( ModuleDefId :: EnumVariantId ( variant) ) = item. as_module_def_id ( ) {
@@ -190,25 +203,24 @@ fn find_path_inner(
190
203
}
191
204
192
205
// - 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 ( ) ;
197
207
let mut best_path = None ;
198
208
let mut best_path_len = max_len;
199
209
200
210
if item. krate ( db) == Some ( from. krate ) {
201
211
// Item was defined in the same crate that wants to import it. It cannot be found in any
202
212
// dependency in this case.
213
+ // FIXME: this should have a fast path that doesn't look through the prelude again?
203
214
for ( module_id, name) in find_local_import_locations ( db, item, from) {
204
215
if !visited_modules. insert ( module_id) {
205
216
cov_mark:: hit!( recursive_imports) ;
206
217
continue ;
207
218
}
208
- if let Some ( mut path) = find_path_inner (
219
+ if let Some ( mut path) = find_path_inner_ (
209
220
db,
210
- ItemInNs :: Types ( ModuleDefId :: ModuleId ( module_id ) ) ,
221
+ def_map ,
211
222
from,
223
+ ItemInNs :: Types ( ModuleDefId :: ModuleId ( module_id) ) ,
212
224
best_path_len - 1 ,
213
225
prefixed,
214
226
visited_modules,
@@ -233,16 +245,18 @@ fn find_path_inner(
233
245
let import_map = db. import_map ( dep. crate_id ) ;
234
246
import_map. import_info_for ( item) . and_then ( |info| {
235
247
// 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_ (
237
250
db,
238
- ItemInNs :: Types ( ModuleDefId :: ModuleId ( info . container ) ) ,
251
+ def_map ,
239
252
from,
253
+ ItemInNs :: Types ( ModuleDefId :: ModuleId ( info. container ) ) ,
240
254
best_path_len - 1 ,
241
255
prefixed,
242
256
visited_modules,
243
257
) ?;
244
258
cov_mark:: hit!( partially_imported) ;
245
- path. push_segment ( info. path . segments . last ( ) . unwrap ( ) . clone ( ) ) ;
259
+ path. push_segment ( info. path . segments . last ( ) ? . clone ( ) ) ;
246
260
Some ( path)
247
261
} )
248
262
} ) ;
@@ -267,7 +281,7 @@ fn find_path_inner(
267
281
268
282
match prefixed. map ( PrefixKind :: prefix) {
269
283
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) ) )
271
285
} ) ,
272
286
None => best_path,
273
287
}
@@ -370,8 +384,8 @@ fn find_local_import_locations(
370
384
}
371
385
372
386
// 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 {
375
389
if vis. is_visible_from ( db, from) {
376
390
worklist. push ( module) ;
377
391
}
@@ -415,15 +429,7 @@ mod tests {
415
429
. take_types ( )
416
430
. unwrap ( ) ;
417
431
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) ;
427
433
assert_eq ! ( found_path, Some ( mod_path) , "{:?}" , prefix_kind) ;
428
434
}
429
435
0 commit comments