diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index ee52794aa8..219ed4c071 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs @@ -682,9 +682,11 @@ pub struct S; //- /main.rs crate:main deps:std $0 //- /std.rs crate:std -pub mod prelude { pub struct S; } -#[prelude_import] -pub use prelude::*; +pub mod prelude { + pub mod rust_2018 { + pub struct S; + } +} "#, "S", "S", @@ -700,11 +702,11 @@ pub use prelude::*; $0 //- /std.rs crate:std pub mod prelude { - pub enum Option { Some(T), None } - pub use Option::*; + pub mod rust_2018 { + pub enum Option { Some(T), None } + pub use Option::*; + } } -#[prelude_import] -pub use prelude::*; "#; check_found_path(code, "None", "None", "None", "None"); check_found_path(code, "Some", "Some", "Some", "Some"); @@ -1080,11 +1082,11 @@ fn f() { } //- /std.rs crate:std pub mod prelude { - pub enum Option { None } - pub use Option::*; + pub mod rust_2018 { + pub enum Option { None } + pub use Option::*; + } } -#[prelude_import] -pub use prelude::*; "#, "None", "None", diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 7f9fdb3793..5984243055 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -5,13 +5,13 @@ use std::iter; -use base_db::{CrateId, FileId, ProcMacroId}; +use base_db::{CrateId, Edition, FileId, ProcMacroId}; use cfg::{CfgExpr, CfgOptions}; use hir_expand::{ ast_id_map::FileAstId, builtin_derive::find_builtin_derive, builtin_macro::find_builtin_macro, - name::{AsName, Name}, + name::{name, AsName, Name}, proc_macro::ProcMacroExpander, FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; @@ -67,14 +67,6 @@ pub(super) fn collect_defs( def_map .extern_prelude .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); - - // look for the 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". - if dep_def_map.prelude.is_some() { - def_map.prelude = dep_def_map.prelude; - } } } @@ -283,6 +275,8 @@ impl DefCollector<'_> { let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) { + self.inject_prelude(&attrs); + // Process other crate-level attributes. for attr in &*attrs { let attr_name = match attr.path.as_ident() { @@ -460,6 +454,58 @@ impl DefCollector<'_> { } } + fn inject_prelude(&mut self, crate_attrs: &Attrs) { + // See compiler/rustc_builtin_macros/src/standard_library_imports.rs + + if crate_attrs.by_key("no_core").exists() { + // libcore does not get a prelude. + return; + } + + let krate = if crate_attrs.by_key("no_std").exists() { + name![core] + } else { + let std = name![std]; + if self.def_map.extern_prelude().any(|(name, _)| *name == std) { + std + } else { + // If `std` does not exist for some reason, fall back to core. This mostly helps + // keep r-a's own tests minimal. + name![core] + } + }; + + let edition = match self.def_map.edition { + Edition::Edition2015 => name![rust_2015], + Edition::Edition2018 => name![rust_2018], + Edition::Edition2021 => name![rust_2021], + }; + + let path_kind = if self.def_map.edition == Edition::Edition2015 { + PathKind::Plain + } else { + PathKind::Abs + }; + let path = + ModPath::from_segments(path_kind, [krate, name![prelude], edition].iter().cloned()); + + let (per_ns, _) = + self.def_map.resolve_path(self.db, self.def_map.root, &path, BuiltinShadowMode::Other); + + match &per_ns.types { + Some((ModuleDefId::ModuleId(m), _)) => { + self.def_map.prelude = Some(*m); + } + _ => { + log::error!( + "could not resolve prelude path `{}` to module (resolved to {:?})", + path, + per_ns.types + ); + } + } + } + /// Adds a definition of procedural macro `name` to the root module. /// /// # Notes on procedural macro resolution @@ -718,6 +764,8 @@ impl DefCollector<'_> { match def.take_types() { Some(ModuleDefId::ModuleId(m)) => { if import.is_prelude { + // Note: This dodgily overrides the injected prelude. The rustc + // implementation seems to work the same though. cov_mark::hit!(std_prelude); self.def_map.prelude = Some(m); } else if m.krate != self.def_map.krate { diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 9f652731d9..58c01354a4 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs @@ -246,15 +246,16 @@ fn std_prelude() { check( r#" //- /main.rs crate:main deps:test_crate +#[prelude_import] +use ::test_crate::prelude::*; + use Foo::*; //- /lib.rs crate:test_crate -mod prelude; -#[prelude_import] -use prelude::*; +pub mod prelude; //- /prelude.rs -pub enum Foo { Bar, Baz }; +pub enum Foo { Bar, Baz } "#, expect![[r#" crate @@ -466,6 +467,74 @@ pub struct Bar; ); } +#[test] +fn no_std_prelude() { + check( + r#" + //- /main.rs crate:main deps:core,std + #![cfg_attr(not(never), no_std)] + use Rust; + + //- /core.rs crate:core + pub mod prelude { + pud mod rust_2018 { + pub struct Rust; + } + } + //- /std.rs crate:std deps:core + pub mod prelude { + pud mod rust_2018 { + } + } + "#, + expect![[r#" + crate + Rust: t v + "#]], + ); +} + +#[test] +fn edition_specific_preludes() { + // We can't test the 2015 prelude here since you can't reexport its contents with 2015's + // absolute paths. + + check( + r#" + //- /main.rs edition:2018 crate:main deps:std + use Rust2018; + + //- /std.rs crate:std + pub mod prelude { + pud mod rust_2018 { + pub struct Rust2018; + } + } + "#, + expect![[r#" + crate + Rust2018: t v + "#]], + ); + check( + r#" + //- /main.rs edition:2021 crate:main deps:std + use Rust2021; + + //- /std.rs crate:std + pub mod prelude { + pud mod rust_2021 { + pub struct Rust2021; + } + } + "#, + expect![[r#" + crate + Rust2021: t v + "#]], + ); +} + #[test] fn std_prelude_takes_precedence_above_core_prelude() { check( @@ -474,18 +543,18 @@ fn std_prelude_takes_precedence_above_core_prelude() { 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; +pub mod prelude { + pub mod rust_2018 { + pub struct Foo; + pub use core::prelude::rust_2018::Bar; + } } //- /core.rs crate:core -#[prelude_import] -pub use self::prelude::*; -mod prelude { - pub struct Bar; +pub mod prelude { + pub mod rust_2018 { + pub struct Bar; + } } "#, expect![[r#" @@ -504,15 +573,15 @@ fn cfg_not_test() { use {Foo, Bar, Baz}; //- /lib.rs crate:std -#[prelude_import] -pub use self::prelude::*; -mod prelude { - #[cfg(test)] - pub struct Foo; - #[cfg(not(test))] - pub struct Bar; - #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] - pub struct Baz; +pub mod prelude { + pub mod rust_2018 { + #[cfg(test)] + pub struct Foo; + #[cfg(not(test))] + pub struct Bar; + #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] + pub struct Baz; + } } "#, expect![[r#" @@ -532,15 +601,15 @@ fn cfg_test() { use {Foo, Bar, Baz}; //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 -#[prelude_import] -pub use self::prelude::*; -mod prelude { - #[cfg(test)] - pub struct Foo; - #[cfg(not(test))] - pub struct Bar; - #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] - pub struct Baz; +pub mod prelude { + pub mod rust_2018 { + #[cfg(test)] + pub struct Foo; + #[cfg(not(test))] + pub struct Bar; + #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] + pub struct Baz; + } } "#, expect![[r#" diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 3065efd65e..3716184386 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs @@ -264,7 +264,7 @@ fn prelude_is_macro_use() { cov_mark::check!(prelude_is_macro_use); check( r#" -//- /main.rs crate:main deps:foo +//- /main.rs crate:main deps:std structs!(Foo); structs_priv!(Bar); structs_outside!(Out); @@ -276,21 +276,20 @@ mod bar; structs!(Baz); crate::structs!(MacroNotResolved3); -//- /lib.rs crate:foo -#[prelude_import] -use self::prelude::*; - -mod prelude { - #[macro_export] - macro_rules! structs { - ($i:ident) => { struct $i; } - } - - mod priv_mod { +//- /lib.rs crate:std +pub mod prelude { + pub mod rust_2018 { #[macro_export] - macro_rules! structs_priv { + macro_rules! structs { ($i:ident) => { struct $i; } } + + mod priv_mod { + #[macro_export] + macro_rules! structs_priv { + ($i:ident) => { struct $i; } + } + } } } @@ -617,12 +616,11 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() { foo!(); //- /std.rs crate:std deps:core -#[prelude_import] -use self::prelude::*; - pub use core::foo; -mod prelude {} +pub mod prelude { + pub mod rust_2018 {} +} #[macro_use] mod std_macros; diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index b07fbf8b3f..abc6753bf1 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs @@ -176,6 +176,10 @@ pub mod known { result, boxed, option, + prelude, + rust_2015, + rust_2018, + rust_2021, // Components of known path (type name) Iterator, IntoIterator, diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 7647bb08b7..d14103aab1 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -982,14 +982,18 @@ fn test() { } //^ S //- /lib.rs crate:core -#[prelude_import] -use clone::*; -mod clone { - trait Clone { +pub mod prelude { + pub mod rust_2018 { + #[rustc_builtin_macro] + pub macro Clone {} + pub use crate::clone::Clone; + } +} + +pub mod clone { + pub trait Clone { fn clone(&self) -> Self; } - #[rustc_builtin_macro] - macro Clone {} } "#, ); @@ -1001,14 +1005,22 @@ fn infer_derive_clone_in_core() { r#" //- /lib.rs crate:core #[prelude_import] -use clone::*; -mod clone { - trait Clone { +use prelude::rust_2018::*; + +pub mod prelude { + pub mod rust_2018 { + #[rustc_builtin_macro] + pub macro Clone {} + pub use crate::clone::Clone; + } +} + +pub mod clone { + pub trait Clone { fn clone(&self) -> Self; } - #[rustc_builtin_macro] - macro Clone {} } + #[derive(Clone)] pub struct S; @@ -1037,14 +1049,18 @@ fn test() { } //- /lib.rs crate:core -#[prelude_import] -use clone::*; -mod clone { - trait Clone { +pub mod prelude { + pub mod rust_2018 { + #[rustc_builtin_macro] + pub macro Clone {} + pub use crate::clone::Clone; + } +} + +pub mod clone { + pub trait Clone { fn clone(&self) -> Self; } - #[rustc_builtin_macro] - macro Clone {} } "#, ); diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index a4c132bc5f..058eb91299 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs @@ -796,7 +796,7 @@ fn test() { fn method_resolution_trait_from_prelude() { check_types( r#" -//- /main.rs crate:main deps:other_crate +//- /main.rs crate:main deps:core struct S; impl Clone for S {} @@ -805,12 +805,12 @@ fn test() { //^ S } -//- /lib.rs crate:other_crate -#[prelude_import] use foo::*; - -mod foo { - trait Clone { - fn clone(&self) -> Self; +//- /lib.rs crate:core +pub mod prelude { + pub mod rust_2018 { + pub trait Clone { + fn clone(&self) -> Self; + } } } "#, diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index ad9edf11cd..1019e783b5 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs @@ -426,11 +426,12 @@ fn test() { //- /std.rs crate:std #[prelude_import] -use prelude::*; - +use self::prelude::rust_2018::*; pub mod prelude { - pub use crate::iter::Iterator; - pub use crate::option::Option; + pub mod rust_2018 { + pub use crate::iter::Iterator; + pub use crate::option::Option; + } } pub mod iter { diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index ac312981df..3418ed21e7 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs @@ -2712,3 +2712,23 @@ fn main() { "#]], ); } + +#[test] +fn prelude_2015() { + check_types( + r#" +//- /main.rs edition:2015 crate:main deps:core +fn f() { + Rust; + //^ Rust +} + +//- /core.rs crate:core +pub mod prelude { + pub mod rust_2015 { + pub struct Rust; + } +} + "#, + ); +} diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 49add4ab99..588f0d1d41 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -20,11 +20,12 @@ fn test() { } //^ u64 //- /core.rs crate:core -#[prelude_import] use future::*; -mod future { - #[lang = "future_trait"] - trait Future { - type Output; +pub mod prelude { + pub mod rust_2018 { + #[lang = "future_trait"] + pub trait Future { + type Output; + } } } "#, @@ -136,17 +137,15 @@ fn test() { } //^ i32 //- /core.rs crate:core -#[prelude_import] use ops::*; -mod ops { - trait Try { +pub mod ops { + pub trait Try { type Ok; type Error; } } -#[prelude_import] use result::*; -mod result { - enum Result { +pub mod result { + pub enum Result { Ok(O), Err(E) } @@ -156,6 +155,12 @@ mod result { type Error = E; } } + +pub mod prelude { + pub mod rust_2018 { + pub use crate::{result::*, ops::*}; + } +} "#, ); } @@ -190,8 +195,7 @@ mov convert { impl From for T {} } -#[prelude_import] use result::*; -mod result { +pub mod result { use crate::convert::From; use crate::ops::{Try, FromResidual}; @@ -208,6 +212,12 @@ mod result { impl> FromResidual> for Result {} } + +pub mod prelude { + pub mod rust_2018 { + pub use crate::result::*; + } +} "#, ); } @@ -217,6 +227,7 @@ fn infer_for_loop() { check_types( r#" //- /main.rs crate:main deps:core,alloc +#![no_std] use alloc::collections::Vec; fn test() { @@ -228,14 +239,19 @@ fn test() { } //- /core.rs crate:core -#[prelude_import] use iter::*; -mod iter { - trait IntoIterator { +pub mod iter { + pub trait IntoIterator { type Item; } } +pub mod prelude { + pub mod rust_2018 { + pub use crate::iter::*; + } +} //- /alloc.rs crate:alloc deps:core +#![no_std] mod collections { struct Vec {} impl Vec { diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 20188a7ddc..bd955aa85c 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -385,10 +385,11 @@ fn foo() { fn foo() { let x: $0 } //- /std/lib.rs crate:std -#[prelude_import] -use prelude::*; - -mod prelude { struct Option; } +pub mod prelude { + pub mod rust_2018 { + pub struct Option; + } +} "#, expect![[r#" fn foo() fn() @@ -406,12 +407,10 @@ mod prelude { struct Option; } fn f() {$0} //- /std/lib.rs crate:std -#[prelude_import] -pub use prelude::*; - -#[macro_use] -mod prelude { - pub use crate::concat; +pub mod prelude { + pub mod rust_2018 { + pub use crate::concat; + } } mod macros { @@ -436,16 +435,18 @@ mod macros { fn foo() { let x: $0 } //- /core/lib.rs crate:core -#[prelude_import] -use prelude::*; - -mod prelude { struct Option; } +pub mod prelude { + pub mod rust_2018 { + pub struct Option; + } +} //- /std/lib.rs crate:std deps:core -#[prelude_import] -use prelude::*; - -mod prelude { struct String; } +pub mod prelude { + pub mod rust_2018 { + pub struct String; + } +} "#, expect![[r#" fn foo() fn() diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs index 29ae12dcf4..3128519661 100644 --- a/crates/ide_db/src/helpers/famous_defs_fixture.rs +++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs @@ -128,17 +128,19 @@ pub mod option { } pub mod prelude { - pub use crate::{ - cmp::Ord, - convert::{From, Into}, - default::Default, - iter::{IntoIterator, Iterator}, - ops::{Fn, FnMut, FnOnce}, - option::Option::{self, *}, - }; + pub mod rust_2018 { + pub use crate::{ + cmp::Ord, + convert::{From, Into}, + default::Default, + iter::{IntoIterator, Iterator}, + ops::{Fn, FnMut, FnOnce}, + option::Option::{self, *}, + }; + } } #[prelude_import] -pub use prelude::*; +pub use prelude::rust_2018::*; //- /libstd.rs crate:std deps:core //! Signatures of traits, types and functions from the std lib for use in tests. @@ -148,4 +150,4 @@ mod return_keyword {} /// Docs for prim_str mod prim_str {} -pub use core::ops; \ No newline at end of file +pub use core::ops;