diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-13 20:14:39 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-13 20:14:39 +0000 |
commit | cb4327b3a9f0858235dc20b7c5c7e25c6c330aab (patch) | |
tree | 489b3497b2762dcabf60d2674031585431e16959 /crates | |
parent | 65266c644a31e6b321e5afb3c5a2ee75be76cb0c (diff) | |
parent | 911e32bca9b73e66eceb6bbee3768c82e94597d5 (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.rs | 44 | ||||
-rw-r--r-- | crates/ra_db/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 127 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/lower.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 112 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 24 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_scope.rs | 21 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap | 54 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_ide_api/src/mock_analysis.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide_api/tests/test/main.rs | 4 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 6 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 3 |
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)] |
57 | pub struct CrateId(pub u32); | 57 | pub struct CrateId(pub u32); |
58 | 58 | ||
59 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
60 | pub enum Edition { | ||
61 | Edition2018, | ||
62 | Edition2015, | ||
63 | } | ||
64 | |||
65 | impl 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)] |
60 | struct CrateData { | 75 | struct CrateData { |
61 | file_id: FileId, | 76 | file_id: FileId, |
77 | edition: Edition, | ||
62 | dependencies: Vec<Dependency>, | 78 | dependencies: Vec<Dependency>, |
63 | } | 79 | } |
64 | 80 | ||
65 | impl CrateData { | 81 | impl 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 | ||
87 | impl CrateGraph { | 103 | impl 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)] |
161 | mod tests { | 181 | mod 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; | |||
14 | pub use crate::{ | 14 | pub 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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use relative_path::RelativePathBuf; | 3 | use relative_path::RelativePathBuf; |
4 | use ra_db::{CrateId, FileId, SourceRootId}; | 4 | use ra_db::{CrateId, FileId, SourceRootId, Edition}; |
5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; | 5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; |
6 | 6 | ||
7 | use crate::{ | 7 | use 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}; | |||
3 | use parking_lot::Mutex; | 3 | use parking_lot::Mutex; |
4 | use ra_db::{ | 4 | use ra_db::{ |
5 | FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, | 5 | FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, |
6 | Edition, | ||
6 | }; | 7 | }; |
7 | use relative_path::RelativePathBuf; | 8 | use relative_path::RelativePathBuf; |
8 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; | 9 | use 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)] |
235 | pub struct CrateGraphFixture(pub FxHashMap<String, (String, Vec<String>)>); | 236 | pub struct CrateGraphFixture(pub FxHashMap<String, (String, Edition, Vec<String>)>); |
236 | 237 | ||
237 | #[macro_export] | 238 | #[macro_export] |
238 | macro_rules! crate_graph { | 239 | macro_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 | ||
19 | use std::{time, sync::Arc}; | 19 | use std::{time, sync::Arc}; |
20 | 20 | ||
21 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
22 | |||
21 | use ra_arena::map::ArenaMap; | 23 | use ra_arena::map::ArenaMap; |
24 | use ra_db::Edition; | ||
22 | use test_utils::tested_by; | 25 | use test_utils::tested_by; |
23 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
24 | 26 | ||
25 | use crate::{ | 27 | use 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)] |
36 | pub struct ItemMap { | 38 | pub 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)] |
439 | enum ResolveMode { | ||
440 | Import, | ||
441 | Other, | ||
442 | } | ||
443 | |||
444 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
407 | enum ReachedFixedPoint { | 445 | enum 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 | ||
3 | use ra_syntax::{ | 3 | use 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 | }; |
7 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 7 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
8 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHashMap; |
9 | 9 | ||
10 | use crate::{ | 10 | use 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] |
269 | fn 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] | ||
269 | fn module_resolution_works_for_non_standard_filenames() { | 308 | fn 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] |
339 | fn 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] | ||
300 | fn name_res_works_for_broken_modules() { | 376 | fn 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] |
546 | fn 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] | ||
470 | fn import_across_source_roots() { | 582 | fn 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 | ||
58 | impl Resolver { | 58 | 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> { |
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 | ||
145 | impl Scope { | 145 | impl 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 | --- | ||
2 | created: "2019-02-13T19:52:43.734834624Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_ide_api/src/completion/completion_item.rs | ||
5 | expression: 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 | }; |
64 | pub use ra_db::{ | 64 | pub use ra_db::{ |
65 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId | 65 | Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId, |
66 | Edition | ||
66 | }; | 67 | }; |
67 | pub use hir::Documentation; | 68 | pub 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; | |||
3 | use relative_path::RelativePathBuf; | 3 | use relative_path::RelativePathBuf; |
4 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; | 4 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; |
5 | 5 | ||
6 | use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId}; | 6 | use 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 @@ | |||
1 | use insta::assert_debug_snapshot_matches; | 1 | use insta::assert_debug_snapshot_matches; |
2 | use ra_ide_api::{ | 2 | use 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 | }; |
6 | use ra_syntax::{TextRange, SmolStr}; | 6 | use 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}; | |||
4 | use ra_arena::{Arena, RawId, impl_arena_id}; | 4 | use ra_arena::{Arena, RawId, impl_arena_id}; |
5 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
6 | use failure::format_err; | 6 | use failure::format_err; |
7 | use ra_db::Edition; | ||
7 | 8 | ||
8 | use crate::Result; | 9 | use 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}; | |||
6 | use failure::bail; | 6 | use failure::bail; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | 8 | ||
9 | use ra_db::{CrateGraph, FileId}; | 9 | use ra_db::{CrateGraph, FileId, Edition}; |
10 | 10 | ||
11 | pub use crate::{ | 11 | pub 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 | ||
4213 | impl ast::AttrsOwner for UseItem {} | ||
4213 | impl UseItem { | 4214 | impl 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" ] |