Skip to content

Commit 4f63e79

Browse files
Merge #9097
9097: feat: Implement per-edition preludes r=jonas-schievink a=jonas-schievink Part of #9056 Our previous implementation was incorrect (presumably because of the misleading comment in libstd [here](https://github.com/rust-lang/rust/blob/a7890c7952bdc9445eb6c63dc671fa7a1ab0260d/library/std/src/lib.rs#L339-L343)). `#[prelude_import]` does not define the prelude, it can only override the implicit prelude for the current crate. This PR fixes that, which also makes the prelude imports in `rustc_span` work. Closes #8815. bors r+ Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
2 parents 71117e6 + f96c1a0 commit 4f63e79

File tree

12 files changed

+318
-141
lines changed

12 files changed

+318
-141
lines changed

crates/hir_def/src/find_path.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -682,9 +682,11 @@ pub struct S;
682682
//- /main.rs crate:main deps:std
683683
$0
684684
//- /std.rs crate:std
685-
pub mod prelude { pub struct S; }
686-
#[prelude_import]
687-
pub use prelude::*;
685+
pub mod prelude {
686+
pub mod rust_2018 {
687+
pub struct S;
688+
}
689+
}
688690
"#,
689691
"S",
690692
"S",
@@ -700,11 +702,11 @@ pub use prelude::*;
700702
$0
701703
//- /std.rs crate:std
702704
pub mod prelude {
703-
pub enum Option<T> { Some(T), None }
704-
pub use Option::*;
705+
pub mod rust_2018 {
706+
pub enum Option<T> { Some(T), None }
707+
pub use Option::*;
708+
}
705709
}
706-
#[prelude_import]
707-
pub use prelude::*;
708710
"#;
709711
check_found_path(code, "None", "None", "None", "None");
710712
check_found_path(code, "Some", "Some", "Some", "Some");
@@ -1080,11 +1082,11 @@ fn f() {
10801082
}
10811083
//- /std.rs crate:std
10821084
pub mod prelude {
1083-
pub enum Option { None }
1084-
pub use Option::*;
1085+
pub mod rust_2018 {
1086+
pub enum Option { None }
1087+
pub use Option::*;
1088+
}
10851089
}
1086-
#[prelude_import]
1087-
pub use prelude::*;
10881090
"#,
10891091
"None",
10901092
"None",

crates/hir_def/src/nameres/collector.rs

+58-10
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
66
use std::iter;
77

8-
use base_db::{CrateId, FileId, ProcMacroId};
8+
use base_db::{CrateId, Edition, FileId, ProcMacroId};
99
use cfg::{CfgExpr, CfgOptions};
1010
use hir_expand::{
1111
ast_id_map::FileAstId,
1212
builtin_derive::find_builtin_derive,
1313
builtin_macro::find_builtin_macro,
14-
name::{AsName, Name},
14+
name::{name, AsName, Name},
1515
proc_macro::ProcMacroExpander,
1616
FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
1717
};
@@ -67,14 +67,6 @@ pub(super) fn collect_defs(
6767
def_map
6868
.extern_prelude
6969
.insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into());
70-
71-
// look for the prelude
72-
// If the dependency defines a prelude, we overwrite an already defined
73-
// prelude. This is necessary to import the "std" prelude if a crate
74-
// depends on both "core" and "std".
75-
if dep_def_map.prelude.is_some() {
76-
def_map.prelude = dep_def_map.prelude;
77-
}
7870
}
7971
}
8072

@@ -283,6 +275,8 @@ impl DefCollector<'_> {
283275

284276
let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
285277
if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
278+
self.inject_prelude(&attrs);
279+
286280
// Process other crate-level attributes.
287281
for attr in &*attrs {
288282
let attr_name = match attr.path.as_ident() {
@@ -460,6 +454,58 @@ impl DefCollector<'_> {
460454
}
461455
}
462456

457+
fn inject_prelude(&mut self, crate_attrs: &Attrs) {
458+
// See compiler/rustc_builtin_macros/src/standard_library_imports.rs
459+
460+
if crate_attrs.by_key("no_core").exists() {
461+
// libcore does not get a prelude.
462+
return;
463+
}
464+
465+
let krate = if crate_attrs.by_key("no_std").exists() {
466+
name![core]
467+
} else {
468+
let std = name![std];
469+
if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
470+
std
471+
} else {
472+
// If `std` does not exist for some reason, fall back to core. This mostly helps
473+
// keep r-a's own tests minimal.
474+
name![core]
475+
}
476+
};
477+
478+
let edition = match self.def_map.edition {
479+
Edition::Edition2015 => name![rust_2015],
480+
Edition::Edition2018 => name![rust_2018],
481+
Edition::Edition2021 => name![rust_2021],
482+
};
483+
484+
let path_kind = if self.def_map.edition == Edition::Edition2015 {
485+
PathKind::Plain
486+
} else {
487+
PathKind::Abs
488+
};
489+
let path =
490+
ModPath::from_segments(path_kind, [krate, name![prelude], edition].iter().cloned());
491+
492+
let (per_ns, _) =
493+
self.def_map.resolve_path(self.db, self.def_map.root, &path, BuiltinShadowMode::Other);
494+
495+
match &per_ns.types {
496+
Some((ModuleDefId::ModuleId(m), _)) => {
497+
self.def_map.prelude = Some(*m);
498+
}
499+
_ => {
500+
log::error!(
501+
"could not resolve prelude path `{}` to module (resolved to {:?})",
502+
path,
503+
per_ns.types
504+
);
505+
}
506+
}
507+
}
508+
463509
/// Adds a definition of procedural macro `name` to the root module.
464510
///
465511
/// # Notes on procedural macro resolution
@@ -718,6 +764,8 @@ impl DefCollector<'_> {
718764
match def.take_types() {
719765
Some(ModuleDefId::ModuleId(m)) => {
720766
if import.is_prelude {
767+
// Note: This dodgily overrides the injected prelude. The rustc
768+
// implementation seems to work the same though.
721769
cov_mark::hit!(std_prelude);
722770
self.def_map.prelude = Some(m);
723771
} else if m.krate != self.def_map.krate {

crates/hir_def/src/nameres/tests.rs

+100-31
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,16 @@ fn std_prelude() {
246246
check(
247247
r#"
248248
//- /main.rs crate:main deps:test_crate
249+
#[prelude_import]
250+
use ::test_crate::prelude::*;
251+
249252
use Foo::*;
250253
251254
//- /lib.rs crate:test_crate
252-
mod prelude;
253-
#[prelude_import]
254-
use prelude::*;
255+
pub mod prelude;
255256
256257
//- /prelude.rs
257-
pub enum Foo { Bar, Baz };
258+
pub enum Foo { Bar, Baz }
258259
"#,
259260
expect![[r#"
260261
crate
@@ -466,6 +467,74 @@ pub struct Bar;
466467
);
467468
}
468469

470+
#[test]
471+
fn no_std_prelude() {
472+
check(
473+
r#"
474+
//- /main.rs crate:main deps:core,std
475+
#![cfg_attr(not(never), no_std)]
476+
use Rust;
477+
478+
//- /core.rs crate:core
479+
pub mod prelude {
480+
pud mod rust_2018 {
481+
pub struct Rust;
482+
}
483+
}
484+
//- /std.rs crate:std deps:core
485+
pub mod prelude {
486+
pud mod rust_2018 {
487+
}
488+
}
489+
"#,
490+
expect![[r#"
491+
crate
492+
Rust: t v
493+
"#]],
494+
);
495+
}
496+
497+
#[test]
498+
fn edition_specific_preludes() {
499+
// We can't test the 2015 prelude here since you can't reexport its contents with 2015's
500+
// absolute paths.
501+
502+
check(
503+
r#"
504+
//- /main.rs edition:2018 crate:main deps:std
505+
use Rust2018;
506+
507+
//- /std.rs crate:std
508+
pub mod prelude {
509+
pud mod rust_2018 {
510+
pub struct Rust2018;
511+
}
512+
}
513+
"#,
514+
expect![[r#"
515+
crate
516+
Rust2018: t v
517+
"#]],
518+
);
519+
check(
520+
r#"
521+
//- /main.rs edition:2021 crate:main deps:std
522+
use Rust2021;
523+
524+
//- /std.rs crate:std
525+
pub mod prelude {
526+
pud mod rust_2021 {
527+
pub struct Rust2021;
528+
}
529+
}
530+
"#,
531+
expect![[r#"
532+
crate
533+
Rust2021: t v
534+
"#]],
535+
);
536+
}
537+
469538
#[test]
470539
fn std_prelude_takes_precedence_above_core_prelude() {
471540
check(
@@ -474,18 +543,18 @@ fn std_prelude_takes_precedence_above_core_prelude() {
474543
use {Foo, Bar};
475544
476545
//- /std.rs crate:std deps:core
477-
#[prelude_import]
478-
pub use self::prelude::*;
479-
mod prelude {
480-
pub struct Foo;
481-
pub use core::prelude::Bar;
546+
pub mod prelude {
547+
pub mod rust_2018 {
548+
pub struct Foo;
549+
pub use core::prelude::rust_2018::Bar;
550+
}
482551
}
483552
484553
//- /core.rs crate:core
485-
#[prelude_import]
486-
pub use self::prelude::*;
487-
mod prelude {
488-
pub struct Bar;
554+
pub mod prelude {
555+
pub mod rust_2018 {
556+
pub struct Bar;
557+
}
489558
}
490559
"#,
491560
expect![[r#"
@@ -504,15 +573,15 @@ fn cfg_not_test() {
504573
use {Foo, Bar, Baz};
505574
506575
//- /lib.rs crate:std
507-
#[prelude_import]
508-
pub use self::prelude::*;
509-
mod prelude {
510-
#[cfg(test)]
511-
pub struct Foo;
512-
#[cfg(not(test))]
513-
pub struct Bar;
514-
#[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
515-
pub struct Baz;
576+
pub mod prelude {
577+
pub mod rust_2018 {
578+
#[cfg(test)]
579+
pub struct Foo;
580+
#[cfg(not(test))]
581+
pub struct Bar;
582+
#[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
583+
pub struct Baz;
584+
}
516585
}
517586
"#,
518587
expect![[r#"
@@ -532,15 +601,15 @@ fn cfg_test() {
532601
use {Foo, Bar, Baz};
533602
534603
//- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42
535-
#[prelude_import]
536-
pub use self::prelude::*;
537-
mod prelude {
538-
#[cfg(test)]
539-
pub struct Foo;
540-
#[cfg(not(test))]
541-
pub struct Bar;
542-
#[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
543-
pub struct Baz;
604+
pub mod prelude {
605+
pub mod rust_2018 {
606+
#[cfg(test)]
607+
pub struct Foo;
608+
#[cfg(not(test))]
609+
pub struct Bar;
610+
#[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
611+
pub struct Baz;
612+
}
544613
}
545614
"#,
546615
expect![[r#"

crates/hir_def/src/nameres/tests/macros.rs

+15-17
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ fn prelude_is_macro_use() {
264264
cov_mark::check!(prelude_is_macro_use);
265265
check(
266266
r#"
267-
//- /main.rs crate:main deps:foo
267+
//- /main.rs crate:main deps:std
268268
structs!(Foo);
269269
structs_priv!(Bar);
270270
structs_outside!(Out);
@@ -276,21 +276,20 @@ mod bar;
276276
structs!(Baz);
277277
crate::structs!(MacroNotResolved3);
278278
279-
//- /lib.rs crate:foo
280-
#[prelude_import]
281-
use self::prelude::*;
282-
283-
mod prelude {
284-
#[macro_export]
285-
macro_rules! structs {
286-
($i:ident) => { struct $i; }
287-
}
288-
289-
mod priv_mod {
279+
//- /lib.rs crate:std
280+
pub mod prelude {
281+
pub mod rust_2018 {
290282
#[macro_export]
291-
macro_rules! structs_priv {
283+
macro_rules! structs {
292284
($i:ident) => { struct $i; }
293285
}
286+
287+
mod priv_mod {
288+
#[macro_export]
289+
macro_rules! structs_priv {
290+
($i:ident) => { struct $i; }
291+
}
292+
}
294293
}
295294
}
296295
@@ -617,12 +616,11 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
617616
foo!();
618617
619618
//- /std.rs crate:std deps:core
620-
#[prelude_import]
621-
use self::prelude::*;
622-
623619
pub use core::foo;
624620
625-
mod prelude {}
621+
pub mod prelude {
622+
pub mod rust_2018 {}
623+
}
626624
627625
#[macro_use]
628626
mod std_macros;

crates/hir_expand/src/name.rs

+4
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ pub mod known {
176176
result,
177177
boxed,
178178
option,
179+
prelude,
180+
rust_2015,
181+
rust_2018,
182+
rust_2021,
179183
// Components of known path (type name)
180184
Iterator,
181185
IntoIterator,

0 commit comments

Comments
 (0)