Skip to content

Commit 2f24e74

Browse files
committed
Implement glob imports within the same crate
Fixes #231.
1 parent 2e1d739 commit 2f24e74

File tree

1 file changed

+77
-16
lines changed

1 file changed

+77
-16
lines changed

crates/ra_hir/src/nameres.rs

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl ModuleScope {
6161

6262
/// `Resolution` is basically `DefId` atm, but it should account for stuff like
6363
/// multiple namespaces, ambiguity and errors.
64-
#[derive(Debug, Clone, PartialEq, Eq)]
64+
#[derive(Debug, Clone, PartialEq, Eq, Default)]
6565
pub struct Resolution {
6666
/// None for unresolved
6767
pub def: PerNs<ModuleDef>,
@@ -154,6 +154,8 @@ struct Resolver<'a, DB> {
154154
krate: Crate,
155155
module_tree: Arc<ModuleTree>,
156156
processed_imports: FxHashSet<(ModuleId, ImportId)>,
157+
/// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import)
158+
glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>,
157159
result: ItemMap,
158160
}
159161

@@ -173,6 +175,7 @@ where
173175
krate,
174176
module_tree,
175177
processed_imports: FxHashSet::default(),
178+
glob_imports: FxHashMap::default(),
176179
result: ItemMap::default(),
177180
}
178181
}
@@ -281,12 +284,28 @@ where
281284
// glob import from other crate => we can just import everything once
282285
let item_map = self.db.item_map(m.krate);
283286
let scope = &item_map[m.module_id];
284-
self.update(module_id, |items| {
285-
// TODO: handle shadowing and visibility
286-
items.items.extend(
287-
scope.items.iter().map(|(name, res)| (name.clone(), res.clone())),
288-
);
289-
});
287+
let items = scope
288+
.items
289+
.iter()
290+
.map(|(name, res)| (name.clone(), res.clone()))
291+
.collect::<Vec<_>>();
292+
self.update(module_id, Some(import_id), &items);
293+
} else {
294+
// glob import from same crate => we do an initial
295+
// import, and then need to propagate any further
296+
// additions
297+
let scope = &self.result[m.module_id];
298+
let items = scope
299+
.items
300+
.iter()
301+
.map(|(name, res)| (name.clone(), res.clone()))
302+
.collect::<Vec<_>>();
303+
self.update(module_id, Some(import_id), &items);
304+
// record the glob import in case we add further items
305+
self.glob_imports
306+
.entry(m.module_id)
307+
.or_default()
308+
.push((module_id, import_id));
290309
}
291310
}
292311
Some(ModuleDef::Enum(e)) => {
@@ -304,9 +323,7 @@ where
304323
Some((name, res))
305324
})
306325
.collect::<Vec<_>>();
307-
self.update(module_id, |items| {
308-
items.items.extend(resolutions);
309-
});
326+
self.update(module_id, Some(import_id), &resolutions);
310327
}
311328
Some(d) => {
312329
log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -328,17 +345,61 @@ where
328345
}
329346
}
330347
}
331-
self.update(module_id, |items| {
332-
let res = Resolution { def, import: Some(import_id) };
333-
items.items.insert(name, res);
334-
});
348+
let resolution = Resolution { def, import: Some(import_id) };
349+
self.update(module_id, None, &[(name, resolution)]);
335350
}
336351
reached_fixedpoint
337352
}
338353

339-
fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
354+
fn update(
355+
&mut self,
356+
module_id: ModuleId,
357+
import: Option<ImportId>,
358+
resolutions: &[(Name, Resolution)],
359+
) {
360+
self.update_recursive(module_id, import, resolutions, 0)
361+
}
362+
363+
fn update_recursive(
364+
&mut self,
365+
module_id: ModuleId,
366+
import: Option<ImportId>,
367+
resolutions: &[(Name, Resolution)],
368+
depth: usize,
369+
) {
370+
if depth > 100 {
371+
// prevent stack overflows (but this shouldn't be possible)
372+
panic!("infinite recursion in glob imports!");
373+
}
340374
let module_items = self.result.per_module.get_mut(module_id).unwrap();
341-
f(module_items)
375+
let mut changed = false;
376+
for (name, res) in resolutions {
377+
let existing = module_items.items.entry(name.clone()).or_default();
378+
if existing.def.types.is_none() && res.def.types.is_some() {
379+
existing.def.types = res.def.types;
380+
existing.import = import.or(res.import);
381+
changed = true;
382+
}
383+
if existing.def.values.is_none() && res.def.values.is_some() {
384+
existing.def.values = res.def.values;
385+
existing.import = import.or(res.import);
386+
changed = true;
387+
}
388+
}
389+
if !changed {
390+
return;
391+
}
392+
let glob_imports = self
393+
.glob_imports
394+
.get(&module_id)
395+
.into_iter()
396+
.flat_map(|v| v.iter())
397+
.cloned()
398+
.collect::<Vec<_>>();
399+
for (glob_importing_module, glob_import) in glob_imports {
400+
// We pass the glob import so that the tracked import in those modules is that glob import
401+
self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
402+
}
342403
}
343404
}
344405

0 commit comments

Comments
 (0)