Skip to content

Commit 6663a5a

Browse files
committed
Refactor resolve_imports logic
1 parent e5997e1 commit 6663a5a

File tree

2 files changed

+129
-40
lines changed

2 files changed

+129
-40
lines changed

crates/ra_hir_def/src/nameres/collector.rs

Lines changed: 120 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
5858
def_map,
5959
glob_imports: FxHashMap::default(),
6060
unresolved_imports: Vec::new(),
61+
resolved_imports: Vec::new(),
62+
6163
unexpanded_macros: Vec::new(),
6264
unexpanded_attribute_macros: Vec::new(),
6365
mod_dirs: FxHashMap::default(),
@@ -97,12 +99,41 @@ impl MacroStackMonitor {
9799
}
98100
}
99101

102+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
103+
enum PartialResolvedImport {
104+
/// None of any namespaces is resolved
105+
Unresolved,
106+
/// One of namespaces is resolved
107+
Indeterminate(PerNs),
108+
/// All namespaces are resolved, OR it is came from other crate
109+
Resolved(PerNs),
110+
}
111+
112+
impl PartialResolvedImport {
113+
fn namespaces(&self) -> PerNs {
114+
match self {
115+
PartialResolvedImport::Unresolved => PerNs::none(),
116+
PartialResolvedImport::Indeterminate(ns) => *ns,
117+
PartialResolvedImport::Resolved(ns) => *ns,
118+
}
119+
}
120+
}
121+
122+
#[derive(Clone, Debug, Eq, PartialEq)]
123+
struct ImportDirective {
124+
module_id: LocalModuleId,
125+
import_id: LocalImportId,
126+
import: raw::ImportData,
127+
status: PartialResolvedImport,
128+
}
129+
100130
/// Walks the tree of module recursively
101131
struct DefCollector<'a, DB> {
102132
db: &'a DB,
103133
def_map: CrateDefMap,
104134
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>,
105-
unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>,
135+
unresolved_imports: Vec<ImportDirective>,
136+
resolved_imports: Vec<ImportDirective>,
106137
unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>,
107138
unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, Path)>,
108139
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
@@ -148,20 +179,38 @@ where
148179
let mut i = 0;
149180
loop {
150181
self.db.check_canceled();
151-
match (self.resolve_imports(), self.resolve_macros()) {
152-
(ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break,
153-
_ => i += 1,
182+
self.resolve_imports();
183+
184+
match self.resolve_macros() {
185+
ReachedFixedPoint::Yes => break,
186+
ReachedFixedPoint::No => i += 1,
154187
}
155188
if i == 1000 {
156189
log::error!("name resolution is stuck");
157190
break;
158191
}
159192
}
160193

194+
// Resolve all indeterminate resolved imports again
195+
// As some of the macros will expand newly import shadowing partial resolved imports
196+
// FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports`
197+
// correctly
198+
let partial_resolved = self.resolved_imports.iter().filter_map(|directive| {
199+
if let PartialResolvedImport::Indeterminate(_) = directive.status {
200+
let mut directive = directive.clone();
201+
directive.status = PartialResolvedImport::Unresolved;
202+
Some(directive)
203+
} else {
204+
None
205+
}
206+
});
207+
self.unresolved_imports.extend(partial_resolved);
208+
self.resolve_imports();
209+
161210
let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
162211
// show unresolved imports in completion, etc
163-
for (module_id, import, import_data) in unresolved_imports {
164-
self.record_resolved_import(module_id, PerNs::none(), import, &import_data)
212+
for directive in unresolved_imports {
213+
self.record_resolved_import(&directive)
165214
}
166215
}
167216

@@ -262,31 +311,43 @@ where
262311
}
263312
}
264313

265-
fn resolve_imports(&mut self) -> ReachedFixedPoint {
266-
let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
267-
let mut resolved = Vec::new();
268-
imports.retain(|(module_id, import, import_data)| {
269-
let (def, fp) = self.resolve_import(*module_id, import_data);
270-
if fp == ReachedFixedPoint::Yes {
271-
resolved.push((*module_id, def, *import, import_data.clone()))
314+
/// Import resolution
315+
///
316+
/// This is a fix point algorithm. We resolve imports until no forward
317+
/// progress in resolving imports is made
318+
fn resolve_imports(&mut self) {
319+
let mut n_previous_unresolved = self.unresolved_imports.len() + 1;
320+
321+
while self.unresolved_imports.len() < n_previous_unresolved {
322+
n_previous_unresolved = self.unresolved_imports.len();
323+
let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
324+
for mut directive in imports {
325+
directive.status = self.resolve_import(directive.module_id, &directive.import);
326+
327+
match directive.status {
328+
PartialResolvedImport::Indeterminate(_) => {
329+
self.record_resolved_import(&directive);
330+
// FIXME: For avoid performance regression,
331+
// we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
332+
self.resolved_imports.push(directive)
333+
}
334+
PartialResolvedImport::Resolved(_) => {
335+
self.record_resolved_import(&directive);
336+
self.resolved_imports.push(directive)
337+
}
338+
PartialResolvedImport::Unresolved => {
339+
self.unresolved_imports.push(directive);
340+
}
341+
}
272342
}
273-
fp == ReachedFixedPoint::No
274-
});
275-
self.unresolved_imports = imports;
276-
// Resolves imports, filling-in module scopes
277-
let result =
278-
if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
279-
for (module_id, def, import, import_data) in resolved {
280-
self.record_resolved_import(module_id, def, import, &import_data)
281343
}
282-
result
283344
}
284345

285346
fn resolve_import(
286347
&self,
287348
module_id: LocalModuleId,
288349
import: &raw::ImportData,
289-
) -> (PerNs, ReachedFixedPoint) {
350+
) -> PartialResolvedImport {
290351
log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
291352
if import.is_extern_crate {
292353
let res = self.def_map.resolve_name_in_extern_prelude(
@@ -295,7 +356,7 @@ where
295356
.as_ident()
296357
.expect("extern crate should have been desugared to one-element path"),
297358
);
298-
(res, ReachedFixedPoint::Yes)
359+
PartialResolvedImport::Resolved(res)
299360
} else {
300361
let res = self.def_map.resolve_path_fp_with_macro(
301362
self.db,
@@ -305,17 +366,35 @@ where
305366
BuiltinShadowMode::Module,
306367
);
307368

308-
(res.resolved_def, res.reached_fixedpoint)
369+
let def = res.resolved_def;
370+
if res.reached_fixedpoint == ReachedFixedPoint::No {
371+
return PartialResolvedImport::Unresolved;
372+
}
373+
374+
if let Some(krate) = res.krate {
375+
if krate != self.def_map.krate {
376+
return PartialResolvedImport::Resolved(def);
377+
}
378+
}
379+
380+
// Check whether all namespace is resolved
381+
if def.take_types().is_some()
382+
&& def.take_values().is_some()
383+
&& def.take_macros().is_some()
384+
{
385+
return PartialResolvedImport::Resolved(def);
386+
}
387+
388+
PartialResolvedImport::Indeterminate(def)
309389
}
310390
}
311391

312-
fn record_resolved_import(
313-
&mut self,
314-
module_id: LocalModuleId,
315-
def: PerNs,
316-
import_id: LocalImportId,
317-
import: &raw::ImportData,
318-
) {
392+
fn record_resolved_import(&mut self, directive: &ImportDirective) {
393+
let module_id = directive.module_id;
394+
let import_id = directive.import_id;
395+
let import = &directive.import;
396+
let def = directive.status.namespaces();
397+
319398
if import.is_glob {
320399
log::debug!("glob import: {:?}", import);
321400
match def.take_types() {
@@ -615,10 +694,14 @@ where
615694
raw::RawItemKind::Module(m) => {
616695
self.collect_module(&self.raw_items[m], &item.attrs)
617696
}
618-
raw::RawItemKind::Import(import_id) => self
619-
.def_collector
620-
.unresolved_imports
621-
.push((self.module_id, import_id, self.raw_items[import_id].clone())),
697+
raw::RawItemKind::Import(import_id) => {
698+
self.def_collector.unresolved_imports.push(ImportDirective {
699+
module_id: self.module_id,
700+
import_id,
701+
import: self.raw_items[import_id].clone(),
702+
status: PartialResolvedImport::Unresolved,
703+
})
704+
}
622705
raw::RawItemKind::Def(def) => {
623706
self.define_def(&self.raw_items[def], &item.attrs)
624707
}
@@ -886,6 +969,7 @@ mod tests {
886969
def_map,
887970
glob_imports: FxHashMap::default(),
888971
unresolved_imports: Vec::new(),
972+
resolved_imports: Vec::new(),
889973
unexpanded_macros: Vec::new(),
890974
unexpanded_attribute_macros: Vec::new(),
891975
mod_dirs: FxHashMap::default(),

crates/ra_hir_def/src/nameres/path_resolution.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
nameres::{BuiltinShadowMode, CrateDefMap},
2020
path::{Path, PathKind},
2121
per_ns::PerNs,
22-
AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
22+
AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
2323
};
2424

2525
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -39,19 +39,21 @@ pub(super) struct ResolvePathResult {
3939
pub(super) resolved_def: PerNs,
4040
pub(super) segment_index: Option<usize>,
4141
pub(super) reached_fixedpoint: ReachedFixedPoint,
42+
pub(super) krate: Option<CrateId>,
4243
}
4344

4445
impl ResolvePathResult {
4546
fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
46-
ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
47+
ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
4748
}
4849

4950
fn with(
5051
resolved_def: PerNs,
5152
reached_fixedpoint: ReachedFixedPoint,
5253
segment_index: Option<usize>,
54+
krate: Option<CrateId>,
5355
) -> ResolvePathResult {
54-
ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
56+
ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate }
5557
}
5658
}
5759

@@ -175,6 +177,7 @@ impl CrateDefMap {
175177
def,
176178
ReachedFixedPoint::Yes,
177179
s.map(|s| s + i),
180+
Some(module.krate),
178181
);
179182
}
180183

@@ -201,6 +204,7 @@ impl CrateDefMap {
201204
PerNs::types(e.into()),
202205
ReachedFixedPoint::Yes,
203206
Some(i),
207+
Some(self.krate),
204208
);
205209
}
206210
}
@@ -218,12 +222,13 @@ impl CrateDefMap {
218222
PerNs::types(s),
219223
ReachedFixedPoint::Yes,
220224
Some(i),
225+
Some(self.krate),
221226
);
222227
}
223228
};
224229
}
225230

226-
ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
231+
ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
227232
}
228233

229234
fn resolve_name_in_module(

0 commit comments

Comments
 (0)