diff options
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 90 |
1 files changed, 60 insertions, 30 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 04cc693b3..68df083d8 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -34,6 +34,7 @@ use crate::{ | |||
34 | /// module, the set of visible items. | 34 | /// module, the set of visible items. |
35 | #[derive(Default, Debug, PartialEq, Eq)] | 35 | #[derive(Default, Debug, PartialEq, Eq)] |
36 | pub struct ItemMap { | 36 | pub struct ItemMap { |
37 | extern_prelude: FxHashMap<Name, ModuleDef>, | ||
37 | per_module: ArenaMap<ModuleId, ModuleScope>, | 38 | per_module: ArenaMap<ModuleId, ModuleScope>, |
38 | } | 39 | } |
39 | 40 | ||
@@ -204,6 +205,7 @@ where | |||
204 | } | 205 | } |
205 | 206 | ||
206 | pub(crate) fn resolve(mut self) -> ItemMap { | 207 | pub(crate) fn resolve(mut self) -> ItemMap { |
208 | self.populate_extern_prelude(); | ||
207 | for (&module_id, items) in self.input.iter() { | 209 | for (&module_id, items) in self.input.iter() { |
208 | self.populate_module(module_id, Arc::clone(items)); | 210 | self.populate_module(module_id, Arc::clone(items)); |
209 | } | 211 | } |
@@ -227,29 +229,19 @@ where | |||
227 | self.result | 229 | self.result |
228 | } | 230 | } |
229 | 231 | ||
232 | fn populate_extern_prelude(&mut self) { | ||
233 | for dep in self.krate.dependencies(self.db) { | ||
234 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate); | ||
235 | if let Some(module) = dep.krate.root_module(self.db) { | ||
236 | self.result | ||
237 | .extern_prelude | ||
238 | .insert(dep.name.clone(), module.into()); | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | |||
230 | fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) { | 243 | fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) { |
231 | let mut module_items = ModuleScope::default(); | 244 | let mut module_items = ModuleScope::default(); |
232 | |||
233 | // Populate extern crates prelude | ||
234 | { | ||
235 | let root_id = module_id.crate_root(&self.module_tree); | ||
236 | let file_id = root_id.file_id(&self.module_tree); | ||
237 | let crate_graph = self.db.crate_graph(); | ||
238 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) | ||
239 | { | ||
240 | let krate = Crate { crate_id }; | ||
241 | for dep in krate.dependencies(self.db) { | ||
242 | if let Some(module) = dep.krate.root_module(self.db) { | ||
243 | let def = module.into(); | ||
244 | self.add_module_item( | ||
245 | &mut module_items, | ||
246 | dep.name.clone(), | ||
247 | PerNs::types(def), | ||
248 | ); | ||
249 | } | ||
250 | } | ||
251 | }; | ||
252 | } | ||
253 | for (import_id, import_data) in input.imports.iter() { | 245 | for (import_id, import_data) in input.imports.iter() { |
254 | if let Some(last_segment) = import_data.path.segments.iter().last() { | 246 | if let Some(last_segment) = import_data.path.segments.iter().last() { |
255 | if !import_data.is_glob { | 247 | if !import_data.is_glob { |
@@ -327,7 +319,16 @@ where | |||
327 | .alias | 319 | .alias |
328 | .clone() | 320 | .clone() |
329 | .unwrap_or_else(|| last_segment.name.clone()); | 321 | .unwrap_or_else(|| last_segment.name.clone()); |
330 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def,); | 322 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); |
323 | |||
324 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | ||
325 | if let Some(root_module) = self.krate.root_module(self.db) { | ||
326 | if import.is_extern_crate && module_id == root_module.module_id { | ||
327 | if let Some(def) = def.take_types() { | ||
328 | self.result.extern_prelude.insert(name.clone(), def); | ||
329 | } | ||
330 | } | ||
331 | } | ||
331 | self.update(module_id, |items| { | 332 | self.update(module_id, |items| { |
332 | let res = Resolution { | 333 | let res = Resolution { |
333 | def, | 334 | def, |
@@ -389,24 +390,53 @@ impl ItemMap { | |||
389 | original_module: Module, | 390 | original_module: Module, |
390 | path: &Path, | 391 | path: &Path, |
391 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { | 392 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { |
392 | let mut curr_per_ns: PerNs<ModuleDef> = PerNs::types(match path.kind { | 393 | let mut segments = path.segments.iter().enumerate(); |
393 | PathKind::Crate => original_module.crate_root(db).into(), | 394 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { |
394 | PathKind::Self_ | PathKind::Plain => original_module.into(), | 395 | PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), |
396 | PathKind::Self_ => PerNs::types(original_module.into()), | ||
397 | PathKind::Plain => { | ||
398 | let segment = match segments.next() { | ||
399 | Some((_, segment)) => segment, | ||
400 | None => return (PerNs::none(), ReachedFixedPoint::Yes), | ||
401 | }; | ||
402 | // Resolve in: | ||
403 | // - current module / scope | ||
404 | // - extern prelude | ||
405 | match self[original_module.module_id].items.get(&segment.name) { | ||
406 | Some(res) if !res.def.is_none() => res.def, | ||
407 | _ => { | ||
408 | if let Some(def) = self.extern_prelude.get(&segment.name) { | ||
409 | PerNs::types(*def) | ||
410 | } else { | ||
411 | return (PerNs::none(), ReachedFixedPoint::No); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | } | ||
395 | PathKind::Super => { | 416 | PathKind::Super => { |
396 | if let Some(p) = original_module.parent(db) { | 417 | if let Some(p) = original_module.parent(db) { |
397 | p.into() | 418 | PerNs::types(p.into()) |
398 | } else { | 419 | } else { |
399 | log::debug!("super path in root module"); | 420 | log::debug!("super path in root module"); |
400 | return (PerNs::none(), ReachedFixedPoint::Yes); | 421 | return (PerNs::none(), ReachedFixedPoint::Yes); |
401 | } | 422 | } |
402 | } | 423 | } |
403 | PathKind::Abs => { | 424 | PathKind::Abs => { |
404 | // TODO: absolute use is not supported | 425 | // 2018-style absolute path -- only extern prelude |
405 | return (PerNs::none(), ReachedFixedPoint::Yes); | 426 | let segment = match segments.next() { |
427 | Some((_, segment)) => segment, | ||
428 | None => return (PerNs::none(), ReachedFixedPoint::Yes), | ||
429 | }; | ||
430 | if let Some(def) = self.extern_prelude.get(&segment.name) { | ||
431 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | ||
432 | PerNs::types(*def) | ||
433 | } else { | ||
434 | return (PerNs::none(), ReachedFixedPoint::Yes); | ||
435 | } | ||
406 | } | 436 | } |
407 | }); | 437 | }; |
408 | 438 | ||
409 | for (i, segment) in path.segments.iter().enumerate() { | 439 | for (i, segment) in segments { |
410 | let curr = match curr_per_ns.as_ref().take_types() { | 440 | let curr = match curr_per_ns.as_ref().take_types() { |
411 | Some(r) => r, | 441 | Some(r) => r, |
412 | None => { | 442 | None => { |