aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-02-10 15:19:50 +0000
committerFlorian Diebold <[email protected]>2019-02-10 15:48:29 +0000
commit2f24e740db3365afac56aad3e8a533340369ef7d (patch)
tree18084cb38cb0fe1faa621c3209a9f3f411faf5f8 /crates/ra_hir
parent2e1d739a8063307facf9ff098c26b02005092e05 (diff)
Implement glob imports within the same crate
Fixes #231.
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/nameres.rs93
1 files changed, 77 insertions, 16 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 2442e754e..94f7db024 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -61,7 +61,7 @@ impl ModuleScope {
61 61
62/// `Resolution` is basically `DefId` atm, but it should account for stuff like 62/// `Resolution` is basically `DefId` atm, but it should account for stuff like
63/// multiple namespaces, ambiguity and errors. 63/// multiple namespaces, ambiguity and errors.
64#[derive(Debug, Clone, PartialEq, Eq)] 64#[derive(Debug, Clone, PartialEq, Eq, Default)]
65pub struct Resolution { 65pub struct Resolution {
66 /// None for unresolved 66 /// None for unresolved
67 pub def: PerNs<ModuleDef>, 67 pub def: PerNs<ModuleDef>,
@@ -154,6 +154,8 @@ struct Resolver<'a, DB> {
154 krate: Crate, 154 krate: Crate,
155 module_tree: Arc<ModuleTree>, 155 module_tree: Arc<ModuleTree>,
156 processed_imports: FxHashSet<(ModuleId, ImportId)>, 156 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)>>,
157 result: ItemMap, 159 result: ItemMap,
158} 160}
159 161
@@ -173,6 +175,7 @@ where
173 krate, 175 krate,
174 module_tree, 176 module_tree,
175 processed_imports: FxHashSet::default(), 177 processed_imports: FxHashSet::default(),
178 glob_imports: FxHashMap::default(),
176 result: ItemMap::default(), 179 result: ItemMap::default(),
177 } 180 }
178 } 181 }
@@ -281,12 +284,28 @@ where
281 // glob import from other crate => we can just import everything once 284 // glob import from other crate => we can just import everything once
282 let item_map = self.db.item_map(m.krate); 285 let item_map = self.db.item_map(m.krate);
283 let scope = &item_map[m.module_id]; 286 let scope = &item_map[m.module_id];
284 self.update(module_id, |items| { 287 let items = scope
285 // TODO: handle shadowing and visibility 288 .items
286 items.items.extend( 289 .iter()
287 scope.items.iter().map(|(name, res)| (name.clone(), res.clone())), 290 .map(|(name, res)| (name.clone(), res.clone()))
288 ); 291 .collect::<Vec<_>>();
289 }); 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));
290 } 309 }
291 } 310 }
292 Some(ModuleDef::Enum(e)) => { 311 Some(ModuleDef::Enum(e)) => {
@@ -304,9 +323,7 @@ where
304 Some((name, res)) 323 Some((name, res))
305 }) 324 })
306 .collect::<Vec<_>>(); 325 .collect::<Vec<_>>();
307 self.update(module_id, |items| { 326 self.update(module_id, Some(import_id), &resolutions);
308 items.items.extend(resolutions);
309 });
310 } 327 }
311 Some(d) => { 328 Some(d) => {
312 log::debug!("glob import {:?} from non-module/enum {:?}", import, d); 329 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -328,17 +345,61 @@ where
328 } 345 }
329 } 346 }
330 } 347 }
331 self.update(module_id, |items| { 348 let resolution = Resolution { def, import: Some(import_id) };
332 let res = Resolution { def, import: Some(import_id) }; 349 self.update(module_id, None, &[(name, resolution)]);
333 items.items.insert(name, res);
334 });
335 } 350 }
336 reached_fixedpoint 351 reached_fixedpoint
337 } 352 }
338 353
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 }
340 let module_items = self.result.per_module.get_mut(module_id).unwrap(); 374 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 }
342 } 403 }
343} 404}
344 405