aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-05 07:53:08 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-05 07:53:08 +0000
commit4d4c46aff8f9a7ce8c2f91fbe6c7c363f5d3e08c (patch)
tree90473c4a67ac70ee40fde54a25b11d7768c41593 /crates/ra_hir/src
parent94d5d0d7e893a50bdd22ce4366ca15f083218d22 (diff)
parentde4c5e381fb1adc25143dcd67af6c87f6d9789ae (diff)
Merge #742
742: Extern crate r=matklad a=flodiebold This implements `extern crate` declarations by lowering them to (absolute) imports, and adds support for absolute paths. It also extracts the extern prelude from the per-module item map, and handles the special case of extern crates in the crate root adding to the extern prelude. This means we finally resolve `Arc`, so it fixes #523 :smile: Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model_api.rs2
-rw-r--r--crates/ra_hir/src/nameres.rs90
-rw-r--r--crates/ra_hir/src/nameres/lower.rs22
-rw-r--r--crates/ra_hir/src/nameres/tests.rs48
-rw-r--r--crates/ra_hir/src/resolve.rs5
5 files changed, 127 insertions, 40 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 92ab0f692..a58bf8f87 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -134,7 +134,7 @@ impl Module {
134 } 134 }
135 135
136 /// Returns the crate this module is part of. 136 /// Returns the crate this module is part of.
137 pub fn krate(&self, _db: &impl HirDatabase) -> Option<Crate> { 137 pub fn krate(&self, _db: &impl PersistentHirDatabase) -> Option<Crate> {
138 Some(self.krate) 138 Some(self.krate)
139 } 139 }
140 140
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 04cc693b3..681aa9a67 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)]
36pub struct ItemMap { 36pub struct ItemMap {
37 pub(crate) 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::No); // extern crate declarations can add to the extern prelude
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 => {
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index df87f520f..7e6e48ae0 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -8,7 +8,7 @@ use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9 9
10use crate::{ 10use crate::{
11 SourceItemId, Path, ModuleSource, Name, 11 SourceItemId, Path, PathKind, ModuleSource, Name,
12 HirFileId, MacroCallLoc, AsName, PerNs, Function, 12 HirFileId, MacroCallLoc, AsName, PerNs, Function,
13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type, 13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
14 ids::LocationCtx, PersistentHirDatabase, 14 ids::LocationCtx, PersistentHirDatabase,
@@ -23,6 +23,7 @@ pub(super) struct ImportData {
23 pub(super) path: Path, 23 pub(super) path: Path,
24 pub(super) alias: Option<Name>, 24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool, 25 pub(super) is_glob: bool,
26 pub(super) is_extern_crate: bool,
26} 27}
27 28
28/// A set of items and imports declared inside a module, without relation to 29/// A set of items and imports declared inside a module, without relation to
@@ -186,8 +187,22 @@ impl LoweredModule {
186 ast::ModuleItemKind::UseItem(it) => { 187 ast::ModuleItemKind::UseItem(it) => {
187 self.add_use_item(source_map, it); 188 self.add_use_item(source_map, it);
188 } 189 }
189 ast::ModuleItemKind::ExternCrateItem(_) => { 190 ast::ModuleItemKind::ExternCrateItem(it) => {
190 // TODO 191 // Lower `extern crate x` to `use ::x`. This is kind of cheating
192 // and only works if we always interpret absolute paths in the
193 // 2018 style; otherwise `::x` could also refer to a module in
194 // the crate root.
195 if let Some(name_ref) = it.name_ref() {
196 let mut path = Path::from_name_ref(name_ref);
197 path.kind = PathKind::Abs;
198 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
199 self.imports.alloc(ImportData {
200 path,
201 alias,
202 is_glob: false,
203 is_extern_crate: true,
204 });
205 }
191 } 206 }
192 ast::ModuleItemKind::ConstDef(it) => { 207 ast::ModuleItemKind::ConstDef(it) => {
193 if let Some(name) = it.name() { 208 if let Some(name) = it.name() {
@@ -215,6 +230,7 @@ impl LoweredModule {
215 path, 230 path,
216 alias, 231 alias,
217 is_glob: segment.is_none(), 232 is_glob: segment.is_none(),
233 is_extern_crate: false,
218 }); 234 });
219 if let Some(segment) = segment { 235 if let Some(segment) = segment {
220 source_map.insert(import, segment) 236 source_map.insert(import, segment)
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 81c8a4f12..0654dbaa1 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -329,7 +329,49 @@ fn item_map_across_crates() {
329 module.module_id, 329 module.module_id,
330 " 330 "
331 Baz: t v 331 Baz: t v
332 test_crate: t 332 ",
333 );
334}
335
336#[test]
337fn extern_crate_rename() {
338 let (mut db, sr) = MockDatabase::with_files(
339 "
340 //- /main.rs
341 extern crate alloc as alloc_crate;
342
343 mod alloc;
344 mod sync;
345
346 //- /sync.rs
347 use alloc_crate::Arc;
348
349 //- /lib.rs
350 struct Arc;
351 ",
352 );
353 let main_id = sr.files[RelativePath::new("/main.rs")];
354 let sync_id = sr.files[RelativePath::new("/sync.rs")];
355 let lib_id = sr.files[RelativePath::new("/lib.rs")];
356
357 let mut crate_graph = CrateGraph::default();
358 let main_crate = crate_graph.add_crate_root(main_id);
359 let lib_crate = crate_graph.add_crate_root(lib_id);
360 crate_graph
361 .add_dep(main_crate, "alloc".into(), lib_crate)
362 .unwrap();
363
364 db.set_crate_graph(Arc::new(crate_graph));
365
366 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
367 let krate = module.krate(&db).unwrap();
368 let item_map = db.item_map(krate);
369
370 check_module_item_map(
371 &item_map,
372 module.module_id,
373 "
374 Arc: t v
333 ", 375 ",
334 ); 376 );
335} 377}
@@ -361,8 +403,6 @@ fn import_across_source_roots() {
361 403
362 let main_id = sr2.files[RelativePath::new("/main.rs")]; 404 let main_id = sr2.files[RelativePath::new("/main.rs")];
363 405
364 eprintln!("lib = {:?}, main = {:?}", lib_id, main_id);
365
366 let mut crate_graph = CrateGraph::default(); 406 let mut crate_graph = CrateGraph::default();
367 let main_crate = crate_graph.add_crate_root(main_id); 407 let main_crate = crate_graph.add_crate_root(main_id);
368 let lib_crate = crate_graph.add_crate_root(lib_id); 408 let lib_crate = crate_graph.add_crate_root(lib_id);
@@ -381,7 +421,6 @@ fn import_across_source_roots() {
381 module.module_id, 421 module.module_id,
382 " 422 "
383 C: t v 423 C: t v
384 test_crate: t
385 ", 424 ",
386 ); 425 );
387} 426}
@@ -423,7 +462,6 @@ fn reexport_across_crates() {
423 module.module_id, 462 module.module_id,
424 " 463 "
425 Baz: t v 464 Baz: t v
426 test_crate: t
427 ", 465 ",
428 ); 466 );
429} 467}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 6c87d0df7..5ca7bacb5 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -197,7 +197,10 @@ impl Scope {
197 .entries() 197 .entries()
198 .for_each(|(name, res)| { 198 .for_each(|(name, res)| {
199 f(name.clone(), res.def.map(Resolution::Def)); 199 f(name.clone(), res.def.map(Resolution::Def));
200 }) 200 });
201 m.item_map.extern_prelude.iter().for_each(|(name, def)| {
202 f(name.clone(), PerNs::types(Resolution::Def(*def)));
203 });
201 } 204 }
202 Scope::GenericParams(gp) => { 205 Scope::GenericParams(gp) => {
203 for param in &gp.params { 206 for param in &gp.params {