diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 7e60839614f0..6db9937a4321 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -36,11 +36,12 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> ); // look for the prelude - if def_map.prelude.is_none() { - let map = db.crate_def_map(dep.crate_id); - if map.prelude.is_some() { - def_map.prelude = map.prelude; - } + // 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_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index 52bd0aa91e8c..256f7d4be72e 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 4e56de3f5424..3e205efd12ae 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!( diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 8b8663a78fcf..0e14f1b70c9f 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,13 @@ 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)) + } + } 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 35d6df5cb5d7..3d827809ee80 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") }