aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-13 20:14:39 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-13 20:14:39 +0000
commitcb4327b3a9f0858235dc20b7c5c7e25c6c330aab (patch)
tree489b3497b2762dcabf60d2674031585431e16959 /crates
parent65266c644a31e6b321e5afb3c5a2ee75be76cb0c (diff)
parent911e32bca9b73e66eceb6bbee3768c82e94597d5 (diff)
Merge #816
816: Prelude & Edition 2015 import resolution r=matklad a=flodiebold I implemented the prelude import, but it turned out to be useless without being able to resolve any of the imports in the prelude :sweat_smile: So I had to add some edition handling and handle 2015-style imports (at least the simplified scheme proposed in rust-lang/rust#57745). So now finally `Option` resolves :smile: One remaining problem is that we don't actually know the edition for sysroot crates. They're currently hardcoded to 2015, but there's already a bunch of PRs upgrading the editions of various rustc crates, so we'll have to detect the edition somehow, or just change the hardcoding to 2018 later, I guess... ~Also currently missing is completion for prelude names, though that shouldn't be hard to add. And `Vec` still doesn't resolve, so I need to look into that.~ Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_db/src/input.rs44
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/code_model_api.rs9
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/mock.rs18
-rw-r--r--crates/ra_hir/src/nameres.rs127
-rw-r--r--crates/ra_hir/src/nameres/lower.rs16
-rw-r--r--crates/ra_hir/src/nameres/tests.rs112
-rw-r--r--crates/ra_hir/src/resolve.rs24
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs21
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap54
-rw-r--r--crates/ra_ide_api/src/lib.rs3
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs6
-rw-r--r--crates/ra_ide_api/tests/test/main.rs4
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs6
-rw-r--r--crates/ra_project_model/src/lib.rs8
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1
-rw-r--r--crates/ra_syntax/src/grammar.ron3
18 files changed, 399 insertions, 60 deletions
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 8decc65c5..e45a510b3 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -56,15 +56,31 @@ pub struct CyclicDependencies;
56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
57pub struct CrateId(pub u32); 57pub struct CrateId(pub u32);
58 58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60pub enum Edition {
61 Edition2018,
62 Edition2015,
63}
64
65impl Edition {
66 pub fn from_string(s: &str) -> Edition {
67 match s {
68 "2015" => Edition::Edition2015,
69 "2018" | _ => Edition::Edition2018,
70 }
71 }
72}
73
59#[derive(Debug, Clone, PartialEq, Eq)] 74#[derive(Debug, Clone, PartialEq, Eq)]
60struct CrateData { 75struct CrateData {
61 file_id: FileId, 76 file_id: FileId,
77 edition: Edition,
62 dependencies: Vec<Dependency>, 78 dependencies: Vec<Dependency>,
63} 79}
64 80
65impl CrateData { 81impl CrateData {
66 fn new(file_id: FileId) -> CrateData { 82 fn new(file_id: FileId, edition: Edition) -> CrateData {
67 CrateData { file_id, dependencies: Vec::new() } 83 CrateData { file_id, edition, dependencies: Vec::new() }
68 } 84 }
69 85
70 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 86 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
@@ -85,9 +101,9 @@ impl Dependency {
85} 101}
86 102
87impl CrateGraph { 103impl CrateGraph {
88 pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { 104 pub fn add_crate_root(&mut self, file_id: FileId, edition: Edition) -> CrateId {
89 let crate_id = CrateId(self.arena.len() as u32); 105 let crate_id = CrateId(self.arena.len() as u32);
90 let prev = self.arena.insert(crate_id, CrateData::new(file_id)); 106 let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition));
91 assert!(prev.is_none()); 107 assert!(prev.is_none());
92 crate_id 108 crate_id
93 } 109 }
@@ -112,6 +128,10 @@ impl CrateGraph {
112 self.arena[&crate_id].file_id 128 self.arena[&crate_id].file_id
113 } 129 }
114 130
131 pub fn edition(&self, crate_id: CrateId) -> Edition {
132 self.arena[&crate_id].edition
133 }
134
115 // TODO: this only finds one crate with the given root; we could have multiple 135 // TODO: this only finds one crate with the given root; we could have multiple
116 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 136 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
117 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; 137 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
@@ -159,14 +179,14 @@ impl CrateGraph {
159 179
160#[cfg(test)] 180#[cfg(test)]
161mod tests { 181mod tests {
162 use super::{CrateGraph, FileId, SmolStr}; 182 use super::{CrateGraph, FileId, SmolStr, Edition::Edition2018};
163 183
164 #[test] 184 #[test]
165 fn it_should_painc_because_of_cycle_dependencies() { 185 fn it_should_panic_because_of_cycle_dependencies() {
166 let mut graph = CrateGraph::default(); 186 let mut graph = CrateGraph::default();
167 let crate1 = graph.add_crate_root(FileId(1u32)); 187 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018);
168 let crate2 = graph.add_crate_root(FileId(2u32)); 188 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018);
169 let crate3 = graph.add_crate_root(FileId(3u32)); 189 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018);
170 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 190 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
171 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 191 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
172 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err()); 192 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err());
@@ -175,9 +195,9 @@ mod tests {
175 #[test] 195 #[test]
176 fn it_works() { 196 fn it_works() {
177 let mut graph = CrateGraph::default(); 197 let mut graph = CrateGraph::default();
178 let crate1 = graph.add_crate_root(FileId(1u32)); 198 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018);
179 let crate2 = graph.add_crate_root(FileId(2u32)); 199 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018);
180 let crate3 = graph.add_crate_root(FileId(3u32)); 200 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018);
181 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 201 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
182 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 202 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
183 } 203 }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 31442713d..e006c6d27 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -14,7 +14,7 @@ pub use ::salsa as salsa;
14pub use crate::{ 14pub use crate::{
15 cancellation::Canceled, 15 cancellation::Canceled,
16 input::{ 16 input::{
17 FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, 17 FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, Edition,
18 }, 18 },
19 loc2id::LocationIntener, 19 loc2id::LocationIntener,
20}; 20};
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 2ac05c836..fb7ad0867 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use ra_db::{CrateId, FileId, SourceRootId}; 4use ra_db::{CrateId, FileId, SourceRootId, Edition};
5use ra_syntax::{ast::self, TreeArc, SyntaxNode}; 5use ra_syntax::{ast::self, TreeArc, SyntaxNode};
6 6
7use crate::{ 7use crate::{
@@ -38,13 +38,20 @@ impl Crate {
38 pub fn crate_id(&self) -> CrateId { 38 pub fn crate_id(&self) -> CrateId {
39 self.crate_id 39 self.crate_id
40 } 40 }
41
41 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> { 42 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> {
42 self.dependencies_impl(db) 43 self.dependencies_impl(db)
43 } 44 }
45
44 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 46 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
45 self.root_module_impl(db) 47 self.root_module_impl(db)
46 } 48 }
47 49
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
48 // TODO: should this be in source_binder? 55 // TODO: should this be in source_binder?
49 pub fn source_root_crates( 56 pub fn source_root_crates(
50 db: &impl PersistentHirDatabase, 57 db: &impl PersistentHirDatabase,
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 50d4e824c..16852a6a1 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 glob_enum 7 glob_enum
8 glob_across_crates 8 glob_across_crates
9 std_prelude
9); 10);
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 5ca870867..f1cad77c5 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -3,6 +3,7 @@ use std::{sync::Arc, panic};
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use ra_db::{ 4use ra_db::{
5 FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, 5 FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa,
6 Edition,
6}; 7};
7use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 9use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
@@ -58,12 +59,12 @@ impl MockDatabase {
58 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { 59 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) {
59 let mut ids = FxHashMap::default(); 60 let mut ids = FxHashMap::default();
60 let mut crate_graph = CrateGraph::default(); 61 let mut crate_graph = CrateGraph::default();
61 for (crate_name, (crate_root, _)) in graph.0.iter() { 62 for (crate_name, (crate_root, edition, _)) in graph.0.iter() {
62 let crate_root = self.file_id_of(&crate_root); 63 let crate_root = self.file_id_of(&crate_root);
63 let crate_id = crate_graph.add_crate_root(crate_root); 64 let crate_id = crate_graph.add_crate_root(crate_root, *edition);
64 ids.insert(crate_name, crate_id); 65 ids.insert(crate_name, crate_id);
65 } 66 }
66 for (crate_name, (_, deps)) in graph.0.iter() { 67 for (crate_name, (_, _, deps)) in graph.0.iter() {
67 let from = ids[crate_name]; 68 let from = ids[crate_name];
68 for dep in deps { 69 for dep in deps {
69 let to = ids[dep]; 70 let to = ids[dep];
@@ -144,7 +145,7 @@ impl MockDatabase {
144 145
145 if is_crate_root { 146 if is_crate_root {
146 let mut crate_graph = CrateGraph::default(); 147 let mut crate_graph = CrateGraph::default();
147 crate_graph.add_crate_root(file_id); 148 crate_graph.add_crate_root(file_id, Edition::Edition2018);
148 self.set_crate_graph(Arc::new(crate_graph)); 149 self.set_crate_graph(Arc::new(crate_graph));
149 } 150 }
150 file_id 151 file_id
@@ -232,16 +233,19 @@ impl MockDatabase {
232} 233}
233 234
234#[derive(Default)] 235#[derive(Default)]
235pub struct CrateGraphFixture(pub FxHashMap<String, (String, Vec<String>)>); 236pub struct CrateGraphFixture(pub FxHashMap<String, (String, Edition, Vec<String>)>);
236 237
237#[macro_export] 238#[macro_export]
238macro_rules! crate_graph { 239macro_rules! crate_graph {
239 ($($crate_name:literal: ($crate_path:literal, [$($dep:literal),*]),)*) => {{ 240 ($($crate_name:literal: ($crate_path:literal, $($edition:literal,)? [$($dep:literal),*]),)*) => {{
240 let mut res = $crate::mock::CrateGraphFixture::default(); 241 let mut res = $crate::mock::CrateGraphFixture::default();
241 $( 242 $(
243 #[allow(unused_mut, unused_assignments)]
244 let mut edition = ra_db::Edition::Edition2018;
245 $(edition = ra_db::Edition::from_string($edition);)?
242 res.0.insert( 246 res.0.insert(
243 $crate_name.to_string(), 247 $crate_name.to_string(),
244 ($crate_path.to_string(), vec![$($dep.to_string()),*]) 248 ($crate_path.to_string(), edition, vec![$($dep.to_string()),*])
245 ); 249 );
246 )* 250 )*
247 res 251 res
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index ffb20d564..e35b4b129 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -18,9 +18,11 @@ pub(crate) mod lower;
18 18
19use std::{time, sync::Arc}; 19use std::{time, sync::Arc};
20 20
21use rustc_hash::{FxHashMap, FxHashSet};
22
21use ra_arena::map::ArenaMap; 23use ra_arena::map::ArenaMap;
24use ra_db::Edition;
22use test_utils::tested_by; 25use test_utils::tested_by;
23use rustc_hash::{FxHashMap, FxHashSet};
24 26
25use crate::{ 27use crate::{
26 Module, ModuleDef, 28 Module, ModuleDef,
@@ -32,8 +34,13 @@ use crate::{
32 34
33/// `ItemMap` is the result of module name resolution. It contains, for each 35/// `ItemMap` is the result of module name resolution. It contains, for each
34/// module, the set of visible items. 36/// module, the set of visible items.
35#[derive(Default, Debug, PartialEq, Eq)] 37#[derive(Debug, PartialEq, Eq)]
36pub struct ItemMap { 38pub struct ItemMap {
39 edition: Edition,
40 /// The prelude module for this crate. This either comes from an import
41 /// marked with the `prelude_import` attribute, or (in the normal case) from
42 /// a dependency (`std` or `core`).
43 pub(crate) prelude: Option<Module>,
37 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, 44 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>,
38 per_module: ArenaMap<ModuleId, ModuleScope>, 45 per_module: ArenaMap<ModuleId, ModuleScope>,
39} 46}
@@ -176,7 +183,12 @@ where
176 module_tree, 183 module_tree,
177 processed_imports: FxHashSet::default(), 184 processed_imports: FxHashSet::default(),
178 glob_imports: FxHashMap::default(), 185 glob_imports: FxHashMap::default(),
179 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 },
180 } 192 }
181 } 193 }
182 194
@@ -211,6 +223,13 @@ where
211 if let Some(module) = dep.krate.root_module(self.db) { 223 if let Some(module) = dep.krate.root_module(self.db) {
212 self.result.extern_prelude.insert(dep.name.clone(), module.into()); 224 self.result.extern_prelude.insert(dep.name.clone(), module.into());
213 } 225 }
226 // look for the prelude
227 if self.result.prelude.is_none() {
228 let item_map = self.db.item_map(dep.krate);
229 if item_map.prelude.is_some() {
230 self.result.prelude = item_map.prelude;
231 }
232 }
214 } 233 }
215 } 234 }
216 235
@@ -266,10 +285,20 @@ where
266 import_id: ImportId, 285 import_id: ImportId,
267 import: &ImportData, 286 import: &ImportData,
268 ) -> ReachedFixedPoint { 287 ) -> ReachedFixedPoint {
269 log::debug!("resolving import: {:?}", import); 288 log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
270 let original_module = Module { krate: self.krate, module_id }; 289 let original_module = Module { krate: self.krate, module_id };
271 let (def, reached_fixedpoint) = 290
272 self.result.resolve_path_fp(self.db, original_module, &import.path); 291 let (def, reached_fixedpoint) = if import.is_extern_crate {
292 let res = self.result.resolve_name_in_extern_prelude(
293 &import
294 .path
295 .as_ident()
296 .expect("extern crate should have been desugared to one-element path"),
297 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else {
300 self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path)
301 };
273 302
274 if reached_fixedpoint != ReachedFixedPoint::Yes { 303 if reached_fixedpoint != ReachedFixedPoint::Yes {
275 return reached_fixedpoint; 304 return reached_fixedpoint;
@@ -279,7 +308,10 @@ where
279 log::debug!("glob import: {:?}", import); 308 log::debug!("glob import: {:?}", import);
280 match def.take_types() { 309 match def.take_types() {
281 Some(ModuleDef::Module(m)) => { 310 Some(ModuleDef::Module(m)) => {
282 if m.krate != self.krate { 311 if import.is_prelude {
312 tested_by!(std_prelude);
313 self.result.prelude = Some(m);
314 } else if m.krate != self.krate {
283 tested_by!(glob_across_crates); 315 tested_by!(glob_across_crates);
284 // glob import from other crate => we can just import everything once 316 // glob import from other crate => we can just import everything once
285 let item_map = self.db.item_map(m.krate); 317 let item_map = self.db.item_map(m.krate);
@@ -404,6 +436,12 @@ where
404} 436}
405 437
406#[derive(Debug, Clone, Copy, PartialEq, Eq)] 438#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439enum ResolveMode {
440 Import,
441 Other,
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Eq)]
407enum ReachedFixedPoint { 445enum ReachedFixedPoint {
408 Yes, 446 Yes,
409 No, 447 No,
@@ -431,15 +469,61 @@ impl ItemMap {
431 original_module: Module, 469 original_module: Module,
432 path: &Path, 470 path: &Path,
433 ) -> PerNs<ModuleDef> { 471 ) -> PerNs<ModuleDef> {
434 self.resolve_path_fp(db, original_module, path).0 472 self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0
473 }
474
475 fn resolve_in_prelude(
476 &self,
477 db: &impl PersistentHirDatabase,
478 original_module: Module,
479 name: &Name,
480 ) -> PerNs<ModuleDef> {
481 if let Some(prelude) = self.prelude {
482 let resolution = if prelude.krate == original_module.krate {
483 self[prelude.module_id].items.get(name).cloned()
484 } else {
485 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
486 };
487 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
488 } else {
489 PerNs::none()
490 }
435 } 491 }
436 492
437 pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs<ModuleDef> { 493 pub(crate) fn resolve_name_in_module(
494 &self,
495 db: &impl PersistentHirDatabase,
496 module: Module,
497 name: &Name,
498 ) -> PerNs<ModuleDef> {
499 // Resolve in:
500 // - current module / scope
501 // - extern prelude
502 // - std prelude
438 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); 503 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
439 let from_extern_prelude = 504 let from_extern_prelude =
440 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 505 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
506 let from_prelude = self.resolve_in_prelude(db, module, name);
507
508 from_scope.or(from_extern_prelude).or(from_prelude)
509 }
510
511 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
512 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
513 }
441 514
442 from_scope.or(from_extern_prelude) 515 fn resolve_name_in_crate_root_or_extern_prelude(
516 &self,
517 db: &impl PersistentHirDatabase,
518 module: Module,
519 name: &Name,
520 ) -> PerNs<ModuleDef> {
521 let crate_root = module.crate_root(db);
522 let from_crate_root =
523 self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
524 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
525
526 from_crate_root.or(from_extern_prelude)
443 } 527 }
444 528
445 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 529 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -447,6 +531,7 @@ impl ItemMap {
447 fn resolve_path_fp( 531 fn resolve_path_fp(
448 &self, 532 &self,
449 db: &impl PersistentHirDatabase, 533 db: &impl PersistentHirDatabase,
534 mode: ResolveMode,
450 original_module: Module, 535 original_module: Module,
451 path: &Path, 536 path: &Path,
452 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 537 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
@@ -454,12 +539,32 @@ impl ItemMap {
454 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 539 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
455 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 540 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
456 PathKind::Self_ => PerNs::types(original_module.into()), 541 PathKind::Self_ => PerNs::types(original_module.into()),
542 // plain import or absolute path in 2015: crate-relative with
543 // fallback to extern prelude (with the simplification in
544 // rust-lang/rust#57745)
545 // TODO there must be a nicer way to write this condition
546 PathKind::Plain | PathKind::Abs
547 if self.edition == Edition::Edition2015
548 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
549 {
550 let segment = match segments.next() {
551 Some((_, segment)) => segment,
552 None => return (PerNs::none(), ReachedFixedPoint::Yes),
553 };
554 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
555 self.resolve_name_in_crate_root_or_extern_prelude(
556 db,
557 original_module,
558 &segment.name,
559 )
560 }
457 PathKind::Plain => { 561 PathKind::Plain => {
458 let segment = match segments.next() { 562 let segment = match segments.next() {
459 Some((_, segment)) => segment, 563 Some((_, segment)) => segment,
460 None => return (PerNs::none(), ReachedFixedPoint::Yes), 564 None => return (PerNs::none(), ReachedFixedPoint::Yes),
461 }; 565 };
462 self.resolve_name_in_module(original_module, &segment.name) 566 log::debug!("resolving {:?} in module", segment);
567 self.resolve_name_in_module(db, original_module, &segment.name)
463 } 568 }
464 PathKind::Super => { 569 PathKind::Super => {
465 if let Some(p) = original_module.parent(db) { 570 if let Some(p) = original_module.parent(db) {
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index 3cd496d7f..81d80654c 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -2,13 +2,13 @@ use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SourceFile, TreeArc, AstPtr, 4 AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner, NameOwner}, 5 ast::{self, ModuleItemOwner, NameOwner, AttrsOwner},
6}; 6};
7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9 9
10use crate::{ 10use crate::{
11 SourceItemId, Path, PathKind, ModuleSource, Name, 11 SourceItemId, Path, ModuleSource, Name,
12 HirFileId, MacroCallLoc, AsName, PerNs, Function, 12 HirFileId, MacroCallLoc, AsName, PerNs, Function,
13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type, 13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
14 ids::LocationCtx, PersistentHirDatabase, 14 ids::LocationCtx, PersistentHirDatabase,
@@ -23,6 +23,7 @@ pub(super) struct ImportData {
23 pub(super) path: Path, 23 pub(super) path: Path,
24 pub(super) alias: Option<Name>, 24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool, 25 pub(super) is_glob: bool,
26 pub(super) is_prelude: bool,
26 pub(super) is_extern_crate: bool, 27 pub(super) is_extern_crate: bool,
27} 28}
28 29
@@ -179,18 +180,14 @@ impl LoweredModule {
179 self.add_use_item(source_map, it); 180 self.add_use_item(source_map, it);
180 } 181 }
181 ast::ModuleItemKind::ExternCrateItem(it) => { 182 ast::ModuleItemKind::ExternCrateItem(it) => {
182 // Lower `extern crate x` to `use ::x`. This is kind of cheating
183 // and only works if we always interpret absolute paths in the
184 // 2018 style; otherwise `::x` could also refer to a module in
185 // the crate root.
186 if let Some(name_ref) = it.name_ref() { 183 if let Some(name_ref) = it.name_ref() {
187 let mut path = Path::from_name_ref(name_ref); 184 let path = Path::from_name_ref(name_ref);
188 path.kind = PathKind::Abs;
189 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name); 185 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
190 self.imports.alloc(ImportData { 186 self.imports.alloc(ImportData {
191 path, 187 path,
192 alias, 188 alias,
193 is_glob: false, 189 is_glob: false,
190 is_prelude: false,
194 is_extern_crate: true, 191 is_extern_crate: true,
195 }); 192 });
196 } 193 }
@@ -214,11 +211,14 @@ impl LoweredModule {
214 } 211 }
215 212
216 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { 213 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
214 let is_prelude =
215 item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
217 Path::expand_use_item(item, |path, segment, alias| { 216 Path::expand_use_item(item, |path, segment, alias| {
218 let import = self.imports.alloc(ImportData { 217 let import = self.imports.alloc(ImportData {
219 path, 218 path,
220 alias, 219 alias,
221 is_glob: segment.is_none(), 220 is_glob: segment.is_none(),
221 is_prelude,
222 is_extern_crate: false, 222 is_extern_crate: false,
223 }); 223 });
224 if let Some(segment) = segment { 224 if let Some(segment) = segment {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 6dbe759d1..6402c89c0 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -266,6 +266,45 @@ fn glob_across_crates() {
266} 266}
267 267
268#[test] 268#[test]
269fn edition_2015_imports() {
270 let mut db = MockDatabase::with_files(
271 "
272 //- /main.rs
273 mod foo;
274 mod bar;
275
276 //- /bar.rs
277 struct Bar;
278
279 //- /foo.rs
280 use bar::Bar;
281 use other_crate::FromLib;
282
283 //- /lib.rs
284 struct FromLib;
285 ",
286 );
287 db.set_crate_graph_from_fixture(crate_graph! {
288 "main": ("/main.rs", "2015", ["other_crate"]),
289 "other_crate": ("/lib.rs", "2018", []),
290 });
291 let foo_id = db.file_id_of("/foo.rs");
292
293 let module = crate::source_binder::module_from_file_id(&db, foo_id).unwrap();
294 let krate = module.krate(&db).unwrap();
295 let item_map = db.item_map(krate);
296
297 check_module_item_map(
298 &item_map,
299 module.module_id,
300 "
301 Bar: t v
302 FromLib: t v
303 ",
304 );
305}
306
307#[test]
269fn module_resolution_works_for_non_standard_filenames() { 308fn module_resolution_works_for_non_standard_filenames() {
270 let mut db = MockDatabase::with_files( 309 let mut db = MockDatabase::with_files(
271 " 310 "
@@ -297,6 +336,43 @@ fn module_resolution_works_for_non_standard_filenames() {
297} 336}
298 337
299#[test] 338#[test]
339fn std_prelude() {
340 covers!(std_prelude);
341 let mut db = MockDatabase::with_files(
342 "
343 //- /main.rs
344 use Foo::*;
345
346 //- /lib.rs
347 mod prelude;
348 #[prelude_import]
349 use prelude::*;
350
351 //- /prelude.rs
352 pub enum Foo { Bar, Baz };
353 ",
354 );
355 db.set_crate_graph_from_fixture(crate_graph! {
356 "main": ("/main.rs", ["test_crate"]),
357 "test_crate": ("/lib.rs", []),
358 });
359 let main_id = db.file_id_of("/main.rs");
360
361 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
362 let krate = module.krate(&db).unwrap();
363 let item_map = db.item_map(krate);
364
365 check_module_item_map(
366 &item_map,
367 module.module_id,
368 "
369 Bar: t v
370 Baz: t v
371 ",
372 );
373}
374
375#[test]
300fn name_res_works_for_broken_modules() { 376fn name_res_works_for_broken_modules() {
301 covers!(name_res_works_for_broken_modules); 377 covers!(name_res_works_for_broken_modules);
302 let (item_map, module_id) = item_map( 378 let (item_map, module_id) = item_map(
@@ -467,6 +543,42 @@ fn extern_crate_rename() {
467} 543}
468 544
469#[test] 545#[test]
546fn extern_crate_rename_2015_edition() {
547 let mut db = MockDatabase::with_files(
548 "
549 //- /main.rs
550 extern crate alloc as alloc_crate;
551
552 mod alloc;
553 mod sync;
554
555 //- /sync.rs
556 use alloc_crate::Arc;
557
558 //- /lib.rs
559 struct Arc;
560 ",
561 );
562 db.set_crate_graph_from_fixture(crate_graph! {
563 "main": ("/main.rs", "2015", ["alloc"]),
564 "alloc": ("/lib.rs", []),
565 });
566 let sync_id = db.file_id_of("/sync.rs");
567
568 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
569 let krate = module.krate(&db).unwrap();
570 let item_map = db.item_map(krate);
571
572 check_module_item_map(
573 &item_map,
574 module.module_id,
575 "
576 Arc: t v
577 ",
578 );
579}
580
581#[test]
470fn import_across_source_roots() { 582fn import_across_source_roots() {
471 let mut db = MockDatabase::with_files( 583 let mut db = MockDatabase::with_files(
472 " 584 "
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 40c860cf4..91a531801 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -56,10 +56,10 @@ pub enum Resolution {
56} 56}
57 57
58impl Resolver { 58impl Resolver {
59 pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 59 pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
60 let mut resolution = PerNs::none(); 60 let mut resolution = PerNs::none();
61 for scope in self.scopes.iter().rev() { 61 for scope in self.scopes.iter().rev() {
62 resolution = resolution.or(scope.resolve_name(name)); 62 resolution = resolution.or(scope.resolve_name(db, name));
63 if resolution.is_both() { 63 if resolution.is_both() {
64 return resolution; 64 return resolution;
65 } 65 }
@@ -69,9 +69,9 @@ impl Resolver {
69 69
70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { 70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
71 if let Some(name) = path.as_ident() { 71 if let Some(name) = path.as_ident() {
72 self.resolve_name(name) 72 self.resolve_name(db, name)
73 } else if path.is_self() { 73 } else if path.is_self() {
74 self.resolve_name(&Name::self_param()) 74 self.resolve_name(db, &Name::self_param())
75 } else { 75 } else {
76 let (item_map, module) = match self.module() { 76 let (item_map, module) = match self.module() {
77 Some(m) => m, 77 Some(m) => m,
@@ -82,10 +82,10 @@ impl Resolver {
82 } 82 }
83 } 83 }
84 84
85 pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> { 85 pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> {
86 let mut names = FxHashMap::default(); 86 let mut names = FxHashMap::default();
87 for scope in self.scopes.iter().rev() { 87 for scope in self.scopes.iter().rev() {
88 scope.collect_names(&mut |name, res| { 88 scope.collect_names(db, &mut |name, res| {
89 let current: &mut PerNs<Resolution> = names.entry(name).or_default(); 89 let current: &mut PerNs<Resolution> = names.entry(name).or_default();
90 if current.types.is_none() { 90 if current.types.is_none() {
91 current.types = res.types; 91 current.types = res.types;
@@ -143,13 +143,13 @@ impl Resolver {
143} 143}
144 144
145impl Scope { 145impl Scope {
146 fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 146 fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
147 match self { 147 match self {
148 Scope::ModuleScope(m) => { 148 Scope::ModuleScope(m) => {
149 if let Some(KnownName::SelfParam) = name.as_known_name() { 149 if let Some(KnownName::SelfParam) = name.as_known_name() {
150 PerNs::types(Resolution::Def(m.module.into())) 150 PerNs::types(Resolution::Def(m.module.into()))
151 } else { 151 } 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)
153 } 153 }
154 } 154 }
155 Scope::GenericParams(gp) => match gp.find_by_name(name) { 155 Scope::GenericParams(gp) => match gp.find_by_name(name) {
@@ -174,7 +174,7 @@ impl Scope {
174 } 174 }
175 } 175 }
176 176
177 fn collect_names(&self, f: &mut dyn FnMut(Name, PerNs<Resolution>)) { 177 fn collect_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, PerNs<Resolution>)) {
178 match self { 178 match self {
179 Scope::ModuleScope(m) => { 179 Scope::ModuleScope(m) => {
180 // TODO: should we provide `self` here? 180 // TODO: should we provide `self` here?
@@ -190,6 +190,12 @@ impl Scope {
190 m.item_map.extern_prelude.iter().for_each(|(name, def)| { 190 m.item_map.extern_prelude.iter().for_each(|(name, def)| {
191 f(name.clone(), PerNs::types(Resolution::Def(*def))); 191 f(name.clone(), PerNs::types(Resolution::Def(*def)));
192 }); 192 });
193 if let Some(prelude) = m.item_map.prelude {
194 let prelude_item_map = db.item_map(prelude.krate);
195 prelude_item_map[prelude.module_id].entries().for_each(|(name, res)| {
196 f(name.clone(), res.def.map(Resolution::Def));
197 });
198 }
193 } 199 }
194 Scope::GenericParams(gp) => { 200 Scope::GenericParams(gp) => {
195 for param in &gp.params { 201 for param in &gp.params {
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 445788407..eeaf26d93 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -4,7 +4,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
4 if !ctx.is_trivial_path { 4 if !ctx.is_trivial_path {
5 return; 5 return;
6 } 6 }
7 let names = ctx.resolver.all_names(); 7 let names = ctx.resolver.all_names(ctx.db);
8 8
9 names.into_iter().for_each(|(name, res)| { 9 names.into_iter().for_each(|(name, res)| {
10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
@@ -165,4 +165,23 @@ mod tests {
165 fn completes_self_in_methods() { 165 fn completes_self_in_methods() {
166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") 166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }")
167 } 167 }
168
169 #[test]
170 fn completes_prelude() {
171 check_reference_completion(
172 "completes_prelude",
173 "
174 //- /main.rs
175 fn foo() { let x: <|> }
176
177 //- /std/lib.rs
178 #[prelude_import]
179 use prelude::*;
180
181 mod prelude {
182 struct Option;
183 }
184 ",
185 );
186 }
168} 187}
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
new file mode 100644
index 000000000..2b5a1a8ea
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
@@ -0,0 +1,54 @@
1---
2created: "2019-02-13T19:52:43.734834624Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "Option",
11 kind: Some(
12 Struct
13 ),
14 detail: None,
15 documentation: None,
16 lookup: None,
17 insert_text: None,
18 insert_text_format: PlainText,
19 source_range: [18; 18),
20 text_edit: None
21 },
22 CompletionItem {
23 completion_kind: Reference,
24 label: "foo",
25 kind: Some(
26 Function
27 ),
28 detail: Some(
29 "fn foo()"
30 ),
31 documentation: None,
32 lookup: None,
33 insert_text: Some(
34 "foo()$0"
35 ),
36 insert_text_format: Snippet,
37 source_range: [18; 18),
38 text_edit: None
39 },
40 CompletionItem {
41 completion_kind: Reference,
42 label: "std",
43 kind: Some(
44 Module
45 ),
46 detail: None,
47 documentation: None,
48 lookup: None,
49 insert_text: None,
50 insert_text_format: PlainText,
51 source_range: [18; 18),
52 text_edit: None
53 }
54]
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index de3ec4e0a..d77a56ce8 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -62,7 +62,8 @@ pub use ra_ide_api_light::{
62 LineIndex, LineCol, translate_offset_with_edit, 62 LineIndex, LineCol, translate_offset_with_edit,
63}; 63};
64pub use ra_db::{ 64pub use ra_db::{
65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId 65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId,
66 Edition
66}; 67};
67pub use hir::Documentation; 68pub use hir::Documentation;
68 69
diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs
index 017ac5de3..550d69641 100644
--- a/crates/ra_ide_api/src/mock_analysis.rs
+++ b/crates/ra_ide_api/src/mock_analysis.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
5 5
6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId}; 6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId, Edition::Edition2018};
7 7
8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
9/// from a set of in-memory files. 9/// from a set of in-memory files.
@@ -89,9 +89,9 @@ impl MockAnalysis {
89 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 89 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
90 let file_id = FileId(i as u32 + 1); 90 let file_id = FileId(i as u32 + 1);
91 if path == "/lib.rs" || path == "/main.rs" { 91 if path == "/lib.rs" || path == "/main.rs" {
92 root_crate = Some(crate_graph.add_crate_root(file_id)); 92 root_crate = Some(crate_graph.add_crate_root(file_id, Edition2018));
93 } else if path.ends_with("/lib.rs") { 93 } else if path.ends_with("/lib.rs") {
94 let other_crate = crate_graph.add_crate_root(file_id); 94 let other_crate = crate_graph.add_crate_root(file_id, Edition2018);
95 let crate_name = path.parent().unwrap().file_name().unwrap(); 95 let crate_name = path.parent().unwrap().file_name().unwrap();
96 if let Some(root_crate) = root_crate { 96 if let Some(root_crate) = root_crate {
97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap(); 97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap();
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs
index 4cf842452..0526f7584 100644
--- a/crates/ra_ide_api/tests/test/main.rs
+++ b/crates/ra_ide_api/tests/test/main.rs
@@ -1,7 +1,7 @@
1use insta::assert_debug_snapshot_matches; 1use insta::assert_debug_snapshot_matches;
2use ra_ide_api::{ 2use ra_ide_api::{
3 mock_analysis::{single_file, single_file_with_position, MockAnalysis}, 3 mock_analysis::{single_file, single_file_with_position, MockAnalysis},
4 AnalysisChange, CrateGraph, FileId, Query, NavigationTarget, 4 AnalysisChange, CrateGraph, Edition::Edition2018, FileId, Query, NavigationTarget
5}; 5};
6use ra_syntax::{TextRange, SmolStr}; 6use ra_syntax::{TextRange, SmolStr};
7 7
@@ -36,7 +36,7 @@ fn test_resolve_crate_root() {
36 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); 36 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
37 37
38 let mut crate_graph = CrateGraph::default(); 38 let mut crate_graph = CrateGraph::default();
39 let crate_id = crate_graph.add_crate_root(root_file); 39 let crate_id = crate_graph.add_crate_root(root_file, Edition2018);
40 let mut change = AnalysisChange::new(); 40 let mut change = AnalysisChange::new();
41 change.set_crate_graph(crate_graph); 41 change.set_crate_graph(crate_graph);
42 host.apply_change(change); 42 host.apply_change(change);
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 5866be519..81cb506b7 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -4,6 +4,7 @@ use cargo_metadata::{MetadataCommand, CargoOpt};
4use ra_arena::{Arena, RawId, impl_arena_id}; 4use ra_arena::{Arena, RawId, impl_arena_id};
5use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
6use failure::format_err; 6use failure::format_err;
7use ra_db::Edition;
7 8
8use crate::Result; 9use crate::Result;
9 10
@@ -35,6 +36,7 @@ struct PackageData {
35 targets: Vec<Target>, 36 targets: Vec<Target>,
36 is_member: bool, 37 is_member: bool,
37 dependencies: Vec<PackageDependency>, 38 dependencies: Vec<PackageDependency>,
39 edition: Edition,
38} 40}
39 41
40#[derive(Debug, Clone)] 42#[derive(Debug, Clone)]
@@ -84,6 +86,9 @@ impl Package {
84 pub fn root(self, ws: &CargoWorkspace) -> &Path { 86 pub fn root(self, ws: &CargoWorkspace) -> &Path {
85 ws.packages[self].manifest.parent().unwrap() 87 ws.packages[self].manifest.parent().unwrap()
86 } 88 }
89 pub fn edition(self, ws: &CargoWorkspace) -> Edition {
90 ws.packages[self].edition
91 }
87 pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a { 92 pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a {
88 ws.packages[self].targets.iter().cloned() 93 ws.packages[self].targets.iter().cloned()
89 } 94 }
@@ -135,6 +140,7 @@ impl CargoWorkspace {
135 manifest: meta_pkg.manifest_path.clone(), 140 manifest: meta_pkg.manifest_path.clone(),
136 targets: Vec::new(), 141 targets: Vec::new(),
137 is_member, 142 is_member,
143 edition: Edition::from_string(&meta_pkg.edition),
138 dependencies: Vec::new(), 144 dependencies: Vec::new(),
139 }); 145 });
140 let pkg_data = &mut packages[pkg]; 146 let pkg_data = &mut packages[pkg];
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 3b1e07149..1b18ac836 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
6use failure::bail; 6use failure::bail;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use ra_db::{CrateGraph, FileId}; 9use ra_db::{CrateGraph, FileId, Edition};
10 10
11pub use crate::{ 11pub use crate::{
12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, 12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
@@ -36,7 +36,8 @@ impl ProjectWorkspace {
36 let mut sysroot_crates = FxHashMap::default(); 36 let mut sysroot_crates = FxHashMap::default();
37 for krate in self.sysroot.crates() { 37 for krate in self.sysroot.crates() {
38 if let Some(file_id) = load(krate.root(&self.sysroot)) { 38 if let Some(file_id) = load(krate.root(&self.sysroot)) {
39 sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); 39 sysroot_crates
40 .insert(krate, crate_graph.add_crate_root(file_id, Edition::Edition2015));
40 } 41 }
41 } 42 }
42 for from in self.sysroot.crates() { 43 for from in self.sysroot.crates() {
@@ -62,7 +63,8 @@ impl ProjectWorkspace {
62 for tgt in pkg.targets(&self.cargo) { 63 for tgt in pkg.targets(&self.cargo) {
63 let root = tgt.root(&self.cargo); 64 let root = tgt.root(&self.cargo);
64 if let Some(file_id) = load(root) { 65 if let Some(file_id) = load(root) {
65 let crate_id = crate_graph.add_crate_root(file_id); 66 let edition = pkg.edition(&self.cargo);
67 let crate_id = crate_graph.add_crate_root(file_id, edition);
66 if tgt.kind(&self.cargo) == TargetKind::Lib { 68 if tgt.kind(&self.cargo) == TargetKind::Lib {
67 lib_tgt = Some(crate_id); 69 lib_tgt = Some(crate_id);
68 pkg_to_lib_crate.insert(pkg, crate_id); 70 pkg_to_lib_crate.insert(pkg, crate_id);
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 5df3f2ccf..7c5e8ce5e 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -4210,6 +4210,7 @@ impl ToOwned for UseItem {
4210} 4210}
4211 4211
4212 4212
4213impl ast::AttrsOwner for UseItem {}
4213impl UseItem { 4214impl UseItem {
4214 pub fn use_tree(&self) -> Option<&UseTree> { 4215 pub fn use_tree(&self) -> Option<&UseTree> {
4215 super::child_opt(self) 4216 super::child_opt(self)
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 2e4b2d776..304bc5909 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -596,7 +596,8 @@ Grammar(
596 options: [ "Pat", "TypeRef" ], 596 options: [ "Pat", "TypeRef" ],
597 ), 597 ),
598 "UseItem": ( 598 "UseItem": (
599 options: [ "UseTree" ] 599 traits: ["AttrsOwner"],
600 options: [ "UseTree" ],
600 ), 601 ),
601 "UseTree": ( 602 "UseTree": (
602 options: [ "Path", "UseTreeList", "Alias" ] 603 options: [ "Path", "UseTreeList", "Alias" ]