diff options
author | Jonas Schievink <[email protected]> | 2021-06-01 12:39:19 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2021-06-01 12:39:19 +0100 |
commit | f96c1a0414ee302fe96503d89f2998483345c8a9 (patch) | |
tree | 6de19b3c128809cd56641f70873c35f17974aced /crates/hir_def/src/nameres | |
parent | 71117e6812f87e014bc8e984e195a75e222ac227 (diff) |
Implement per-edition preludes
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 68 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 131 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/macros.rs | 32 |
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 | ||
6 | use std::iter; | 6 | use std::iter; |
7 | 7 | ||
8 | use base_db::{CrateId, FileId, ProcMacroId}; | 8 | use base_db::{CrateId, Edition, FileId, ProcMacroId}; |
9 | use cfg::{CfgExpr, CfgOptions}; | 9 | use cfg::{CfgExpr, CfgOptions}; |
10 | use hir_expand::{ | 10 | use 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] | ||
250 | use ::test_crate::prelude::*; | ||
251 | |||
249 | use Foo::*; | 252 | use Foo::*; |
250 | 253 | ||
251 | //- /lib.rs crate:test_crate | 254 | //- /lib.rs crate:test_crate |
252 | mod prelude; | 255 | pub mod prelude; |
253 | #[prelude_import] | ||
254 | use prelude::*; | ||
255 | 256 | ||
256 | //- /prelude.rs | 257 | //- /prelude.rs |
257 | pub enum Foo { Bar, Baz }; | 258 | pub 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] |
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 | |||
538 | #[test] | ||
470 | fn std_prelude_takes_precedence_above_core_prelude() { | 539 | fn 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() { | |||
474 | use {Foo, Bar}; | 543 | use {Foo, Bar}; |
475 | 544 | ||
476 | //- /std.rs crate:std deps:core | 545 | //- /std.rs crate:std deps:core |
477 | #[prelude_import] | 546 | pub mod prelude { |
478 | pub use self::prelude::*; | 547 | pub mod rust_2018 { |
479 | mod 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] | 554 | pub mod prelude { |
486 | pub use self::prelude::*; | 555 | pub mod rust_2018 { |
487 | mod 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() { | |||
504 | use {Foo, Bar, Baz}; | 573 | use {Foo, Bar, Baz}; |
505 | 574 | ||
506 | //- /lib.rs crate:std | 575 | //- /lib.rs crate:std |
507 | #[prelude_import] | 576 | pub mod prelude { |
508 | pub use self::prelude::*; | 577 | pub mod rust_2018 { |
509 | mod 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() { | |||
532 | use {Foo, Bar, Baz}; | 601 | use {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] | 604 | pub mod prelude { |
536 | pub use self::prelude::*; | 605 | pub mod rust_2018 { |
537 | mod 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 |
268 | structs!(Foo); | 268 | structs!(Foo); |
269 | structs_priv!(Bar); | 269 | structs_priv!(Bar); |
270 | structs_outside!(Out); | 270 | structs_outside!(Out); |
@@ -276,21 +276,20 @@ mod bar; | |||
276 | structs!(Baz); | 276 | structs!(Baz); |
277 | crate::structs!(MacroNotResolved3); | 277 | crate::structs!(MacroNotResolved3); |
278 | 278 | ||
279 | //- /lib.rs crate:foo | 279 | //- /lib.rs crate:std |
280 | #[prelude_import] | 280 | pub mod prelude { |
281 | use self::prelude::*; | 281 | pub mod rust_2018 { |
282 | |||
283 | mod 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() { | |||
617 | foo!(); | 616 | foo!(); |
618 | 617 | ||
619 | //- /std.rs crate:std deps:core | 618 | //- /std.rs crate:std deps:core |
620 | #[prelude_import] | ||
621 | use self::prelude::*; | ||
622 | |||
623 | pub use core::foo; | 619 | pub use core::foo; |
624 | 620 | ||
625 | mod prelude {} | 621 | pub mod prelude { |
622 | pub mod rust_2018 {} | ||
623 | } | ||
626 | 624 | ||
627 | #[macro_use] | 625 | #[macro_use] |
628 | mod std_macros; | 626 | mod std_macros; |