aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-06-01 12:39:19 +0100
committerJonas Schievink <[email protected]>2021-06-01 12:39:19 +0100
commitf96c1a0414ee302fe96503d89f2998483345c8a9 (patch)
tree6de19b3c128809cd56641f70873c35f17974aced /crates/hir_def/src/nameres
parent71117e6812f87e014bc8e984e195a75e222ac227 (diff)
Implement per-edition preludes
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r--crates/hir_def/src/nameres/collector.rs68
-rw-r--r--crates/hir_def/src/nameres/tests.rs131
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs32
3 files changed, 173 insertions, 58 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 7f9fdb379..598424305 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -5,13 +5,13 @@
5 5
6use std::iter; 6use std::iter;
7 7
8use base_db::{CrateId, FileId, ProcMacroId}; 8use base_db::{CrateId, Edition, FileId, ProcMacroId};
9use cfg::{CfgExpr, CfgOptions}; 9use cfg::{CfgExpr, CfgOptions};
10use hir_expand::{ 10use hir_expand::{
11 ast_id_map::FileAstId, 11 ast_id_map::FileAstId,
12 builtin_derive::find_builtin_derive, 12 builtin_derive::find_builtin_derive,
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{name, AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 16 FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
@@ -67,14 +67,6 @@ pub(super) fn collect_defs(
67 def_map 67 def_map
68 .extern_prelude 68 .extern_prelude
69 .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); 69 .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 }
78 } 70 }
79 } 71 }
80 72
@@ -283,6 +275,8 @@ impl DefCollector<'_> {
283 275
284 let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); 276 let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
285 if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) { 277 if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
278 self.inject_prelude(&attrs);
279
286 // Process other crate-level attributes. 280 // Process other crate-level attributes.
287 for attr in &*attrs { 281 for attr in &*attrs {
288 let attr_name = match attr.path.as_ident() { 282 let attr_name = match attr.path.as_ident() {
@@ -460,6 +454,58 @@ impl DefCollector<'_> {
460 } 454 }
461 } 455 }
462 456
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
463 /// Adds a definition of procedural macro `name` to the root module. 509 /// Adds a definition of procedural macro `name` to the root module.
464 /// 510 ///
465 /// # Notes on procedural macro resolution 511 /// # Notes on procedural macro resolution
@@ -718,6 +764,8 @@ impl DefCollector<'_> {
718 match def.take_types() { 764 match def.take_types() {
719 Some(ModuleDefId::ModuleId(m)) => { 765 Some(ModuleDefId::ModuleId(m)) => {
720 if import.is_prelude { 766 if import.is_prelude {
767 // Note: This dodgily overrides the injected prelude. The rustc
768 // implementation seems to work the same though.
721 cov_mark::hit!(std_prelude); 769 cov_mark::hit!(std_prelude);
722 self.def_map.prelude = Some(m); 770 self.def_map.prelude = Some(m);
723 } else if m.krate != self.def_map.krate { 771 } 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 9f652731d..58c01354a 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -246,15 +246,16 @@ fn std_prelude() {
246 check( 246 check(
247 r#" 247 r#"
248//- /main.rs crate:main deps:test_crate 248//- /main.rs crate:main deps:test_crate
249#[prelude_import]
250use ::test_crate::prelude::*;
251
249use Foo::*; 252use Foo::*;
250 253
251//- /lib.rs crate:test_crate 254//- /lib.rs crate:test_crate
252mod prelude; 255pub mod prelude;
253#[prelude_import]
254use prelude::*;
255 256
256//- /prelude.rs 257//- /prelude.rs
257pub enum Foo { Bar, Baz }; 258pub enum Foo { Bar, Baz }
258"#, 259"#,
259 expect![[r#" 260 expect![[r#"
260 crate 261 crate
@@ -467,6 +468,74 @@ pub struct Bar;
467} 468}
468 469
469#[test] 470#[test]
471fn 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]
498fn 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
538#[test]
470fn std_prelude_takes_precedence_above_core_prelude() { 539fn std_prelude_takes_precedence_above_core_prelude() {
471 check( 540 check(
472 r#" 541 r#"
@@ -474,18 +543,18 @@ fn std_prelude_takes_precedence_above_core_prelude() {
474use {Foo, Bar}; 543use {Foo, Bar};
475 544
476//- /std.rs crate:std deps:core 545//- /std.rs crate:std deps:core
477#[prelude_import] 546pub mod prelude {
478pub use self::prelude::*; 547 pub mod rust_2018 {
479mod prelude { 548 pub struct Foo;
480 pub struct Foo; 549 pub use core::prelude::rust_2018::Bar;
481 pub use core::prelude::Bar; 550 }
482} 551}
483 552
484//- /core.rs crate:core 553//- /core.rs crate:core
485#[prelude_import] 554pub mod prelude {
486pub use self::prelude::*; 555 pub mod rust_2018 {
487mod prelude { 556 pub struct Bar;
488 pub struct Bar; 557 }
489} 558}
490"#, 559"#,
491 expect![[r#" 560 expect![[r#"
@@ -504,15 +573,15 @@ fn cfg_not_test() {
504use {Foo, Bar, Baz}; 573use {Foo, Bar, Baz};
505 574
506//- /lib.rs crate:std 575//- /lib.rs crate:std
507#[prelude_import] 576pub mod prelude {
508pub use self::prelude::*; 577 pub mod rust_2018 {
509mod prelude { 578 #[cfg(test)]
510 #[cfg(test)] 579 pub struct Foo;
511 pub struct Foo; 580 #[cfg(not(test))]
512 #[cfg(not(test))] 581 pub struct Bar;
513 pub struct Bar; 582 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
514 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] 583 pub struct Baz;
515 pub struct Baz; 584 }
516} 585}
517"#, 586"#,
518 expect![[r#" 587 expect![[r#"
@@ -532,15 +601,15 @@ fn cfg_test() {
532use {Foo, Bar, Baz}; 601use {Foo, Bar, Baz};
533 602
534//- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 603//- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42
535#[prelude_import] 604pub mod prelude {
536pub use self::prelude::*; 605 pub mod rust_2018 {
537mod prelude { 606 #[cfg(test)]
538 #[cfg(test)] 607 pub struct Foo;
539 pub struct Foo; 608 #[cfg(not(test))]
540 #[cfg(not(test))] 609 pub struct Bar;
541 pub struct Bar; 610 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
542 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] 611 pub struct Baz;
543 pub struct Baz; 612 }
544} 613}
545"#, 614"#,
546 expect![[r#" 615 expect![[r#"
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index 3065efd65..371618438 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() {
264 cov_mark::check!(prelude_is_macro_use); 264 cov_mark::check!(prelude_is_macro_use);
265 check( 265 check(
266 r#" 266 r#"
267//- /main.rs crate:main deps:foo 267//- /main.rs crate:main deps:std
268structs!(Foo); 268structs!(Foo);
269structs_priv!(Bar); 269structs_priv!(Bar);
270structs_outside!(Out); 270structs_outside!(Out);
@@ -276,21 +276,20 @@ mod bar;
276structs!(Baz); 276structs!(Baz);
277crate::structs!(MacroNotResolved3); 277crate::structs!(MacroNotResolved3);
278 278
279//- /lib.rs crate:foo 279//- /lib.rs crate:std
280#[prelude_import] 280pub mod prelude {
281use self::prelude::*; 281 pub mod rust_2018 {
282
283mod prelude {
284 #[macro_export]
285 macro_rules! structs {
286 ($i:ident) => { struct $i; }
287 }
288
289 mod priv_mod {
290 #[macro_export] 282 #[macro_export]
291 macro_rules! structs_priv { 283 macro_rules! structs {
292 ($i:ident) => { struct $i; } 284 ($i:ident) => { struct $i; }
293 } 285 }
286
287 mod priv_mod {
288 #[macro_export]
289 macro_rules! structs_priv {
290 ($i:ident) => { struct $i; }
291 }
292 }
294 } 293 }
295} 294}
296 295
@@ -617,12 +616,11 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
617foo!(); 616foo!();
618 617
619//- /std.rs crate:std deps:core 618//- /std.rs crate:std deps:core
620#[prelude_import]
621use self::prelude::*;
622
623pub use core::foo; 619pub use core::foo;
624 620
625mod prelude {} 621pub mod prelude {
622 pub mod rust_2018 {}
623}
626 624
627#[macro_use] 625#[macro_use]
628mod std_macros; 626mod std_macros;