Skip to content

Commit 741e5d5

Browse files
committed
Resolve 2015 style imports
1 parent 15d9ea2 commit 741e5d5

File tree

5 files changed

+114
-8
lines changed

5 files changed

+114
-8
lines changed

crates/ra_db/src/input.rs

+4
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ impl CrateGraph {
119119
self.arena[&crate_id].file_id
120120
}
121121

122+
pub fn edition(&self, crate_id: CrateId) -> Edition {
123+
self.arena[&crate_id].edition
124+
}
125+
122126
// TODO: this only finds one crate with the given root; we could have multiple
123127
pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
124128
let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;

crates/ra_hir/src/code_model_api.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::sync::Arc;
22

33
use relative_path::RelativePathBuf;
4-
use ra_db::{CrateId, FileId, SourceRootId};
4+
use ra_db::{CrateId, FileId, SourceRootId, Edition};
55
use ra_syntax::{ast::self, TreeArc, SyntaxNode};
66

77
use crate::{
@@ -38,13 +38,20 @@ impl Crate {
3838
pub fn crate_id(&self) -> CrateId {
3939
self.crate_id
4040
}
41+
4142
pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> {
4243
self.dependencies_impl(db)
4344
}
45+
4446
pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
4547
self.root_module_impl(db)
4648
}
4749

50+
pub fn edition(&self, db: &impl PersistentHirDatabase) -> Edition {
51+
let crate_graph = db.crate_graph();
52+
crate_graph.edition(self.crate_id)
53+
}
54+
4855
// TODO: should this be in source_binder?
4956
pub fn source_root_crates(
5057
db: &impl PersistentHirDatabase,

crates/ra_hir/src/nameres.rs

+56-7
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ pub(crate) mod lower;
1818

1919
use std::{time, sync::Arc};
2020

21+
use rustc_hash::{FxHashMap, FxHashSet};
22+
2123
use ra_arena::map::ArenaMap;
24+
use ra_db::Edition;
2225
use test_utils::tested_by;
23-
use rustc_hash::{FxHashMap, FxHashSet};
2426

2527
use crate::{
2628
Module, ModuleDef,
@@ -32,8 +34,9 @@ use crate::{
3234

3335
/// `ItemMap` is the result of module name resolution. It contains, for each
3436
/// module, the set of visible items.
35-
#[derive(Default, Debug, PartialEq, Eq)]
37+
#[derive(Debug, PartialEq, Eq)]
3638
pub struct ItemMap {
39+
edition: Edition,
3740
/// The prelude module for this crate. This either comes from an import
3841
/// marked with the `prelude_import` attribute, or (in the normal case) from
3942
/// a dependency (`std` or `core`).
@@ -180,7 +183,12 @@ where
180183
module_tree,
181184
processed_imports: FxHashSet::default(),
182185
glob_imports: FxHashMap::default(),
183-
result: ItemMap::default(),
186+
result: ItemMap {
187+
edition: krate.edition(db),
188+
prelude: None,
189+
extern_prelude: FxHashMap::default(),
190+
per_module: ArenaMap::default(),
191+
},
184192
}
185193
}
186194

@@ -277,10 +285,14 @@ where
277285
import_id: ImportId,
278286
import: &ImportData,
279287
) -> ReachedFixedPoint {
280-
log::debug!("resolving import: {:?}", import);
288+
log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
281289
let original_module = Module { krate: self.krate, module_id };
282-
let (def, reached_fixedpoint) =
283-
self.result.resolve_path_fp(self.db, original_module, &import.path);
290+
let (def, reached_fixedpoint) = self.result.resolve_path_fp(
291+
self.db,
292+
ResolveMode::Import,
293+
original_module,
294+
&import.path,
295+
);
284296

285297
if reached_fixedpoint != ReachedFixedPoint::Yes {
286298
return reached_fixedpoint;
@@ -417,6 +429,12 @@ where
417429
}
418430
}
419431

432+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
433+
enum ResolveMode {
434+
Import,
435+
Other,
436+
}
437+
420438
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
421439
enum ReachedFixedPoint {
422440
Yes,
@@ -445,7 +463,7 @@ impl ItemMap {
445463
original_module: Module,
446464
path: &Path,
447465
) -> PerNs<ModuleDef> {
448-
self.resolve_path_fp(db, original_module, path).0
466+
self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0
449467
}
450468

451469
fn resolve_in_prelude(
@@ -484,23 +502,54 @@ impl ItemMap {
484502
from_scope.or(from_extern_prelude).or(from_prelude)
485503
}
486504

505+
fn resolve_name_in_crate_root_or_extern_prelude(
506+
&self,
507+
db: &impl PersistentHirDatabase,
508+
module: Module,
509+
name: &Name,
510+
) -> PerNs<ModuleDef> {
511+
let crate_root = module.crate_root(db);
512+
let from_crate_root = self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
513+
let from_extern_prelude =
514+
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
515+
516+
from_crate_root.or(from_extern_prelude)
517+
}
518+
487519
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
488520
// the result.
489521
fn resolve_path_fp(
490522
&self,
491523
db: &impl PersistentHirDatabase,
524+
mode: ResolveMode,
492525
original_module: Module,
493526
path: &Path,
494527
) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
495528
let mut segments = path.segments.iter().enumerate();
496529
let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
497530
PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
498531
PathKind::Self_ => PerNs::types(original_module.into()),
532+
// plain import or absolute path in 2015: crate-relative with
533+
// fallback to extern prelude (with the simplification in
534+
// rust-lang/rust#57745)
535+
// TODO there must be a nicer way to write this condition
536+
PathKind::Plain | PathKind::Abs
537+
if self.edition == Edition::Edition2015
538+
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
539+
{
540+
let segment = match segments.next() {
541+
Some((_, segment)) => segment,
542+
None => return (PerNs::none(), ReachedFixedPoint::Yes),
543+
};
544+
log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
545+
self.resolve_name_in_crate_root_or_extern_prelude(db, original_module, &segment.name)
546+
}
499547
PathKind::Plain => {
500548
let segment = match segments.next() {
501549
Some((_, segment)) => segment,
502550
None => return (PerNs::none(), ReachedFixedPoint::Yes),
503551
};
552+
log::debug!("resolving {:?} in module", segment);
504553
self.resolve_name_in_module(db, original_module, &segment.name)
505554
}
506555
PathKind::Super => {

crates/ra_hir/src/nameres/tests.rs

+45
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,51 @@ fn glob_across_crates() {
265265
);
266266
}
267267

268+
#[test]
269+
fn edition_2015_imports() {
270+
use ra_db::{CrateGraph, Edition};
271+
let mut db = MockDatabase::with_files(
272+
"
273+
//- /main.rs
274+
mod foo;
275+
mod bar;
276+
277+
//- /bar.rs
278+
struct Bar;
279+
280+
//- /foo.rs
281+
use bar::Bar;
282+
use other_crate::FromLib;
283+
284+
//- /lib.rs
285+
struct FromLib;
286+
",
287+
);
288+
let main_id = db.file_id_of("/main.rs");
289+
let lib_id = db.file_id_of("/lib.rs");
290+
let foo_id = db.file_id_of("/foo.rs");
291+
292+
let mut crate_graph = CrateGraph::default();
293+
let main_crate = crate_graph.add_crate_root(main_id, Edition::Edition2015);
294+
let lib_crate = crate_graph.add_crate_root(lib_id, Edition::Edition2018);
295+
crate_graph.add_dep(main_crate, "other_crate".into(), lib_crate).unwrap();
296+
297+
db.set_crate_graph(Arc::new(crate_graph));
298+
299+
let module = crate::source_binder::module_from_file_id(&db, foo_id).unwrap();
300+
let krate = module.krate(&db).unwrap();
301+
let item_map = db.item_map(krate);
302+
303+
check_module_item_map(
304+
&item_map,
305+
module.module_id,
306+
"
307+
Bar: t v
308+
FromLib: t v
309+
",
310+
);
311+
}
312+
268313
#[test]
269314
fn module_resolution_works_for_non_standard_filenames() {
270315
let mut db = MockDatabase::with_files(

crates/ra_project_model/src/sysroot.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{
22
path::{Path, PathBuf},
33
process::Command,
4+
vec::Vec
45
};
56

67
use ra_arena::{Arena, RawId, impl_arena_id};

0 commit comments

Comments
 (0)