From 799903ba16dd0d80ca975a2e0e58e81f71ddc023 Mon Sep 17 00:00:00 2001 From: Matthias Einwag Date: Sat, 9 Nov 2019 15:22:19 -0800 Subject: Resolve core types This adds support for completion and goto definition of types defined within the "core" crate. The core crate is added as a dependency to each crate in the project. The core crate exported it's own prelude. This caused now all crates to inherit the core crates prelude instead of the std crates. In order to avoid the problem the prelude resolution has been changed to overwrite an already resolved prelude if this was set to a crate named core - in order to pick a better prelude like std. Fixes #2199 --- crates/ra_hir_def/src/nameres/collector.rs | 6 +++++- crates/ra_project_model/src/lib.rs | 8 +++++++- crates/ra_project_model/src/sysroot.rs | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 7e6083961..36a61dc3d 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -27,6 +27,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> let crate_graph = db.crate_graph(); // populate external prelude + let mut prelude_is_core = false; for dep in crate_graph.dependencies(def_map.krate) { let dep_def_map = db.crate_def_map(dep.crate_id); log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); @@ -36,10 +37,13 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> ); // look for the prelude - if def_map.prelude.is_none() { + // If the prelude is the "core" prelude, try to replace it with a higher + // level prelude (e.g. "std") if available. + if def_map.prelude.is_none() || prelude_is_core { let map = db.crate_def_map(dep.crate_id); if map.prelude.is_some() { def_map.prelude = map.prelude; + prelude_is_core = dep.name == "core"; } } } diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 8b8663a78..b1268f29b 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -199,6 +199,7 @@ impl ProjectWorkspace { } } + let libcore = sysroot.core().and_then(|it| sysroot_crates.get(&it).copied()); let libstd = sysroot.std().and_then(|it| sysroot_crates.get(&it).copied()); let mut pkg_to_lib_crate = FxHashMap::default(); @@ -226,7 +227,7 @@ impl ProjectWorkspace { } } - // Set deps to the std and to the lib target of the current package + // Set deps to the core, std and to the lib target of the current package for &from in pkg_crates.get(&pkg).into_iter().flatten() { if let Some(to) = lib_tgt { if to != from { @@ -240,6 +241,11 @@ impl ProjectWorkspace { } } } + if let Some(core) = libcore { + if let Err(_) = crate_graph.add_dep(from, "core".into(), core) { + log::error!("cyclic dependency on core for {}", pkg.name(&cargo)) + } + } if let Some(std) = libstd { if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { log::error!("cyclic dependency on std for {}", pkg.name(&cargo)) diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index 35d6df5cb..3d827809e 100644 --- a/crates/ra_project_model/src/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs @@ -27,6 +27,10 @@ struct SysrootCrateData { } impl Sysroot { + pub fn core(&self) -> Option { + self.by_name("core") + } + pub fn std(&self) -> Option { self.by_name("std") } -- cgit v1.2.3 From 8baa05666c455b4dd6333fd5ac1a694136039f43 Mon Sep 17 00:00:00 2001 From: Matthias Einwag Date: Sat, 9 Nov 2019 17:38:08 -0800 Subject: Add tests for resolving types in core and std preludes --- crates/ra_hir_def/src/nameres/tests.rs | 31 +++++++++++ crates/ra_ide_api/src/completion/complete_scope.rs | 62 ++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index 52bd0aa91..256f7d4be 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs @@ -463,6 +463,37 @@ fn values_dont_shadow_extern_crates() { "###); } +#[test] +fn std_prelude_takes_precedence_above_core_prelude() { + let map = def_map( + r#" + //- /main.rs crate:main deps:core,std + use {Foo, Bar}; + + //- /std.rs crate:std deps:core + #[prelude_import] + pub use self::prelude::*; + mod prelude { + pub struct Foo; + pub use core::prelude::Bar; + } + + //- /core.rs crate:core + #[prelude_import] + pub use self::prelude::*; + mod prelude { + pub struct Bar; + } + "#, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮Foo: t v + "###); +} + #[test] fn cfg_not_test() { let map = def_map( diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 4e56de3f5..3e205efd1 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -597,6 +597,68 @@ mod tests { ); } + #[test] + fn completes_std_prelude_if_core_is_defined() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + fn foo() { let x: <|> } + + //- /core/lib.rs + #[prelude_import] + use prelude::*; + + mod prelude { + struct Option; + } + + //- /std/lib.rs + #[prelude_import] + use prelude::*; + + mod prelude { + struct String; + } + " + ), + @r###" + [ + CompletionItem { + label: "String", + source_range: [18; 18), + delete: [18; 18), + insert: "String", + kind: Struct, + }, + CompletionItem { + label: "core", + source_range: [18; 18), + delete: [18; 18), + insert: "core", + kind: Module, + }, + CompletionItem { + label: "foo()", + source_range: [18; 18), + delete: [18; 18), + insert: "foo()$0", + kind: Function, + lookup: "foo", + detail: "fn foo()", + }, + CompletionItem { + label: "std", + source_range: [18; 18), + delete: [18; 18), + insert: "std", + kind: Module, + }, + ] + "### + ); + } + #[test] fn completes_macros_as_value() { assert_debug_snapshot!( -- cgit v1.2.3 From d634364462931c0a4944de29b38681a482817b6b Mon Sep 17 00:00:00 2001 From: Matthias Einwag Date: Sun, 10 Nov 2019 13:15:47 -0800 Subject: Overwrite the prelude with one defined in a later dependency This removes the special casing for the "core" prelude. Whenever a later dependency also exports a prelude, it will replace the formerly imported prelude. The utilized prelude then depends purely on import order. --- crates/ra_hir_def/src/nameres/collector.rs | 15 ++++++--------- crates/ra_project_model/src/lib.rs | 2 ++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 36a61dc3d..6db9937a4 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -27,7 +27,6 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> let crate_graph = db.crate_graph(); // populate external prelude - let mut prelude_is_core = false; for dep in crate_graph.dependencies(def_map.krate) { let dep_def_map = db.crate_def_map(dep.crate_id); log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); @@ -37,14 +36,12 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> ); // look for the prelude - // If the prelude is the "core" prelude, try to replace it with a higher - // level prelude (e.g. "std") if available. - if def_map.prelude.is_none() || prelude_is_core { - let map = db.crate_def_map(dep.crate_id); - if map.prelude.is_some() { - def_map.prelude = map.prelude; - prelude_is_core = dep.name == "core"; - } + // If the dependency defines a prelude, we overwrite an already defined + // prelude. This is necessary to import the "std" prelude if a crate + // depends on both "core" and "std". + let dep_def_map = db.crate_def_map(dep.crate_id); + if dep_def_map.prelude.is_some() { + def_map.prelude = dep_def_map.prelude; } } diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index b1268f29b..0e14f1b70 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -241,6 +241,8 @@ impl ProjectWorkspace { } } } + // core is added as a dependency before std in order to + // mimic rustcs dependency order if let Some(core) = libcore { if let Err(_) = crate_graph.add_dep(from, "core".into(), core) { log::error!("cyclic dependency on core for {}", pkg.name(&cargo)) -- cgit v1.2.3