Skip to content

Commit 1526eb2

Browse files
committed
Import the prelude
1 parent 65266c6 commit 1526eb2

File tree

7 files changed

+99
-12
lines changed

7 files changed

+99
-12
lines changed

crates/ra_hir/src/marks.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ test_utils::marks!(
66
type_var_resolves_to_int_var
77
glob_enum
88
glob_across_crates
9+
std_prelude
910
);

crates/ra_hir/src/nameres.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ use crate::{
3434
/// module, the set of visible items.
3535
#[derive(Default, Debug, PartialEq, Eq)]
3636
pub struct ItemMap {
37+
/// The prelude module for this crate. This either comes from an import
38+
/// marked with the `prelude_import` attribute, or (in the normal case) from
39+
/// a dependency (`std` or `core`).
40+
prelude: Option<Module>,
3741
pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>,
3842
per_module: ArenaMap<ModuleId, ModuleScope>,
3943
}
@@ -211,6 +215,13 @@ where
211215
if let Some(module) = dep.krate.root_module(self.db) {
212216
self.result.extern_prelude.insert(dep.name.clone(), module.into());
213217
}
218+
// look for the prelude
219+
if self.result.prelude.is_none() {
220+
let item_map = self.db.item_map(dep.krate);
221+
if item_map.prelude.is_some() {
222+
self.result.prelude = item_map.prelude;
223+
}
224+
}
214225
}
215226
}
216227

@@ -279,7 +290,10 @@ where
279290
log::debug!("glob import: {:?}", import);
280291
match def.take_types() {
281292
Some(ModuleDef::Module(m)) => {
282-
if m.krate != self.krate {
293+
if import.is_prelude {
294+
tested_by!(std_prelude);
295+
self.result.prelude = Some(m);
296+
} else if m.krate != self.krate {
283297
tested_by!(glob_across_crates);
284298
// glob import from other crate => we can just import everything once
285299
let item_map = self.db.item_map(m.krate);
@@ -434,12 +448,40 @@ impl ItemMap {
434448
self.resolve_path_fp(db, original_module, path).0
435449
}
436450

437-
pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs<ModuleDef> {
451+
fn resolve_in_prelude(
452+
&self,
453+
db: &impl PersistentHirDatabase,
454+
original_module: Module,
455+
name: &Name,
456+
) -> PerNs<ModuleDef> {
457+
if let Some(prelude) = self.prelude {
458+
let resolution = if prelude.krate == original_module.krate {
459+
self[prelude.module_id].items.get(name).cloned()
460+
} else {
461+
db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
462+
};
463+
resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
464+
} else {
465+
PerNs::none()
466+
}
467+
}
468+
469+
pub(crate) fn resolve_name_in_module(
470+
&self,
471+
db: &impl PersistentHirDatabase,
472+
module: Module,
473+
name: &Name,
474+
) -> PerNs<ModuleDef> {
475+
// Resolve in:
476+
// - current module / scope
477+
// - extern prelude
478+
// - std prelude
438479
let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
439480
let from_extern_prelude =
440481
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
482+
let from_prelude = self.resolve_in_prelude(db, module, name);
441483

442-
from_scope.or(from_extern_prelude)
484+
from_scope.or(from_extern_prelude).or(from_prelude)
443485
}
444486

445487
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -459,7 +501,7 @@ impl ItemMap {
459501
Some((_, segment)) => segment,
460502
None => return (PerNs::none(), ReachedFixedPoint::Yes),
461503
};
462-
self.resolve_name_in_module(original_module, &segment.name)
504+
self.resolve_name_in_module(db, original_module, &segment.name)
463505
}
464506
PathKind::Super => {
465507
if let Some(p) = original_module.parent(db) {

crates/ra_hir/src/nameres/lower.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::sync::Arc;
22

33
use ra_syntax::{
44
AstNode, SourceFile, TreeArc, AstPtr,
5-
ast::{self, ModuleItemOwner, NameOwner},
5+
ast::{self, ModuleItemOwner, NameOwner, AttrsOwner},
66
};
77
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
88
use rustc_hash::FxHashMap;
@@ -23,6 +23,7 @@ pub(super) struct ImportData {
2323
pub(super) path: Path,
2424
pub(super) alias: Option<Name>,
2525
pub(super) is_glob: bool,
26+
pub(super) is_prelude: bool,
2627
pub(super) is_extern_crate: bool,
2728
}
2829

@@ -191,6 +192,7 @@ impl LoweredModule {
191192
path,
192193
alias,
193194
is_glob: false,
195+
is_prelude: false,
194196
is_extern_crate: true,
195197
});
196198
}
@@ -214,11 +216,14 @@ impl LoweredModule {
214216
}
215217

216218
fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
219+
let is_prelude =
220+
item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
217221
Path::expand_use_item(item, |path, segment, alias| {
218222
let import = self.imports.alloc(ImportData {
219223
path,
220224
alias,
221225
is_glob: segment.is_none(),
226+
is_prelude,
222227
is_extern_crate: false,
223228
});
224229
if let Some(segment) = segment {

crates/ra_hir/src/nameres/tests.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,43 @@ fn module_resolution_works_for_non_standard_filenames() {
296296
);
297297
}
298298

299+
#[test]
300+
fn std_prelude() {
301+
covers!(std_prelude);
302+
let mut db = MockDatabase::with_files(
303+
"
304+
//- /main.rs
305+
use Foo::*;
306+
307+
//- /lib.rs
308+
mod prelude;
309+
#[prelude_import]
310+
use prelude::*;
311+
312+
//- /prelude.rs
313+
pub enum Foo { Bar, Baz };
314+
",
315+
);
316+
db.set_crate_graph_from_fixture(crate_graph! {
317+
"main": ("/main.rs", ["test_crate"]),
318+
"test_crate": ("/lib.rs", []),
319+
});
320+
let main_id = db.file_id_of("/main.rs");
321+
322+
let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
323+
let krate = module.krate(&db).unwrap();
324+
let item_map = db.item_map(krate);
325+
326+
check_module_item_map(
327+
&item_map,
328+
module.module_id,
329+
"
330+
Bar: t v
331+
Baz: t v
332+
",
333+
);
334+
}
335+
299336
#[test]
300337
fn name_res_works_for_broken_modules() {
301338
covers!(name_res_works_for_broken_modules);

crates/ra_hir/src/resolve.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ pub enum Resolution {
5656
}
5757

5858
impl Resolver {
59-
pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> {
59+
pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
6060
let mut resolution = PerNs::none();
6161
for scope in self.scopes.iter().rev() {
62-
resolution = resolution.or(scope.resolve_name(name));
62+
resolution = resolution.or(scope.resolve_name(db, name));
6363
if resolution.is_both() {
6464
return resolution;
6565
}
@@ -69,9 +69,9 @@ impl Resolver {
6969

7070
pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
7171
if let Some(name) = path.as_ident() {
72-
self.resolve_name(name)
72+
self.resolve_name(db, name)
7373
} else if path.is_self() {
74-
self.resolve_name(&Name::self_param())
74+
self.resolve_name(db, &Name::self_param())
7575
} else {
7676
let (item_map, module) = match self.module() {
7777
Some(m) => m,
@@ -143,13 +143,13 @@ impl Resolver {
143143
}
144144

145145
impl Scope {
146-
fn resolve_name(&self, name: &Name) -> PerNs<Resolution> {
146+
fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
147147
match self {
148148
Scope::ModuleScope(m) => {
149149
if let Some(KnownName::SelfParam) = name.as_known_name() {
150150
PerNs::types(Resolution::Def(m.module.into()))
151151
} else {
152-
m.item_map.resolve_name_in_module(m.module, name).map(Resolution::Def)
152+
m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def)
153153
}
154154
}
155155
Scope::GenericParams(gp) => match gp.find_by_name(name) {

crates/ra_syntax/src/ast/generated.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4210,6 +4210,7 @@ impl ToOwned for UseItem {
42104210
}
42114211

42124212

4213+
impl ast::AttrsOwner for UseItem {}
42134214
impl UseItem {
42144215
pub fn use_tree(&self) -> Option<&UseTree> {
42154216
super::child_opt(self)

crates/ra_syntax/src/grammar.ron

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,8 @@ Grammar(
596596
options: [ "Pat", "TypeRef" ],
597597
),
598598
"UseItem": (
599-
options: [ "UseTree" ]
599+
traits: ["AttrsOwner"],
600+
options: [ "UseTree" ],
600601
),
601602
"UseTree": (
602603
options: [ "Path", "UseTreeList", "Alias" ]

0 commit comments

Comments
 (0)