diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-05 07:53:08 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-05 07:53:08 +0000 |
commit | 4d4c46aff8f9a7ce8c2f91fbe6c7c363f5d3e08c (patch) | |
tree | 90473c4a67ac70ee40fde54a25b11d7768c41593 /crates/ra_hir/src | |
parent | 94d5d0d7e893a50bdd22ce4366ca15f083218d22 (diff) | |
parent | de4c5e381fb1adc25143dcd67af6c87f6d9789ae (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.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 90 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/lower.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 5 |
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)] |
36 | pub struct ItemMap { | 36 | pub 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}; | |||
8 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHashMap; |
9 | 9 | ||
10 | use crate::{ | 10 | use 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] | ||
337 | fn 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 { |