Skip to content

Commit 800ae51

Browse files
bors[bot]Veykril
andauthored
Merge #11788
11788: internal: Improve `find_path` and extern prelude handling r=Veykril a=Veykril Co-authored-by: Lukas Wirth <[email protected]>
2 parents 98d1724 + cb1b7e1 commit 800ae51

File tree

6 files changed

+103
-93
lines changed

6 files changed

+103
-93
lines changed

crates/hir_def/src/find_path.rs

Lines changed: 64 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ use crate::{
1818
/// *from where* you're referring to the item, hence the `from` parameter.
1919
pub 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

2524
pub 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

3634
const MAX_PATH_LEN: usize = 15;
@@ -56,12 +54,12 @@ impl ModPathExt for ModPath {
5654
fn 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
10299
fn 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

crates/hir_def/src/item_scope.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ impl ItemScope {
119119
self.values.values().copied()
120120
}
121121

122+
pub fn types(
123+
&self,
124+
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
125+
self.types.values().copied()
126+
}
127+
122128
pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
123129
self.unnamed_consts.iter().copied()
124130
}
@@ -142,6 +148,10 @@ impl ItemScope {
142148
}
143149
}
144150

151+
pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
152+
self.types.get(name).copied()
153+
}
154+
145155
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
146156
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
147157
let (def, mut iter) = match item {

crates/hir_def/src/nameres.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ use crate::{
7575
path::ModPath,
7676
per_ns::PerNs,
7777
visibility::Visibility,
78-
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, ModuleDefId, ModuleId, ProcMacroId,
78+
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, ModuleId, ProcMacroId,
7979
};
8080

8181
/// Contains the results of (early) name resolution.
@@ -98,7 +98,7 @@ pub struct DefMap {
9898
/// marked with the `prelude_import` attribute, or (in the normal case) from
9999
/// a dependency (`std` or `core`).
100100
prelude: Option<ModuleId>,
101-
extern_prelude: FxHashMap<Name, ModuleDefId>,
101+
extern_prelude: FxHashMap<Name, ModuleId>,
102102

103103
/// Side table for resolving derive helpers.
104104
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
@@ -318,7 +318,7 @@ impl DefMap {
318318
self.prelude
319319
}
320320

321-
pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleDefId)> + '_ {
321+
pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleId)> + '_ {
322322
self.extern_prelude.iter()
323323
}
324324

crates/hir_def/src/nameres/collector.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
7070
deps.insert(dep.as_name(), dep_root.into());
7171

7272
if dep.is_prelude() && !tree_id.is_block() {
73-
def_map.extern_prelude.insert(dep.as_name(), dep_root.into());
73+
def_map.extern_prelude.insert(dep.as_name(), dep_root);
7474
}
7575
}
7676

@@ -234,7 +234,7 @@ enum MacroDirectiveKind {
234234
struct DefCollector<'a> {
235235
db: &'a dyn DefDatabase,
236236
def_map: DefMap,
237-
deps: FxHashMap<Name, ModuleDefId>,
237+
deps: FxHashMap<Name, ModuleId>,
238238
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
239239
unresolved_imports: Vec<ImportDirective>,
240240
resolved_imports: Vec<ImportDirective>,
@@ -687,9 +687,7 @@ impl DefCollector<'_> {
687687
self.def_map.edition,
688688
);
689689

690-
let res = self.resolve_extern_crate(&extern_crate.name);
691-
692-
if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
690+
if let Some(m) = self.resolve_extern_crate(&extern_crate.name) {
693691
if m == self.def_map.module_id(current_module_id) {
694692
cov_mark::hit!(ignore_macro_use_extern_crate_self);
695693
return;
@@ -757,10 +755,11 @@ impl DefCollector<'_> {
757755

758756
let res = self.resolve_extern_crate(name);
759757

760-
if res.is_none() {
761-
PartialResolvedImport::Unresolved
762-
} else {
763-
PartialResolvedImport::Resolved(res)
758+
match res {
759+
Some(res) => {
760+
PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public))
761+
}
762+
None => PartialResolvedImport::Unresolved,
764763
}
765764
} else {
766765
let res = self.def_map.resolve_path_fp_with_macro(
@@ -796,7 +795,7 @@ impl DefCollector<'_> {
796795
}
797796
}
798797

799-
fn resolve_extern_crate(&self, name: &Name) -> PerNs {
798+
fn resolve_extern_crate(&self, name: &Name) -> Option<ModuleId> {
800799
if *name == name!(self) {
801800
cov_mark::hit!(extern_crate_self_as);
802801
let root = match self.def_map.block {
@@ -806,9 +805,9 @@ impl DefCollector<'_> {
806805
}
807806
None => self.def_map.module_id(self.def_map.root()),
808807
};
809-
PerNs::types(root.into(), Visibility::Public)
808+
Some(root)
810809
} else {
811-
self.deps.get(name).map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
810+
self.deps.get(name).copied()
812811
}
813812
}
814813

@@ -846,7 +845,8 @@ impl DefCollector<'_> {
846845

847846
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
848847
if import.is_extern_crate && module_id == self.def_map.root {
849-
if let (Some(def), Some(name)) = (def.take_types(), name) {
848+
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
849+
{
850850
self.def_map.extern_prelude.insert(name.clone(), def);
851851
}
852852
}

0 commit comments

Comments
 (0)