diff options
Diffstat (limited to 'crates')
28 files changed, 730 insertions, 692 deletions
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs index 6e1e3de84..a8f8446cb 100644 --- a/crates/ra_assists/src/doc_tests.rs +++ b/crates/ra_assists/src/doc_tests.rs | |||
@@ -5,13 +5,14 @@ | |||
5 | 5 | ||
6 | mod generated; | 6 | mod generated; |
7 | 7 | ||
8 | use hir::mock::MockDatabase; | 8 | use ra_db::{fixture::WithFixture, FileRange}; |
9 | use ra_db::FileRange; | ||
10 | use test_utils::{assert_eq_text, extract_range_or_offset}; | 9 | use test_utils::{assert_eq_text, extract_range_or_offset}; |
11 | 10 | ||
11 | use crate::test_db::TestDB; | ||
12 | |||
12 | fn check(assist_id: &str, before: &str, after: &str) { | 13 | fn check(assist_id: &str, before: &str, after: &str) { |
13 | let (selection, before) = extract_range_or_offset(before); | 14 | let (selection, before) = extract_range_or_offset(before); |
14 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 15 | let (db, file_id) = TestDB::with_single_file(&before); |
15 | let frange = FileRange { file_id, range: selection.into() }; | 16 | let frange = FileRange { file_id, range: selection.into() }; |
16 | 17 | ||
17 | let (_assist_id, action) = crate::assists(&db, frange) | 18 | let (_assist_id, action) = crate::assists(&db, frange) |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 38599d4f1..39c1c283f 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -9,6 +9,8 @@ mod assist_ctx; | |||
9 | mod marks; | 9 | mod marks; |
10 | #[cfg(test)] | 10 | #[cfg(test)] |
11 | mod doc_tests; | 11 | mod doc_tests; |
12 | #[cfg(test)] | ||
13 | mod test_db; | ||
12 | 14 | ||
13 | use hir::db::HirDatabase; | 15 | use hir::db::HirDatabase; |
14 | use ra_db::FileRange; | 16 | use ra_db::FileRange; |
@@ -146,20 +148,19 @@ mod assists { | |||
146 | 148 | ||
147 | #[cfg(test)] | 149 | #[cfg(test)] |
148 | mod helpers { | 150 | mod helpers { |
149 | use hir::mock::MockDatabase; | 151 | use ra_db::{fixture::WithFixture, FileRange}; |
150 | use ra_db::FileRange; | ||
151 | use ra_syntax::TextRange; | 152 | use ra_syntax::TextRange; |
152 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; | 153 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; |
153 | 154 | ||
154 | use crate::{Assist, AssistCtx}; | 155 | use crate::{test_db::TestDB, Assist, AssistCtx}; |
155 | 156 | ||
156 | pub(crate) fn check_assist( | 157 | pub(crate) fn check_assist( |
157 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 158 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
158 | before: &str, | 159 | before: &str, |
159 | after: &str, | 160 | after: &str, |
160 | ) { | 161 | ) { |
161 | let (before_cursor_pos, before) = extract_offset(before); | 162 | let (before_cursor_pos, before) = extract_offset(before); |
162 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 163 | let (db, file_id) = TestDB::with_single_file(&before); |
163 | let frange = | 164 | let frange = |
164 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 165 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
165 | let assist = | 166 | let assist = |
@@ -182,12 +183,12 @@ mod helpers { | |||
182 | } | 183 | } |
183 | 184 | ||
184 | pub(crate) fn check_assist_range( | 185 | pub(crate) fn check_assist_range( |
185 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 186 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
186 | before: &str, | 187 | before: &str, |
187 | after: &str, | 188 | after: &str, |
188 | ) { | 189 | ) { |
189 | let (range, before) = extract_range(before); | 190 | let (range, before) = extract_range(before); |
190 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 191 | let (db, file_id) = TestDB::with_single_file(&before); |
191 | let frange = FileRange { file_id, range }; | 192 | let frange = FileRange { file_id, range }; |
192 | let assist = | 193 | let assist = |
193 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 194 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
@@ -204,12 +205,12 @@ mod helpers { | |||
204 | } | 205 | } |
205 | 206 | ||
206 | pub(crate) fn check_assist_target( | 207 | pub(crate) fn check_assist_target( |
207 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 208 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
208 | before: &str, | 209 | before: &str, |
209 | target: &str, | 210 | target: &str, |
210 | ) { | 211 | ) { |
211 | let (before_cursor_pos, before) = extract_offset(before); | 212 | let (before_cursor_pos, before) = extract_offset(before); |
212 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 213 | let (db, file_id) = TestDB::with_single_file(&before); |
213 | let frange = | 214 | let frange = |
214 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 215 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
215 | let assist = | 216 | let assist = |
@@ -224,12 +225,12 @@ mod helpers { | |||
224 | } | 225 | } |
225 | 226 | ||
226 | pub(crate) fn check_assist_range_target( | 227 | pub(crate) fn check_assist_range_target( |
227 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 228 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
228 | before: &str, | 229 | before: &str, |
229 | target: &str, | 230 | target: &str, |
230 | ) { | 231 | ) { |
231 | let (range, before) = extract_range(before); | 232 | let (range, before) = extract_range(before); |
232 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 233 | let (db, file_id) = TestDB::with_single_file(&before); |
233 | let frange = FileRange { file_id, range }; | 234 | let frange = FileRange { file_id, range }; |
234 | let assist = | 235 | let assist = |
235 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 236 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
@@ -243,11 +244,11 @@ mod helpers { | |||
243 | } | 244 | } |
244 | 245 | ||
245 | pub(crate) fn check_assist_not_applicable( | 246 | pub(crate) fn check_assist_not_applicable( |
246 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 247 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
247 | before: &str, | 248 | before: &str, |
248 | ) { | 249 | ) { |
249 | let (before_cursor_pos, before) = extract_offset(before); | 250 | let (before_cursor_pos, before) = extract_offset(before); |
250 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 251 | let (db, file_id) = TestDB::with_single_file(&before); |
251 | let frange = | 252 | let frange = |
252 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 253 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
253 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | 254 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); |
@@ -255,11 +256,11 @@ mod helpers { | |||
255 | } | 256 | } |
256 | 257 | ||
257 | pub(crate) fn check_assist_range_not_applicable( | 258 | pub(crate) fn check_assist_range_not_applicable( |
258 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 259 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
259 | before: &str, | 260 | before: &str, |
260 | ) { | 261 | ) { |
261 | let (range, before) = extract_range(before); | 262 | let (range, before) = extract_range(before); |
262 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 263 | let (db, file_id) = TestDB::with_single_file(&before); |
263 | let frange = FileRange { file_id, range }; | 264 | let frange = FileRange { file_id, range }; |
264 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | 265 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); |
265 | assert!(assist.is_none()); | 266 | assert!(assist.is_none()); |
@@ -268,16 +269,17 @@ mod helpers { | |||
268 | 269 | ||
269 | #[cfg(test)] | 270 | #[cfg(test)] |
270 | mod tests { | 271 | mod tests { |
271 | use hir::mock::MockDatabase; | 272 | use ra_db::{fixture::WithFixture, FileRange}; |
272 | use ra_db::FileRange; | ||
273 | use ra_syntax::TextRange; | 273 | use ra_syntax::TextRange; |
274 | use test_utils::{extract_offset, extract_range}; | 274 | use test_utils::{extract_offset, extract_range}; |
275 | 275 | ||
276 | use crate::test_db::TestDB; | ||
277 | |||
276 | #[test] | 278 | #[test] |
277 | fn assist_order_field_struct() { | 279 | fn assist_order_field_struct() { |
278 | let before = "struct Foo { <|>bar: u32 }"; | 280 | let before = "struct Foo { <|>bar: u32 }"; |
279 | let (before_cursor_pos, before) = extract_offset(before); | 281 | let (before_cursor_pos, before) = extract_offset(before); |
280 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 282 | let (db, file_id) = TestDB::with_single_file(&before); |
281 | let frange = | 283 | let frange = |
282 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 284 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
283 | let assists = super::assists(&db, frange); | 285 | let assists = super::assists(&db, frange); |
@@ -298,7 +300,7 @@ mod tests { | |||
298 | } | 300 | } |
299 | }"; | 301 | }"; |
300 | let (range, before) = extract_range(before); | 302 | let (range, before) = extract_range(before); |
301 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 303 | let (db, file_id) = TestDB::with_single_file(&before); |
302 | let frange = FileRange { file_id, range }; | 304 | let frange = FileRange { file_id, range }; |
303 | let assists = super::assists(&db, frange); | 305 | let assists = super::assists(&db, frange); |
304 | let mut assists = assists.iter(); | 306 | let mut assists = assists.iter(); |
diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs new file mode 100644 index 000000000..5be7383ed --- /dev/null +++ b/crates/ra_assists/src/test_db.rs | |||
@@ -0,0 +1,45 @@ | |||
1 | //! Database used for testing `ra_assists`. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | ||
6 | |||
7 | #[salsa::database( | ||
8 | ra_db::SourceDatabaseExtStorage, | ||
9 | ra_db::SourceDatabaseStorage, | ||
10 | hir::db::InternDatabaseStorage, | ||
11 | hir::db::AstDatabaseStorage, | ||
12 | hir::db::DefDatabaseStorage, | ||
13 | hir::db::DefDatabase2Storage, | ||
14 | hir::db::HirDatabaseStorage | ||
15 | )] | ||
16 | #[derive(Debug, Default)] | ||
17 | pub struct TestDB { | ||
18 | runtime: salsa::Runtime<TestDB>, | ||
19 | } | ||
20 | |||
21 | impl salsa::Database for TestDB { | ||
22 | fn salsa_runtime(&self) -> &salsa::Runtime<Self> { | ||
23 | &self.runtime | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl std::panic::RefUnwindSafe for TestDB {} | ||
28 | |||
29 | impl FileLoader for TestDB { | ||
30 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
31 | FileLoaderDelegate(self).file_text(file_id) | ||
32 | } | ||
33 | fn resolve_relative_path( | ||
34 | &self, | ||
35 | anchor: FileId, | ||
36 | relative_path: &RelativePath, | ||
37 | ) -> Option<FileId> { | ||
38 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
39 | } | ||
40 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
41 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
42 | } | ||
43 | } | ||
44 | |||
45 | impl hir::debug::HirDebugHelper for TestDB {} | ||
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml index c85da7a2c..d08c5ceac 100644 --- a/crates/ra_batch/Cargo.toml +++ b/crates/ra_batch/Cargo.toml | |||
@@ -7,7 +7,7 @@ authors = ["rust-analyzer developers"] | |||
7 | [dependencies] | 7 | [dependencies] |
8 | log = "0.4.5" | 8 | log = "0.4.5" |
9 | rustc-hash = "1.0" | 9 | rustc-hash = "1.0" |
10 | crossbeam-channel = "0.3.5" | 10 | crossbeam-channel = "0.4.0" |
11 | 11 | ||
12 | ra_vfs = "0.5.0" | 12 | ra_vfs = "0.5.0" |
13 | ra_vfs_glob = { path = "../ra_vfs_glob" } | 13 | ra_vfs_glob = { path = "../ra_vfs_glob" } |
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index fcd102e8b..c9d3bdb77 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml | |||
@@ -8,7 +8,7 @@ publish = false | |||
8 | [dependencies] | 8 | [dependencies] |
9 | pico-args = "0.3.0" | 9 | pico-args = "0.3.0" |
10 | flexi_logger = "0.14.0" | 10 | flexi_logger = "0.14.0" |
11 | indicatif = "0.12.0" | 11 | indicatif = "0.13.0" |
12 | 12 | ||
13 | ra_syntax = { path = "../ra_syntax" } | 13 | ra_syntax = { path = "../ra_syntax" } |
14 | ra_ide_api = { path = "../ra_ide_api" } | 14 | ra_ide_api = { path = "../ra_ide_api" } |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 181c5d47a..9d0db8024 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | pub(crate) mod src; | 3 | pub(crate) mod src; |
4 | pub(crate) mod docs; | 4 | pub(crate) mod docs; |
5 | pub(crate) mod attrs; | ||
5 | 6 | ||
6 | use std::sync::Arc; | 7 | use std::sync::Arc; |
7 | 8 | ||
@@ -30,8 +31,8 @@ use crate::{ | |||
30 | impl_block::ImplBlock, | 31 | impl_block::ImplBlock, |
31 | resolve::{Resolver, Scope, TypeNs}, | 32 | resolve::{Resolver, Scope, TypeNs}, |
32 | traits::TraitData, | 33 | traits::TraitData, |
33 | ty::{InferenceResult, TraitRef}, | 34 | ty::{InferenceResult, Namespace, TraitRef}, |
34 | Either, HasSource, Name, ScopeDef, Ty, {ImportId, Namespace}, | 35 | Either, HasSource, ImportId, Name, ScopeDef, Ty, |
35 | }; | 36 | }; |
36 | 37 | ||
37 | /// hir::Crate describes a single crate. It's the main interface with which | 38 | /// hir::Crate describes a single crate. It's the main interface with which |
diff --git a/crates/ra_hir/src/code_model/attrs.rs b/crates/ra_hir/src/code_model/attrs.rs new file mode 100644 index 000000000..f7db36b66 --- /dev/null +++ b/crates/ra_hir/src/code_model/attrs.rs | |||
@@ -0,0 +1,92 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use crate::{ | ||
4 | db::{AstDatabase, DefDatabase, HirDatabase}, | ||
5 | Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static, | ||
6 | Struct, StructField, Trait, TypeAlias, Union, | ||
7 | }; | ||
8 | use hir_def::attr::Attr; | ||
9 | use hir_expand::hygiene::Hygiene; | ||
10 | use ra_syntax::ast; | ||
11 | use std::sync::Arc; | ||
12 | |||
13 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
14 | pub enum AttrDef { | ||
15 | Module(Module), | ||
16 | StructField(StructField), | ||
17 | Adt(Adt), | ||
18 | Function(Function), | ||
19 | EnumVariant(EnumVariant), | ||
20 | Static(Static), | ||
21 | Const(Const), | ||
22 | Trait(Trait), | ||
23 | TypeAlias(TypeAlias), | ||
24 | MacroDef(MacroDef), | ||
25 | } | ||
26 | |||
27 | impl_froms!( | ||
28 | AttrDef: Module, | ||
29 | StructField, | ||
30 | Adt(Struct, Enum, Union), | ||
31 | EnumVariant, | ||
32 | Static, | ||
33 | Const, | ||
34 | Function, | ||
35 | Trait, | ||
36 | TypeAlias, | ||
37 | MacroDef | ||
38 | ); | ||
39 | |||
40 | pub trait Attrs { | ||
41 | fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>>; | ||
42 | } | ||
43 | |||
44 | pub(crate) fn attributes_query( | ||
45 | db: &(impl DefDatabase + AstDatabase), | ||
46 | def: AttrDef, | ||
47 | ) -> Option<Arc<[Attr]>> { | ||
48 | match def { | ||
49 | AttrDef::Module(it) => { | ||
50 | let src = it.declaration_source(db)?; | ||
51 | let hygiene = Hygiene::new(db, src.file_id); | ||
52 | Attr::from_attrs_owner(&src.ast, &hygiene) | ||
53 | } | ||
54 | AttrDef::StructField(it) => match it.source(db).ast { | ||
55 | FieldSource::Named(named) => { | ||
56 | let src = it.source(db); | ||
57 | let hygiene = Hygiene::new(db, src.file_id); | ||
58 | Attr::from_attrs_owner(&named, &hygiene) | ||
59 | } | ||
60 | FieldSource::Pos(..) => None, | ||
61 | }, | ||
62 | AttrDef::Adt(it) => match it { | ||
63 | Adt::Struct(it) => attrs_from_ast(it, db), | ||
64 | Adt::Enum(it) => attrs_from_ast(it, db), | ||
65 | Adt::Union(it) => attrs_from_ast(it, db), | ||
66 | }, | ||
67 | AttrDef::EnumVariant(it) => attrs_from_ast(it, db), | ||
68 | AttrDef::Static(it) => attrs_from_ast(it, db), | ||
69 | AttrDef::Const(it) => attrs_from_ast(it, db), | ||
70 | AttrDef::Function(it) => attrs_from_ast(it, db), | ||
71 | AttrDef::Trait(it) => attrs_from_ast(it, db), | ||
72 | AttrDef::TypeAlias(it) => attrs_from_ast(it, db), | ||
73 | AttrDef::MacroDef(it) => attrs_from_ast(it, db), | ||
74 | } | ||
75 | } | ||
76 | |||
77 | fn attrs_from_ast<T, D>(node: T, db: &D) -> Option<Arc<[Attr]>> | ||
78 | where | ||
79 | T: HasSource, | ||
80 | T::Ast: ast::AttrsOwner, | ||
81 | D: DefDatabase + AstDatabase, | ||
82 | { | ||
83 | let src = node.source(db); | ||
84 | let hygiene = Hygiene::new(db, src.file_id); | ||
85 | Attr::from_attrs_owner(&src.ast, &hygiene) | ||
86 | } | ||
87 | |||
88 | impl<T: Into<AttrDef> + Copy> Attrs for T { | ||
89 | fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>> { | ||
90 | db.attrs((*self).into()) | ||
91 | } | ||
92 | } | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index eb66325f7..75c322c99 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::attr::Attr; | ||
5 | use ra_db::salsa; | 6 | use ra_db::salsa; |
6 | use ra_syntax::SmolStr; | 7 | use ra_syntax::SmolStr; |
7 | 8 | ||
@@ -14,10 +15,10 @@ use crate::{ | |||
14 | traits::TraitData, | 15 | traits::TraitData, |
15 | ty::{ | 16 | ty::{ |
16 | method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, | 17 | method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, |
17 | InferenceResult, Substs, Ty, TypableDef, TypeCtor, | 18 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, |
18 | }, | 19 | }, |
19 | type_alias::TypeAliasData, | 20 | type_alias::TypeAliasData, |
20 | Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Namespace, Static, | 21 | Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, |
21 | StructField, Trait, TypeAlias, | 22 | StructField, Trait, TypeAlias, |
22 | }; | 23 | }; |
23 | 24 | ||
@@ -75,6 +76,9 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { | |||
75 | 76 | ||
76 | #[salsa::invoke(crate::code_model::docs::documentation_query)] | 77 | #[salsa::invoke(crate::code_model::docs::documentation_query)] |
77 | fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>; | 78 | fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>; |
79 | |||
80 | #[salsa::invoke(crate::code_model::attrs::attributes_query)] | ||
81 | fn attrs(&self, def: crate::AttrDef) -> Option<Arc<[Attr]>>; | ||
78 | } | 82 | } |
79 | 83 | ||
80 | #[salsa::query_group(HirDatabaseStorage)] | 84 | #[salsa::query_group(HirDatabaseStorage)] |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 5496822e7..c14c2ab66 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -174,11 +174,11 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
174 | 174 | ||
175 | #[cfg(test)] | 175 | #[cfg(test)] |
176 | mod tests { | 176 | mod tests { |
177 | use ra_db::SourceDatabase; | 177 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
178 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | 178 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; |
179 | use test_utils::{assert_eq_text, extract_offset}; | 179 | use test_utils::{assert_eq_text, extract_offset}; |
180 | 180 | ||
181 | use crate::{mock::MockDatabase, source_binder::SourceAnalyzer}; | 181 | use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; |
182 | 182 | ||
183 | fn do_check(code: &str, expected: &[&str]) { | 183 | fn do_check(code: &str, expected: &[&str]) { |
184 | let (off, code) = extract_offset(code); | 184 | let (off, code) = extract_offset(code); |
@@ -191,7 +191,7 @@ mod tests { | |||
191 | buf | 191 | buf |
192 | }; | 192 | }; |
193 | 193 | ||
194 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | 194 | let (db, file_id) = TestDB::with_single_file(&code); |
195 | let file = db.parse(file_id).ok().unwrap(); | 195 | let file = db.parse(file_id).ok().unwrap(); |
196 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 196 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
197 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); | 197 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); |
@@ -288,7 +288,7 @@ mod tests { | |||
288 | fn do_check_local_name(code: &str, expected_offset: u32) { | 288 | fn do_check_local_name(code: &str, expected_offset: u32) { |
289 | let (off, code) = extract_offset(code); | 289 | let (off, code) = extract_offset(code); |
290 | 290 | ||
291 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | 291 | let (db, file_id) = TestDB::with_single_file(&code); |
292 | let file = db.parse(file_id).ok().unwrap(); | 292 | let file = db.parse(file_id).ok().unwrap(); |
293 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | 293 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) |
294 | .expect("failed to find a name at the target offset"); | 294 | .expect("failed to find a name at the target offset"); |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 3ba99d92d..131f6c797 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -29,8 +29,6 @@ macro_rules! impl_froms { | |||
29 | pub mod debug; | 29 | pub mod debug; |
30 | 30 | ||
31 | pub mod db; | 31 | pub mod db; |
32 | #[macro_use] | ||
33 | pub mod mock; | ||
34 | pub mod source_binder; | 32 | pub mod source_binder; |
35 | 33 | ||
36 | mod ids; | 34 | mod ids; |
@@ -52,6 +50,8 @@ mod code_model; | |||
52 | pub mod from_source; | 50 | pub mod from_source; |
53 | 51 | ||
54 | #[cfg(test)] | 52 | #[cfg(test)] |
53 | mod test_db; | ||
54 | #[cfg(test)] | ||
55 | mod marks; | 55 | mod marks; |
56 | 56 | ||
57 | use hir_expand::AstId; | 57 | use hir_expand::AstId; |
@@ -61,6 +61,7 @@ use crate::{ids::MacroFileKind, resolve::Resolver}; | |||
61 | pub use crate::{ | 61 | pub use crate::{ |
62 | adt::VariantDef, | 62 | adt::VariantDef, |
63 | code_model::{ | 63 | code_model::{ |
64 | attrs::{AttrDef, Attrs}, | ||
64 | docs::{DocDef, Docs, Documentation}, | 65 | docs::{DocDef, Docs, Documentation}, |
65 | src::{HasBodySource, HasSource}, | 66 | src::{HasBodySource, HasSource}, |
66 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, | 67 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, |
@@ -81,10 +82,7 @@ pub use crate::{ | |||
81 | 82 | ||
82 | pub use hir_def::{ | 83 | pub use hir_def::{ |
83 | builtin_type::BuiltinType, | 84 | builtin_type::BuiltinType, |
84 | nameres::{ | 85 | nameres::{per_ns::PerNs, raw::ImportId}, |
85 | per_ns::{Namespace, PerNs}, | ||
86 | raw::ImportId, | ||
87 | }, | ||
88 | path::{Path, PathKind}, | 86 | path::{Path, PathKind}, |
89 | type_ref::Mutability, | 87 | type_ref::Mutability, |
90 | }; | 88 | }; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs deleted file mode 100644 index ab97a09b9..000000000 --- a/crates/ra_hir/src/mock.rs +++ /dev/null | |||
@@ -1,262 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::{panic, sync::Arc}; | ||
4 | |||
5 | use hir_expand::diagnostics::DiagnosticSink; | ||
6 | use parking_lot::Mutex; | ||
7 | use ra_cfg::CfgOptions; | ||
8 | use ra_db::{ | ||
9 | salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition, | ||
10 | RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, | ||
11 | }; | ||
12 | use rustc_hash::FxHashMap; | ||
13 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | ||
14 | |||
15 | use crate::{db, debug::HirDebugHelper}; | ||
16 | |||
17 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | ||
18 | |||
19 | #[salsa::database( | ||
20 | ra_db::SourceDatabaseExtStorage, | ||
21 | ra_db::SourceDatabaseStorage, | ||
22 | db::InternDatabaseStorage, | ||
23 | db::AstDatabaseStorage, | ||
24 | db::DefDatabaseStorage, | ||
25 | db::DefDatabase2Storage, | ||
26 | db::HirDatabaseStorage | ||
27 | )] | ||
28 | #[derive(Debug)] | ||
29 | pub struct MockDatabase { | ||
30 | events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, | ||
31 | runtime: salsa::Runtime<MockDatabase>, | ||
32 | files: FxHashMap<String, FileId>, | ||
33 | crate_names: Arc<FxHashMap<CrateId, String>>, | ||
34 | file_paths: Arc<FxHashMap<FileId, String>>, | ||
35 | } | ||
36 | |||
37 | impl panic::RefUnwindSafe for MockDatabase {} | ||
38 | |||
39 | impl FileLoader for MockDatabase { | ||
40 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
41 | FileLoaderDelegate(self).file_text(file_id) | ||
42 | } | ||
43 | fn resolve_relative_path( | ||
44 | &self, | ||
45 | anchor: FileId, | ||
46 | relative_path: &RelativePath, | ||
47 | ) -> Option<FileId> { | ||
48 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
49 | } | ||
50 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
51 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl HirDebugHelper for MockDatabase { | ||
56 | fn crate_name(&self, krate: CrateId) -> Option<String> { | ||
57 | self.crate_names.get(&krate).cloned() | ||
58 | } | ||
59 | |||
60 | fn file_path(&self, file_id: FileId) -> Option<String> { | ||
61 | self.file_paths.get(&file_id).cloned() | ||
62 | } | ||
63 | } | ||
64 | |||
65 | impl MockDatabase { | ||
66 | pub fn with_files(fixture: &str) -> MockDatabase { | ||
67 | let (db, position) = MockDatabase::from_fixture(fixture); | ||
68 | assert!(position.is_none()); | ||
69 | db | ||
70 | } | ||
71 | |||
72 | pub fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) { | ||
73 | let mut db = MockDatabase::default(); | ||
74 | let mut source_root = SourceRoot::default(); | ||
75 | let file_id = db.add_file(WORKSPACE, "/", &mut source_root, "/main.rs", text); | ||
76 | db.set_source_root(WORKSPACE, Arc::new(source_root.clone())); | ||
77 | (db, source_root, file_id) | ||
78 | } | ||
79 | |||
80 | pub fn file_id_of(&self, path: &str) -> FileId { | ||
81 | match self.files.get(path) { | ||
82 | Some(it) => *it, | ||
83 | None => panic!("unknown file: {:?}\nexisting files:\n{:#?}", path, self.files), | ||
84 | } | ||
85 | } | ||
86 | |||
87 | pub fn diagnostics(&self) -> String { | ||
88 | let mut buf = String::new(); | ||
89 | let mut files: Vec<FileId> = self.files.values().copied().collect(); | ||
90 | files.sort(); | ||
91 | for file in files { | ||
92 | let src = crate::Source { | ||
93 | file_id: file.into(), | ||
94 | ast: crate::ModuleSource::new(self, Some(file), None), | ||
95 | }; | ||
96 | let module = crate::Module::from_definition(self, src).unwrap(); | ||
97 | module.diagnostics( | ||
98 | self, | ||
99 | &mut DiagnosticSink::new(|d| { | ||
100 | buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
101 | }), | ||
102 | ) | ||
103 | } | ||
104 | buf | ||
105 | } | ||
106 | |||
107 | fn from_fixture(fixture: &str) -> (MockDatabase, Option<FilePosition>) { | ||
108 | let mut db = MockDatabase::default(); | ||
109 | |||
110 | let pos = db.add_fixture(fixture); | ||
111 | |||
112 | (db, pos) | ||
113 | } | ||
114 | |||
115 | fn add_fixture(&mut self, fixture: &str) -> Option<FilePosition> { | ||
116 | let mut position = None; | ||
117 | let mut source_root = SourceRoot::default(); | ||
118 | let mut source_root_id = WORKSPACE; | ||
119 | let mut source_root_prefix = "/".to_string(); | ||
120 | for entry in parse_fixture(fixture) { | ||
121 | if entry.meta.starts_with("root") { | ||
122 | self.set_source_root(source_root_id, Arc::new(source_root)); | ||
123 | source_root = SourceRoot::default(); | ||
124 | |||
125 | source_root_id = SourceRootId(source_root_id.0 + 1); | ||
126 | source_root_prefix = entry.meta["root".len()..].trim().to_string(); | ||
127 | continue; | ||
128 | } | ||
129 | if entry.text.contains(CURSOR_MARKER) { | ||
130 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); | ||
131 | position = Some(self.add_file_with_position( | ||
132 | source_root_id, | ||
133 | &source_root_prefix, | ||
134 | &mut source_root, | ||
135 | &entry.meta, | ||
136 | &entry.text, | ||
137 | )); | ||
138 | } else { | ||
139 | self.add_file( | ||
140 | source_root_id, | ||
141 | &source_root_prefix, | ||
142 | &mut source_root, | ||
143 | &entry.meta, | ||
144 | &entry.text, | ||
145 | ); | ||
146 | } | ||
147 | } | ||
148 | self.set_source_root(source_root_id, Arc::new(source_root)); | ||
149 | position | ||
150 | } | ||
151 | |||
152 | fn add_file( | ||
153 | &mut self, | ||
154 | source_root_id: SourceRootId, | ||
155 | source_root_prefix: &str, | ||
156 | source_root: &mut SourceRoot, | ||
157 | path: &str, | ||
158 | text: &str, | ||
159 | ) -> FileId { | ||
160 | assert!(source_root_prefix.starts_with('/')); | ||
161 | assert!(source_root_prefix.ends_with('/')); | ||
162 | assert!(path.starts_with(source_root_prefix)); | ||
163 | let rel_path = RelativePathBuf::from_path(&path[source_root_prefix.len()..]).unwrap(); | ||
164 | |||
165 | let is_crate_root = rel_path == "lib.rs" || rel_path == "/main.rs"; | ||
166 | |||
167 | let file_id = FileId(self.files.len() as u32); | ||
168 | |||
169 | let prev = self.files.insert(path.to_string(), file_id); | ||
170 | assert!(prev.is_none(), "duplicate files in the text fixture"); | ||
171 | Arc::make_mut(&mut self.file_paths).insert(file_id, path.to_string()); | ||
172 | |||
173 | let text = Arc::new(text.to_string()); | ||
174 | self.set_file_text(file_id, text); | ||
175 | self.set_file_relative_path(file_id, rel_path.clone()); | ||
176 | self.set_file_source_root(file_id, source_root_id); | ||
177 | source_root.insert_file(rel_path, file_id); | ||
178 | |||
179 | if is_crate_root { | ||
180 | let mut crate_graph = CrateGraph::default(); | ||
181 | crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); | ||
182 | self.set_crate_graph(Arc::new(crate_graph)); | ||
183 | } | ||
184 | file_id | ||
185 | } | ||
186 | |||
187 | fn add_file_with_position( | ||
188 | &mut self, | ||
189 | source_root_id: SourceRootId, | ||
190 | source_root_prefix: &str, | ||
191 | source_root: &mut SourceRoot, | ||
192 | path: &str, | ||
193 | text: &str, | ||
194 | ) -> FilePosition { | ||
195 | let (offset, text) = extract_offset(text); | ||
196 | let file_id = self.add_file(source_root_id, source_root_prefix, source_root, path, &text); | ||
197 | FilePosition { file_id, offset } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | impl salsa::Database for MockDatabase { | ||
202 | fn salsa_runtime(&self) -> &salsa::Runtime<MockDatabase> { | ||
203 | &self.runtime | ||
204 | } | ||
205 | |||
206 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<MockDatabase>) { | ||
207 | let mut events = self.events.lock(); | ||
208 | if let Some(events) = &mut *events { | ||
209 | events.push(event()); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | impl Default for MockDatabase { | ||
215 | fn default() -> MockDatabase { | ||
216 | let mut db = MockDatabase { | ||
217 | events: Default::default(), | ||
218 | runtime: salsa::Runtime::default(), | ||
219 | files: FxHashMap::default(), | ||
220 | crate_names: Default::default(), | ||
221 | file_paths: Default::default(), | ||
222 | }; | ||
223 | db.set_crate_graph(Default::default()); | ||
224 | db | ||
225 | } | ||
226 | } | ||
227 | |||
228 | impl salsa::ParallelDatabase for MockDatabase { | ||
229 | fn snapshot(&self) -> salsa::Snapshot<MockDatabase> { | ||
230 | salsa::Snapshot::new(MockDatabase { | ||
231 | events: Default::default(), | ||
232 | runtime: self.runtime.snapshot(self), | ||
233 | // only the root database can be used to get file_id by path. | ||
234 | files: FxHashMap::default(), | ||
235 | file_paths: Arc::clone(&self.file_paths), | ||
236 | crate_names: Arc::clone(&self.crate_names), | ||
237 | }) | ||
238 | } | ||
239 | } | ||
240 | |||
241 | impl MockDatabase { | ||
242 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> { | ||
243 | *self.events.lock() = Some(Vec::new()); | ||
244 | f(); | ||
245 | self.events.lock().take().unwrap() | ||
246 | } | ||
247 | |||
248 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
249 | let events = self.log(f); | ||
250 | events | ||
251 | .into_iter() | ||
252 | .filter_map(|e| match e.kind { | ||
253 | // This pretty horrible, but `Debug` is the only way to inspect | ||
254 | // QueryDescriptor at the moment. | ||
255 | salsa::EventKind::WillExecute { database_key } => { | ||
256 | Some(format!("{:?}", database_key)) | ||
257 | } | ||
258 | _ => None, | ||
259 | }) | ||
260 | .collect() | ||
261 | } | ||
262 | } | ||
diff --git a/crates/ra_hir/src/test_db.rs b/crates/ra_hir/src/test_db.rs new file mode 100644 index 000000000..5237b303a --- /dev/null +++ b/crates/ra_hir/src/test_db.rs | |||
@@ -0,0 +1,120 @@ | |||
1 | //! Database used for testing `hir`. | ||
2 | |||
3 | use std::{panic, sync::Arc}; | ||
4 | |||
5 | use hir_def::{db::DefDatabase2, ModuleId}; | ||
6 | use hir_expand::diagnostics::DiagnosticSink; | ||
7 | use parking_lot::Mutex; | ||
8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase}; | ||
9 | |||
10 | use crate::{db, debug::HirDebugHelper}; | ||
11 | |||
12 | #[salsa::database( | ||
13 | ra_db::SourceDatabaseExtStorage, | ||
14 | ra_db::SourceDatabaseStorage, | ||
15 | db::InternDatabaseStorage, | ||
16 | db::AstDatabaseStorage, | ||
17 | db::DefDatabaseStorage, | ||
18 | db::DefDatabase2Storage, | ||
19 | db::HirDatabaseStorage | ||
20 | )] | ||
21 | #[derive(Debug, Default)] | ||
22 | pub struct TestDB { | ||
23 | events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, | ||
24 | runtime: salsa::Runtime<TestDB>, | ||
25 | } | ||
26 | |||
27 | impl salsa::Database for TestDB { | ||
28 | fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> { | ||
29 | &self.runtime | ||
30 | } | ||
31 | |||
32 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { | ||
33 | let mut events = self.events.lock(); | ||
34 | if let Some(events) = &mut *events { | ||
35 | events.push(event()); | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl salsa::ParallelDatabase for TestDB { | ||
41 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { | ||
42 | salsa::Snapshot::new(TestDB { | ||
43 | events: Default::default(), | ||
44 | runtime: self.runtime.snapshot(self), | ||
45 | }) | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl panic::RefUnwindSafe for TestDB {} | ||
50 | |||
51 | impl FileLoader for TestDB { | ||
52 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
53 | FileLoaderDelegate(self).file_text(file_id) | ||
54 | } | ||
55 | fn resolve_relative_path( | ||
56 | &self, | ||
57 | anchor: FileId, | ||
58 | relative_path: &RelativePath, | ||
59 | ) -> Option<FileId> { | ||
60 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
61 | } | ||
62 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
63 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
64 | } | ||
65 | } | ||
66 | |||
67 | // FIXME: improve `WithFixture` to bring useful hir debugging back | ||
68 | impl HirDebugHelper for TestDB { | ||
69 | fn crate_name(&self, _krate: CrateId) -> Option<String> { | ||
70 | None | ||
71 | } | ||
72 | |||
73 | fn file_path(&self, _file_id: FileId) -> Option<String> { | ||
74 | None | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl TestDB { | ||
79 | pub fn diagnostics(&self) -> String { | ||
80 | let mut buf = String::new(); | ||
81 | let crate_graph = self.crate_graph(); | ||
82 | for krate in crate_graph.iter().next() { | ||
83 | let crate_def_map = self.crate_def_map(krate); | ||
84 | for (module_id, _) in crate_def_map.modules.iter() { | ||
85 | let module_id = ModuleId { krate, module_id }; | ||
86 | let module = crate::Module::from(module_id); | ||
87 | module.diagnostics( | ||
88 | self, | ||
89 | &mut DiagnosticSink::new(|d| { | ||
90 | buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
91 | }), | ||
92 | ) | ||
93 | } | ||
94 | } | ||
95 | buf | ||
96 | } | ||
97 | } | ||
98 | |||
99 | impl TestDB { | ||
100 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { | ||
101 | *self.events.lock() = Some(Vec::new()); | ||
102 | f(); | ||
103 | self.events.lock().take().unwrap() | ||
104 | } | ||
105 | |||
106 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
107 | let events = self.log(f); | ||
108 | events | ||
109 | .into_iter() | ||
110 | .filter_map(|e| match e.kind { | ||
111 | // This pretty horrible, but `Debug` is the only way to inspect | ||
112 | // QueryDescriptor at the moment. | ||
113 | salsa::EventKind::WillExecute { database_key } => { | ||
114 | Some(format!("{:?}", database_key)) | ||
115 | } | ||
116 | _ => None, | ||
117 | }) | ||
118 | .collect() | ||
119 | } | ||
120 | } | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d1a9d7411..cd2ac0e8b 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -27,7 +27,7 @@ pub(crate) use infer::{infer_query, InferTy, InferenceResult}; | |||
27 | pub use lower::CallableDef; | 27 | pub use lower::CallableDef; |
28 | pub(crate) use lower::{ | 28 | pub(crate) use lower::{ |
29 | callable_item_sig, generic_defaults_query, generic_predicates_for_param_query, | 29 | callable_item_sig, generic_defaults_query, generic_predicates_for_param_query, |
30 | generic_predicates_query, type_for_def, type_for_field, TypableDef, | 30 | generic_predicates_query, type_for_def, type_for_field, Namespace, TypableDef, |
31 | }; | 31 | }; |
32 | pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 32 | pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
33 | 33 | ||
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index a09ef5c5d..4af1d65ee 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs | |||
@@ -12,10 +12,10 @@ use crate::{ | |||
12 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, | 12 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, |
13 | generics::{GenericParams, HasGenericParams}, | 13 | generics::{GenericParams, HasGenericParams}, |
14 | ty::{ | 14 | ty::{ |
15 | autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation, | 15 | autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Namespace, |
16 | ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | 16 | Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, |
17 | }, | 17 | }, |
18 | Adt, Name, Namespace, | 18 | Adt, Name, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 21 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index 59b7f7eb6..865ced5a1 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs | |||
@@ -6,8 +6,8 @@ use super::{ExprOrPatId, InferenceContext, TraitRef}; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::HirDatabase, | 7 | db::HirDatabase, |
8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
9 | ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk}, | 9 | ty::{method_resolution, Namespace, Substs, Ty, TypableDef, TypeWalk}, |
10 | AssocItem, Container, HasGenericParams, Name, Namespace, Path, | 10 | AssocItem, Container, HasGenericParams, Name, Path, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index e29ab8492..d26b16cb2 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -29,10 +29,21 @@ use crate::{ | |||
29 | Adt, | 29 | Adt, |
30 | }, | 30 | }, |
31 | util::make_mut_slice, | 31 | util::make_mut_slice, |
32 | Const, Enum, EnumVariant, Function, ModuleDef, Namespace, Path, Static, Struct, StructField, | 32 | Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, Trait, |
33 | Trait, TypeAlias, Union, | 33 | TypeAlias, Union, |
34 | }; | 34 | }; |
35 | 35 | ||
36 | // FIXME: this is only really used in `type_for_def`, which contains a bunch of | ||
37 | // impossible cases. Perhaps we should recombine `TypeableDef` and `Namespace` | ||
38 | // into a `AsTypeDef`, `AsValueDef` enums? | ||
39 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
40 | pub enum Namespace { | ||
41 | Types, | ||
42 | Values, | ||
43 | // Note that only type inference uses this enum, and it doesn't care about macros. | ||
44 | // Macro, | ||
45 | } | ||
46 | |||
36 | impl Ty { | 47 | impl Ty { |
37 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | 48 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
38 | match type_ref { | 49 | match type_ref { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 4b7e34878..e56b9356e 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | use test_utils::covers; | 11 | use test_utils::covers; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | expr::BodySourceMap, mock::MockDatabase, ty::display::HirDisplay, ty::InferenceResult, | 14 | expr::BodySourceMap, test_db::TestDB, ty::display::HirDisplay, ty::InferenceResult, |
15 | SourceAnalyzer, | 15 | SourceAnalyzer, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -24,7 +24,7 @@ mod coercion; | |||
24 | 24 | ||
25 | #[test] | 25 | #[test] |
26 | fn cfg_impl_block() { | 26 | fn cfg_impl_block() { |
27 | let (db, pos) = MockDatabase::with_position( | 27 | let (db, pos) = TestDB::with_position( |
28 | r#" | 28 | r#" |
29 | //- /main.rs crate:main deps:foo cfg:test | 29 | //- /main.rs crate:main deps:foo cfg:test |
30 | use foo::S as T; | 30 | use foo::S as T; |
@@ -64,7 +64,7 @@ impl S { | |||
64 | 64 | ||
65 | #[test] | 65 | #[test] |
66 | fn infer_await() { | 66 | fn infer_await() { |
67 | let (db, pos) = MockDatabase::with_position( | 67 | let (db, pos) = TestDB::with_position( |
68 | r#" | 68 | r#" |
69 | //- /main.rs crate:main deps:std | 69 | //- /main.rs crate:main deps:std |
70 | 70 | ||
@@ -95,7 +95,7 @@ mod future { | |||
95 | 95 | ||
96 | #[test] | 96 | #[test] |
97 | fn infer_box() { | 97 | fn infer_box() { |
98 | let (db, pos) = MockDatabase::with_position( | 98 | let (db, pos) = TestDB::with_position( |
99 | r#" | 99 | r#" |
100 | //- /main.rs crate:main deps:std | 100 | //- /main.rs crate:main deps:std |
101 | 101 | ||
@@ -122,7 +122,7 @@ mod boxed { | |||
122 | 122 | ||
123 | #[test] | 123 | #[test] |
124 | fn infer_adt_self() { | 124 | fn infer_adt_self() { |
125 | let (db, pos) = MockDatabase::with_position( | 125 | let (db, pos) = TestDB::with_position( |
126 | r#" | 126 | r#" |
127 | //- /main.rs | 127 | //- /main.rs |
128 | enum Nat { Succ(Self), Demo(Nat), Zero } | 128 | enum Nat { Succ(Self), Demo(Nat), Zero } |
@@ -141,7 +141,7 @@ fn test() { | |||
141 | 141 | ||
142 | #[test] | 142 | #[test] |
143 | fn infer_try() { | 143 | fn infer_try() { |
144 | let (db, pos) = MockDatabase::with_position( | 144 | let (db, pos) = TestDB::with_position( |
145 | r#" | 145 | r#" |
146 | //- /main.rs crate:main deps:std | 146 | //- /main.rs crate:main deps:std |
147 | 147 | ||
@@ -181,7 +181,7 @@ mod result { | |||
181 | 181 | ||
182 | #[test] | 182 | #[test] |
183 | fn infer_for_loop() { | 183 | fn infer_for_loop() { |
184 | let (db, pos) = MockDatabase::with_position( | 184 | let (db, pos) = TestDB::with_position( |
185 | r#" | 185 | r#" |
186 | //- /main.rs crate:main deps:std | 186 | //- /main.rs crate:main deps:std |
187 | 187 | ||
@@ -223,7 +223,7 @@ mod collections { | |||
223 | #[test] | 223 | #[test] |
224 | fn infer_while_let() { | 224 | fn infer_while_let() { |
225 | covers!(infer_while_let); | 225 | covers!(infer_while_let); |
226 | let (db, pos) = MockDatabase::with_position( | 226 | let (db, pos) = TestDB::with_position( |
227 | r#" | 227 | r#" |
228 | //- /main.rs | 228 | //- /main.rs |
229 | enum Option<T> { Some(T), None } | 229 | enum Option<T> { Some(T), None } |
@@ -2484,7 +2484,7 @@ pub fn main_loop() { | |||
2484 | 2484 | ||
2485 | #[test] | 2485 | #[test] |
2486 | fn cross_crate_associated_method_call() { | 2486 | fn cross_crate_associated_method_call() { |
2487 | let (db, pos) = MockDatabase::with_position( | 2487 | let (db, pos) = TestDB::with_position( |
2488 | r#" | 2488 | r#" |
2489 | //- /main.rs crate:main deps:other_crate | 2489 | //- /main.rs crate:main deps:other_crate |
2490 | fn test() { | 2490 | fn test() { |
@@ -3378,7 +3378,7 @@ fn test() { S.foo()<|>; } | |||
3378 | 3378 | ||
3379 | #[test] | 3379 | #[test] |
3380 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { | 3380 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { |
3381 | let (db, pos) = MockDatabase::with_position( | 3381 | let (db, pos) = TestDB::with_position( |
3382 | r#" | 3382 | r#" |
3383 | //- /main.rs crate:main deps:foo | 3383 | //- /main.rs crate:main deps:foo |
3384 | fn test() { | 3384 | fn test() { |
@@ -3482,7 +3482,7 @@ fn test() { (&S).foo()<|>; } | |||
3482 | 3482 | ||
3483 | #[test] | 3483 | #[test] |
3484 | fn method_resolution_trait_from_prelude() { | 3484 | fn method_resolution_trait_from_prelude() { |
3485 | let (db, pos) = MockDatabase::with_position( | 3485 | let (db, pos) = TestDB::with_position( |
3486 | r#" | 3486 | r#" |
3487 | //- /main.rs crate:main deps:other_crate | 3487 | //- /main.rs crate:main deps:other_crate |
3488 | struct S; | 3488 | struct S; |
@@ -4651,7 +4651,7 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
4651 | assert_eq!(t, "{unknown}"); | 4651 | assert_eq!(t, "{unknown}"); |
4652 | } | 4652 | } |
4653 | 4653 | ||
4654 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 4654 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { |
4655 | let file = db.parse(pos.file_id).ok().unwrap(); | 4655 | let file = db.parse(pos.file_id).ok().unwrap(); |
4656 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 4656 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
4657 | let analyzer = SourceAnalyzer::new(db, pos.file_id, expr.syntax(), Some(pos.offset)); | 4657 | let analyzer = SourceAnalyzer::new(db, pos.file_id, expr.syntax(), Some(pos.offset)); |
@@ -4660,12 +4660,12 @@ fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | |||
4660 | } | 4660 | } |
4661 | 4661 | ||
4662 | fn type_at(content: &str) -> String { | 4662 | fn type_at(content: &str) -> String { |
4663 | let (db, file_pos) = MockDatabase::with_position(content); | 4663 | let (db, file_pos) = TestDB::with_position(content); |
4664 | type_at_pos(&db, file_pos) | 4664 | type_at_pos(&db, file_pos) |
4665 | } | 4665 | } |
4666 | 4666 | ||
4667 | fn infer(content: &str) -> String { | 4667 | fn infer(content: &str) -> String { |
4668 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 4668 | let (db, file_id) = TestDB::with_single_file(content); |
4669 | let source_file = db.parse(file_id).ok().unwrap(); | 4669 | let source_file = db.parse(file_id).ok().unwrap(); |
4670 | 4670 | ||
4671 | let mut acc = String::new(); | 4671 | let mut acc = String::new(); |
@@ -4748,7 +4748,7 @@ fn ellipsize(mut text: String, max_len: usize) -> String { | |||
4748 | 4748 | ||
4749 | #[test] | 4749 | #[test] |
4750 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | 4750 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { |
4751 | let (mut db, pos) = MockDatabase::with_position( | 4751 | let (mut db, pos) = TestDB::with_position( |
4752 | " | 4752 | " |
4753 | //- /lib.rs | 4753 | //- /lib.rs |
4754 | fn foo() -> i32 { | 4754 | fn foo() -> i32 { |
@@ -4788,7 +4788,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
4788 | 4788 | ||
4789 | #[test] | 4789 | #[test] |
4790 | fn no_such_field_diagnostics() { | 4790 | fn no_such_field_diagnostics() { |
4791 | let diagnostics = MockDatabase::with_files( | 4791 | let diagnostics = TestDB::with_files( |
4792 | r" | 4792 | r" |
4793 | //- /lib.rs | 4793 | //- /lib.rs |
4794 | struct S { foo: i32, bar: () } | 4794 | struct S { foo: i32, bar: () } |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 39ef92182..c694952f3 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -18,7 +18,10 @@ use crate::{ | |||
18 | db::HirDatabase, | 18 | db::HirDatabase, |
19 | generics::GenericDef, | 19 | generics::GenericDef, |
20 | ty::display::HirDisplay, | 20 | ty::display::HirDisplay, |
21 | ty::{ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk}, | 21 | ty::{ |
22 | ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
23 | TypeWalk, | ||
24 | }, | ||
22 | AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias, | 25 | AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias, |
23 | }; | 26 | }; |
24 | 27 | ||
@@ -652,7 +655,7 @@ fn impl_block_datum( | |||
652 | }) | 655 | }) |
653 | .filter_map(|t| { | 656 | .filter_map(|t| { |
654 | let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?; | 657 | let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?; |
655 | let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars); | 658 | let ty = db.type_for_def(t.into(), Namespace::Types).subst(&bound_vars); |
656 | Some(chalk_rust_ir::AssociatedTyValue { | 659 | Some(chalk_rust_ir::AssociatedTyValue { |
657 | impl_id, | 660 | impl_id, |
658 | associated_ty_id: assoc_ty.to_chalk(db), | 661 | associated_ty_id: assoc_ty.to_chalk(db), |
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 433bdde48..d3ecabb9b 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -14,10 +14,10 @@ | |||
14 | //! | 14 | //! |
15 | //! ## Collecting RawItems | 15 | //! ## Collecting RawItems |
16 | //! | 16 | //! |
17 | //! This happens in the `raw` module, which parses a single source file into a | 17 | //! This happens in the `raw` module, which parses a single source file into a |
18 | //! set of top-level items. Nested imports are desugared to flat imports in | 18 | //! set of top-level items. Nested imports are desugared to flat imports in this |
19 | //! this phase. Macro calls are represented as a triple of (Path, Option<Name>, | 19 | //! phase. Macro calls are represented as a triple of (Path, Option<Name>, |
20 | //! TokenTree). | 20 | //! TokenTree). |
21 | //! | 21 | //! |
22 | //! ## Collecting Modules | 22 | //! ## Collecting Modules |
23 | //! | 23 | //! |
@@ -44,14 +44,14 @@ | |||
44 | //! Macros from other crates (including proc-macros) can be used with | 44 | //! Macros from other crates (including proc-macros) can be used with |
45 | //! `foo::bar!` syntax. We handle them similarly to imports. There's a list of | 45 | //! `foo::bar!` syntax. We handle them similarly to imports. There's a list of |
46 | //! unexpanded macros. On every iteration, we try to resolve each macro call | 46 | //! unexpanded macros. On every iteration, we try to resolve each macro call |
47 | //! path and, upon success, we run macro expansion and "collect module" phase | 47 | //! path and, upon success, we run macro expansion and "collect module" phase on |
48 | //! on the result | 48 | //! the result |
49 | 49 | ||
50 | // FIXME: review privacy of submodules | ||
51 | pub mod raw; | 50 | pub mod raw; |
52 | pub mod per_ns; | 51 | pub mod per_ns; |
53 | pub mod collector; | 52 | mod collector; |
54 | pub mod mod_resolution; | 53 | mod mod_resolution; |
54 | mod path_resolution; | ||
55 | 55 | ||
56 | #[cfg(test)] | 56 | #[cfg(test)] |
57 | mod tests; | 57 | mod tests; |
@@ -65,14 +65,15 @@ use ra_db::{CrateId, Edition, FileId}; | |||
65 | use ra_prof::profile; | 65 | use ra_prof::profile; |
66 | use ra_syntax::ast; | 66 | use ra_syntax::ast; |
67 | use rustc_hash::{FxHashMap, FxHashSet}; | 67 | use rustc_hash::{FxHashMap, FxHashSet}; |
68 | use test_utils::tested_by; | ||
69 | 68 | ||
70 | use crate::{ | 69 | use crate::{ |
71 | builtin_type::BuiltinType, | 70 | builtin_type::BuiltinType, |
72 | db::DefDatabase2, | 71 | db::DefDatabase2, |
73 | nameres::{diagnostics::DefDiagnostic, per_ns::PerNs, raw::ImportId}, | 72 | nameres::{ |
74 | path::{Path, PathKind}, | 73 | diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, |
75 | AdtId, AstId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, TraitId, | 74 | }, |
75 | path::Path, | ||
76 | AstId, CrateModuleId, ModuleDefId, ModuleId, TraitId, | ||
76 | }; | 77 | }; |
77 | 78 | ||
78 | /// Contains all top-level defs from a macro-expanded crate | 79 | /// Contains all top-level defs from a macro-expanded crate |
@@ -195,45 +196,6 @@ pub struct Resolution { | |||
195 | pub import: Option<ImportId>, | 196 | pub import: Option<ImportId>, |
196 | } | 197 | } |
197 | 198 | ||
198 | impl Resolution { | ||
199 | pub(crate) fn from_macro(macro_: MacroDefId) -> Self { | ||
200 | Resolution { def: PerNs::macros(macro_), import: None } | ||
201 | } | ||
202 | } | ||
203 | |||
204 | #[derive(Debug, Clone)] | ||
205 | struct ResolvePathResult { | ||
206 | resolved_def: PerNs, | ||
207 | segment_index: Option<usize>, | ||
208 | reached_fixedpoint: ReachedFixedPoint, | ||
209 | } | ||
210 | |||
211 | impl ResolvePathResult { | ||
212 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | ||
213 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) | ||
214 | } | ||
215 | |||
216 | fn with( | ||
217 | resolved_def: PerNs, | ||
218 | reached_fixedpoint: ReachedFixedPoint, | ||
219 | segment_index: Option<usize>, | ||
220 | ) -> ResolvePathResult { | ||
221 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
226 | enum ResolveMode { | ||
227 | Import, | ||
228 | Other, | ||
229 | } | ||
230 | |||
231 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
232 | enum ReachedFixedPoint { | ||
233 | Yes, | ||
234 | No, | ||
235 | } | ||
236 | |||
237 | impl CrateDefMap { | 199 | impl CrateDefMap { |
238 | pub(crate) fn crate_def_map_query( | 200 | pub(crate) fn crate_def_map_query( |
239 | // Note that this doesn't have `+ AstDatabase`! | 201 | // Note that this doesn't have `+ AstDatabase`! |
@@ -296,210 +258,6 @@ impl CrateDefMap { | |||
296 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); | 258 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); |
297 | (res.resolved_def, res.segment_index) | 259 | (res.resolved_def, res.segment_index) |
298 | } | 260 | } |
299 | |||
300 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | ||
301 | // the result. | ||
302 | fn resolve_path_fp_with_macro( | ||
303 | &self, | ||
304 | db: &impl DefDatabase2, | ||
305 | mode: ResolveMode, | ||
306 | original_module: CrateModuleId, | ||
307 | path: &Path, | ||
308 | ) -> ResolvePathResult { | ||
309 | let mut segments = path.segments.iter().enumerate(); | ||
310 | let mut curr_per_ns: PerNs = match path.kind { | ||
311 | PathKind::DollarCrate(krate) => { | ||
312 | if krate == self.krate { | ||
313 | tested_by!(macro_dollar_crate_self); | ||
314 | PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into()) | ||
315 | } else { | ||
316 | let def_map = db.crate_def_map(krate); | ||
317 | let module = ModuleId { krate, module_id: def_map.root }; | ||
318 | tested_by!(macro_dollar_crate_other); | ||
319 | PerNs::types(module.into()) | ||
320 | } | ||
321 | } | ||
322 | PathKind::Crate => { | ||
323 | PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into()) | ||
324 | } | ||
325 | PathKind::Self_ => { | ||
326 | PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into()) | ||
327 | } | ||
328 | // plain import or absolute path in 2015: crate-relative with | ||
329 | // fallback to extern prelude (with the simplification in | ||
330 | // rust-lang/rust#57745) | ||
331 | // FIXME there must be a nicer way to write this condition | ||
332 | PathKind::Plain | PathKind::Abs | ||
333 | if self.edition == Edition::Edition2015 | ||
334 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | ||
335 | { | ||
336 | let segment = match segments.next() { | ||
337 | Some((_, segment)) => segment, | ||
338 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
339 | }; | ||
340 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | ||
341 | self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) | ||
342 | } | ||
343 | PathKind::Plain => { | ||
344 | let segment = match segments.next() { | ||
345 | Some((_, segment)) => segment, | ||
346 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
347 | }; | ||
348 | log::debug!("resolving {:?} in module", segment); | ||
349 | self.resolve_name_in_module(db, original_module, &segment.name) | ||
350 | } | ||
351 | PathKind::Super => { | ||
352 | if let Some(p) = self.modules[original_module].parent { | ||
353 | PerNs::types(ModuleId { krate: self.krate, module_id: p }.into()) | ||
354 | } else { | ||
355 | log::debug!("super path in root module"); | ||
356 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
357 | } | ||
358 | } | ||
359 | PathKind::Abs => { | ||
360 | // 2018-style absolute path -- only extern prelude | ||
361 | let segment = match segments.next() { | ||
362 | Some((_, segment)) => segment, | ||
363 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
364 | }; | ||
365 | if let Some(def) = self.extern_prelude.get(&segment.name) { | ||
366 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | ||
367 | PerNs::types(*def) | ||
368 | } else { | ||
369 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | ||
370 | } | ||
371 | } | ||
372 | PathKind::Type(_) => { | ||
373 | // This is handled in `infer::infer_path_expr` | ||
374 | // The result returned here does not matter | ||
375 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
376 | } | ||
377 | }; | ||
378 | |||
379 | for (i, segment) in segments { | ||
380 | let curr = match curr_per_ns.take_types() { | ||
381 | Some(r) => r, | ||
382 | None => { | ||
383 | // we still have path segments left, but the path so far | ||
384 | // didn't resolve in the types namespace => no resolution | ||
385 | // (don't break here because `curr_per_ns` might contain | ||
386 | // something in the value namespace, and it would be wrong | ||
387 | // to return that) | ||
388 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
389 | } | ||
390 | }; | ||
391 | // resolve segment in curr | ||
392 | |||
393 | curr_per_ns = match curr { | ||
394 | ModuleDefId::ModuleId(module) => { | ||
395 | if module.krate != self.krate { | ||
396 | let path = | ||
397 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; | ||
398 | log::debug!("resolving {:?} in other crate", path); | ||
399 | let defp_map = db.crate_def_map(module.krate); | ||
400 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); | ||
401 | return ResolvePathResult::with( | ||
402 | def, | ||
403 | ReachedFixedPoint::Yes, | ||
404 | s.map(|s| s + i), | ||
405 | ); | ||
406 | } | ||
407 | |||
408 | // Since it is a qualified path here, it should not contains legacy macros | ||
409 | match self[module.module_id].scope.get(&segment.name) { | ||
410 | Some(res) => res.def, | ||
411 | _ => { | ||
412 | log::debug!("path segment {:?} not found", segment.name); | ||
413 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | ||
418 | // enum variant | ||
419 | tested_by!(can_import_enum_variant); | ||
420 | let enum_data = db.enum_data(e); | ||
421 | match enum_data.variant(&segment.name) { | ||
422 | Some(local_id) => { | ||
423 | let variant = EnumVariantId { parent: e, local_id }; | ||
424 | PerNs::both(variant.into(), variant.into()) | ||
425 | } | ||
426 | None => { | ||
427 | return ResolvePathResult::with( | ||
428 | PerNs::types(e.into()), | ||
429 | ReachedFixedPoint::Yes, | ||
430 | Some(i), | ||
431 | ); | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | s => { | ||
436 | // could be an inherent method call in UFCS form | ||
437 | // (`Struct::method`), or some other kind of associated item | ||
438 | log::debug!( | ||
439 | "path segment {:?} resolved to non-module {:?}, but is not last", | ||
440 | segment.name, | ||
441 | curr, | ||
442 | ); | ||
443 | |||
444 | return ResolvePathResult::with( | ||
445 | PerNs::types(s), | ||
446 | ReachedFixedPoint::Yes, | ||
447 | Some(i), | ||
448 | ); | ||
449 | } | ||
450 | }; | ||
451 | } | ||
452 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | ||
453 | } | ||
454 | |||
455 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { | ||
456 | let from_crate_root = | ||
457 | self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); | ||
458 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | ||
459 | |||
460 | from_crate_root.or(from_extern_prelude) | ||
461 | } | ||
462 | |||
463 | pub(crate) fn resolve_name_in_module( | ||
464 | &self, | ||
465 | db: &impl DefDatabase2, | ||
466 | module: CrateModuleId, | ||
467 | name: &Name, | ||
468 | ) -> PerNs { | ||
469 | // Resolve in: | ||
470 | // - legacy scope of macro | ||
471 | // - current module / scope | ||
472 | // - extern prelude | ||
473 | // - std prelude | ||
474 | let from_legacy_macro = | ||
475 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); | ||
476 | let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); | ||
477 | let from_extern_prelude = | ||
478 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | ||
479 | let from_prelude = self.resolve_in_prelude(db, name); | ||
480 | |||
481 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) | ||
482 | } | ||
483 | |||
484 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | ||
485 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) | ||
486 | } | ||
487 | |||
488 | fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs { | ||
489 | if let Some(prelude) = self.prelude { | ||
490 | let keep; | ||
491 | let def_map = if prelude.krate == self.krate { | ||
492 | self | ||
493 | } else { | ||
494 | // Extend lifetime | ||
495 | keep = db.crate_def_map(prelude.krate); | ||
496 | &keep | ||
497 | }; | ||
498 | def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) | ||
499 | } else { | ||
500 | PerNs::none() | ||
501 | } | ||
502 | } | ||
503 | } | 261 | } |
504 | 262 | ||
505 | mod diagnostics { | 263 | mod diagnostics { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 3b61d9895..aacd50df8 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -14,8 +14,8 @@ use crate::{ | |||
14 | attr::Attr, | 14 | attr::Attr, |
15 | db::DefDatabase2, | 15 | db::DefDatabase2, |
16 | nameres::{ | 16 | nameres::{ |
17 | diagnostics::DefDiagnostic, mod_resolution::ModDir, per_ns::PerNs, raw, CrateDefMap, | 17 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
18 | ModuleData, ReachedFixedPoint, Resolution, ResolveMode, | 18 | per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, |
19 | }, | 19 | }, |
20 | path::{Path, PathKind}, | 20 | path::{Path, PathKind}, |
21 | AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, | 21 | AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, |
@@ -182,7 +182,11 @@ where | |||
182 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | 182 | // In Rust, `#[macro_export]` macros are unconditionally visible at the |
183 | // crate root, even if the parent modules is **not** visible. | 183 | // crate root, even if the parent modules is **not** visible. |
184 | if export { | 184 | if export { |
185 | self.update(self.def_map.root, None, &[(name, Resolution::from_macro(macro_))]); | 185 | self.update( |
186 | self.def_map.root, | ||
187 | None, | ||
188 | &[(name, Resolution { def: PerNs::macros(macro_), import: None })], | ||
189 | ); | ||
186 | } | 190 | } |
187 | } | 191 | } |
188 | 192 | ||
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs index f6b0b8fb1..b3b1379d0 100644 --- a/crates/ra_hir_def/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::SmolStr; | |||
6 | use crate::{db::DefDatabase2, HirFileId}; | 6 | use crate::{db::DefDatabase2, HirFileId}; |
7 | 7 | ||
8 | #[derive(Clone, Debug)] | 8 | #[derive(Clone, Debug)] |
9 | pub struct ModDir { | 9 | pub(super) struct ModDir { |
10 | /// `.` for `mod.rs`, `lib.rs` | 10 | /// `.` for `mod.rs`, `lib.rs` |
11 | /// `./foo` for `foo.rs` | 11 | /// `./foo` for `foo.rs` |
12 | /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` | 12 | /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` |
@@ -16,11 +16,15 @@ pub struct ModDir { | |||
16 | } | 16 | } |
17 | 17 | ||
18 | impl ModDir { | 18 | impl ModDir { |
19 | pub fn root() -> ModDir { | 19 | pub(super) fn root() -> ModDir { |
20 | ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } | 20 | ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } |
21 | } | 21 | } |
22 | 22 | ||
23 | pub fn descend_into_definition(&self, name: &Name, attr_path: Option<&SmolStr>) -> ModDir { | 23 | pub(super) fn descend_into_definition( |
24 | &self, | ||
25 | name: &Name, | ||
26 | attr_path: Option<&SmolStr>, | ||
27 | ) -> ModDir { | ||
24 | let mut path = self.path.clone(); | 28 | let mut path = self.path.clone(); |
25 | match attr_to_path(attr_path) { | 29 | match attr_to_path(attr_path) { |
26 | None => path.push(&name.to_string()), | 30 | None => path.push(&name.to_string()), |
@@ -34,7 +38,7 @@ impl ModDir { | |||
34 | ModDir { path, root_non_dir_owner: false } | 38 | ModDir { path, root_non_dir_owner: false } |
35 | } | 39 | } |
36 | 40 | ||
37 | pub fn resolve_declaration( | 41 | pub(super) fn resolve_declaration( |
38 | &self, | 42 | &self, |
39 | db: &impl DefDatabase2, | 43 | db: &impl DefDatabase2, |
40 | file_id: HirFileId, | 44 | file_id: HirFileId, |
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs new file mode 100644 index 000000000..95692f826 --- /dev/null +++ b/crates/ra_hir_def/src/nameres/path_resolution.rs | |||
@@ -0,0 +1,261 @@ | |||
1 | //! This modules implements a function to resolve a path `foo::bar::baz` to a | ||
2 | //! def, which is used within the name resolution. | ||
3 | //! | ||
4 | //! When name resolution is finished, the result of resolving a path is either | ||
5 | //! `Some(def)` or `None`. However, when we are in process of resolving imports | ||
6 | //! or macros, there's a third possibility: | ||
7 | //! | ||
8 | //! I can't resolve this path right now, but I might be resolve this path | ||
9 | //! later, when more macros are expanded. | ||
10 | //! | ||
11 | //! `ReachedFixedPoint` signals about this. | ||
12 | |||
13 | use hir_expand::name::Name; | ||
14 | use ra_db::Edition; | ||
15 | use test_utils::tested_by; | ||
16 | |||
17 | use crate::{ | ||
18 | db::DefDatabase2, | ||
19 | nameres::{per_ns::PerNs, CrateDefMap}, | ||
20 | path::{Path, PathKind}, | ||
21 | AdtId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, | ||
22 | }; | ||
23 | |||
24 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
25 | pub(super) enum ResolveMode { | ||
26 | Import, | ||
27 | Other, | ||
28 | } | ||
29 | |||
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
31 | pub(super) enum ReachedFixedPoint { | ||
32 | Yes, | ||
33 | No, | ||
34 | } | ||
35 | |||
36 | #[derive(Debug, Clone)] | ||
37 | pub(super) struct ResolvePathResult { | ||
38 | pub(super) resolved_def: PerNs, | ||
39 | pub(super) segment_index: Option<usize>, | ||
40 | pub(super) reached_fixedpoint: ReachedFixedPoint, | ||
41 | } | ||
42 | |||
43 | impl ResolvePathResult { | ||
44 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | ||
45 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) | ||
46 | } | ||
47 | |||
48 | fn with( | ||
49 | resolved_def: PerNs, | ||
50 | reached_fixedpoint: ReachedFixedPoint, | ||
51 | segment_index: Option<usize>, | ||
52 | ) -> ResolvePathResult { | ||
53 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl CrateDefMap { | ||
58 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | ||
59 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) | ||
60 | } | ||
61 | |||
62 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | ||
63 | // the result. | ||
64 | pub(super) fn resolve_path_fp_with_macro( | ||
65 | &self, | ||
66 | db: &impl DefDatabase2, | ||
67 | mode: ResolveMode, | ||
68 | original_module: CrateModuleId, | ||
69 | path: &Path, | ||
70 | ) -> ResolvePathResult { | ||
71 | let mut segments = path.segments.iter().enumerate(); | ||
72 | let mut curr_per_ns: PerNs = match path.kind { | ||
73 | PathKind::DollarCrate(krate) => { | ||
74 | if krate == self.krate { | ||
75 | tested_by!(macro_dollar_crate_self); | ||
76 | PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into()) | ||
77 | } else { | ||
78 | let def_map = db.crate_def_map(krate); | ||
79 | let module = ModuleId { krate, module_id: def_map.root }; | ||
80 | tested_by!(macro_dollar_crate_other); | ||
81 | PerNs::types(module.into()) | ||
82 | } | ||
83 | } | ||
84 | PathKind::Crate => { | ||
85 | PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into()) | ||
86 | } | ||
87 | PathKind::Self_ => { | ||
88 | PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into()) | ||
89 | } | ||
90 | // plain import or absolute path in 2015: crate-relative with | ||
91 | // fallback to extern prelude (with the simplification in | ||
92 | // rust-lang/rust#57745) | ||
93 | // FIXME there must be a nicer way to write this condition | ||
94 | PathKind::Plain | PathKind::Abs | ||
95 | if self.edition == Edition::Edition2015 | ||
96 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | ||
97 | { | ||
98 | let segment = match segments.next() { | ||
99 | Some((_, segment)) => segment, | ||
100 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
101 | }; | ||
102 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | ||
103 | self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) | ||
104 | } | ||
105 | PathKind::Plain => { | ||
106 | let segment = match segments.next() { | ||
107 | Some((_, segment)) => segment, | ||
108 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
109 | }; | ||
110 | log::debug!("resolving {:?} in module", segment); | ||
111 | self.resolve_name_in_module(db, original_module, &segment.name) | ||
112 | } | ||
113 | PathKind::Super => { | ||
114 | if let Some(p) = self.modules[original_module].parent { | ||
115 | PerNs::types(ModuleId { krate: self.krate, module_id: p }.into()) | ||
116 | } else { | ||
117 | log::debug!("super path in root module"); | ||
118 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
119 | } | ||
120 | } | ||
121 | PathKind::Abs => { | ||
122 | // 2018-style absolute path -- only extern prelude | ||
123 | let segment = match segments.next() { | ||
124 | Some((_, segment)) => segment, | ||
125 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
126 | }; | ||
127 | if let Some(def) = self.extern_prelude.get(&segment.name) { | ||
128 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | ||
129 | PerNs::types(*def) | ||
130 | } else { | ||
131 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | ||
132 | } | ||
133 | } | ||
134 | PathKind::Type(_) => { | ||
135 | // This is handled in `infer::infer_path_expr` | ||
136 | // The result returned here does not matter | ||
137 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
138 | } | ||
139 | }; | ||
140 | |||
141 | for (i, segment) in segments { | ||
142 | let curr = match curr_per_ns.take_types() { | ||
143 | Some(r) => r, | ||
144 | None => { | ||
145 | // we still have path segments left, but the path so far | ||
146 | // didn't resolve in the types namespace => no resolution | ||
147 | // (don't break here because `curr_per_ns` might contain | ||
148 | // something in the value namespace, and it would be wrong | ||
149 | // to return that) | ||
150 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
151 | } | ||
152 | }; | ||
153 | // resolve segment in curr | ||
154 | |||
155 | curr_per_ns = match curr { | ||
156 | ModuleDefId::ModuleId(module) => { | ||
157 | if module.krate != self.krate { | ||
158 | let path = | ||
159 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; | ||
160 | log::debug!("resolving {:?} in other crate", path); | ||
161 | let defp_map = db.crate_def_map(module.krate); | ||
162 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); | ||
163 | return ResolvePathResult::with( | ||
164 | def, | ||
165 | ReachedFixedPoint::Yes, | ||
166 | s.map(|s| s + i), | ||
167 | ); | ||
168 | } | ||
169 | |||
170 | // Since it is a qualified path here, it should not contains legacy macros | ||
171 | match self[module.module_id].scope.get(&segment.name) { | ||
172 | Some(res) => res.def, | ||
173 | _ => { | ||
174 | log::debug!("path segment {:?} not found", segment.name); | ||
175 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | ||
180 | // enum variant | ||
181 | tested_by!(can_import_enum_variant); | ||
182 | let enum_data = db.enum_data(e); | ||
183 | match enum_data.variant(&segment.name) { | ||
184 | Some(local_id) => { | ||
185 | let variant = EnumVariantId { parent: e, local_id }; | ||
186 | PerNs::both(variant.into(), variant.into()) | ||
187 | } | ||
188 | None => { | ||
189 | return ResolvePathResult::with( | ||
190 | PerNs::types(e.into()), | ||
191 | ReachedFixedPoint::Yes, | ||
192 | Some(i), | ||
193 | ); | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | s => { | ||
198 | // could be an inherent method call in UFCS form | ||
199 | // (`Struct::method`), or some other kind of associated item | ||
200 | log::debug!( | ||
201 | "path segment {:?} resolved to non-module {:?}, but is not last", | ||
202 | segment.name, | ||
203 | curr, | ||
204 | ); | ||
205 | |||
206 | return ResolvePathResult::with( | ||
207 | PerNs::types(s), | ||
208 | ReachedFixedPoint::Yes, | ||
209 | Some(i), | ||
210 | ); | ||
211 | } | ||
212 | }; | ||
213 | } | ||
214 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | ||
215 | } | ||
216 | |||
217 | fn resolve_name_in_module( | ||
218 | &self, | ||
219 | db: &impl DefDatabase2, | ||
220 | module: CrateModuleId, | ||
221 | name: &Name, | ||
222 | ) -> PerNs { | ||
223 | // Resolve in: | ||
224 | // - legacy scope of macro | ||
225 | // - current module / scope | ||
226 | // - extern prelude | ||
227 | // - std prelude | ||
228 | let from_legacy_macro = | ||
229 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); | ||
230 | let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); | ||
231 | let from_extern_prelude = | ||
232 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | ||
233 | let from_prelude = self.resolve_in_prelude(db, name); | ||
234 | |||
235 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) | ||
236 | } | ||
237 | |||
238 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { | ||
239 | let from_crate_root = | ||
240 | self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); | ||
241 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | ||
242 | |||
243 | from_crate_root.or(from_extern_prelude) | ||
244 | } | ||
245 | |||
246 | fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs { | ||
247 | if let Some(prelude) = self.prelude { | ||
248 | let keep; | ||
249 | let def_map = if prelude.krate == self.krate { | ||
250 | self | ||
251 | } else { | ||
252 | // Extend lifetime | ||
253 | keep = db.crate_def_map(prelude.krate); | ||
254 | &keep | ||
255 | }; | ||
256 | def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) | ||
257 | } else { | ||
258 | PerNs::none() | ||
259 | } | ||
260 | } | ||
261 | } | ||
diff --git a/crates/ra_hir_def/src/nameres/per_ns.rs b/crates/ra_hir_def/src/nameres/per_ns.rs index 298b0b0c7..717ed1ef9 100644 --- a/crates/ra_hir_def/src/nameres/per_ns.rs +++ b/crates/ra_hir_def/src/nameres/per_ns.rs | |||
@@ -4,14 +4,6 @@ use hir_expand::MacroDefId; | |||
4 | 4 | ||
5 | use crate::ModuleDefId; | 5 | use crate::ModuleDefId; |
6 | 6 | ||
7 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
8 | pub enum Namespace { | ||
9 | Types, | ||
10 | Values, | ||
11 | // Note that only type inference uses this enum, and it doesn't care about macros. | ||
12 | // Macro, | ||
13 | } | ||
14 | |||
15 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 7 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
16 | pub struct PerNs { | 8 | pub struct PerNs { |
17 | pub types: Option<ModuleDefId>, | 9 | pub types: Option<ModuleDefId>, |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index cb47fa317..369376f30 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -88,7 +88,7 @@ impl RawItems { | |||
88 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) | 88 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) |
89 | } | 89 | } |
90 | 90 | ||
91 | pub fn items(&self) -> &[RawItem] { | 91 | pub(super) fn items(&self) -> &[RawItem] { |
92 | &self.items | 92 | &self.items |
93 | } | 93 | } |
94 | } | 94 | } |
@@ -125,19 +125,19 @@ impl Index<Macro> for RawItems { | |||
125 | type Attrs = Option<Arc<[Attr]>>; | 125 | type Attrs = Option<Arc<[Attr]>>; |
126 | 126 | ||
127 | #[derive(Debug, PartialEq, Eq, Clone)] | 127 | #[derive(Debug, PartialEq, Eq, Clone)] |
128 | pub struct RawItem { | 128 | pub(super) struct RawItem { |
129 | attrs: Attrs, | 129 | attrs: Attrs, |
130 | pub kind: RawItemKind, | 130 | pub(super) kind: RawItemKind, |
131 | } | 131 | } |
132 | 132 | ||
133 | impl RawItem { | 133 | impl RawItem { |
134 | pub fn attrs(&self) -> &[Attr] { | 134 | pub(super) fn attrs(&self) -> &[Attr] { |
135 | self.attrs.as_ref().map_or(&[], |it| &*it) | 135 | self.attrs.as_ref().map_or(&[], |it| &*it) |
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
139 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 139 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
140 | pub enum RawItemKind { | 140 | pub(super) enum RawItemKind { |
141 | Module(Module), | 141 | Module(Module), |
142 | Import(ImportId), | 142 | Import(ImportId), |
143 | Def(Def), | 143 | Def(Def), |
@@ -145,11 +145,11 @@ pub enum RawItemKind { | |||
145 | } | 145 | } |
146 | 146 | ||
147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
148 | pub struct Module(RawId); | 148 | pub(super) struct Module(RawId); |
149 | impl_arena_id!(Module); | 149 | impl_arena_id!(Module); |
150 | 150 | ||
151 | #[derive(Debug, PartialEq, Eq)] | 151 | #[derive(Debug, PartialEq, Eq)] |
152 | pub enum ModuleData { | 152 | pub(super) enum ModuleData { |
153 | Declaration { name: Name, ast_id: FileAstId<ast::Module> }, | 153 | Declaration { name: Name, ast_id: FileAstId<ast::Module> }, |
154 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, | 154 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, |
155 | } | 155 | } |
@@ -160,26 +160,26 @@ impl_arena_id!(ImportId); | |||
160 | 160 | ||
161 | #[derive(Debug, Clone, PartialEq, Eq)] | 161 | #[derive(Debug, Clone, PartialEq, Eq)] |
162 | pub struct ImportData { | 162 | pub struct ImportData { |
163 | pub path: Path, | 163 | pub(super) path: Path, |
164 | pub alias: Option<Name>, | 164 | pub(super) alias: Option<Name>, |
165 | pub is_glob: bool, | 165 | pub(super) is_glob: bool, |
166 | pub is_prelude: bool, | 166 | pub(super) is_prelude: bool, |
167 | pub is_extern_crate: bool, | 167 | pub(super) is_extern_crate: bool, |
168 | pub is_macro_use: bool, | 168 | pub(super) is_macro_use: bool, |
169 | } | 169 | } |
170 | 170 | ||
171 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 171 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
172 | pub struct Def(RawId); | 172 | pub(super) struct Def(RawId); |
173 | impl_arena_id!(Def); | 173 | impl_arena_id!(Def); |
174 | 174 | ||
175 | #[derive(Debug, PartialEq, Eq)] | 175 | #[derive(Debug, PartialEq, Eq)] |
176 | pub struct DefData { | 176 | pub(super) struct DefData { |
177 | pub name: Name, | 177 | pub(super) name: Name, |
178 | pub kind: DefKind, | 178 | pub(super) kind: DefKind, |
179 | } | 179 | } |
180 | 180 | ||
181 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 181 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
182 | pub enum DefKind { | 182 | pub(super) enum DefKind { |
183 | Function(FileAstId<ast::FnDef>), | 183 | Function(FileAstId<ast::FnDef>), |
184 | Struct(FileAstId<ast::StructDef>), | 184 | Struct(FileAstId<ast::StructDef>), |
185 | Union(FileAstId<ast::StructDef>), | 185 | Union(FileAstId<ast::StructDef>), |
@@ -191,15 +191,15 @@ pub enum DefKind { | |||
191 | } | 191 | } |
192 | 192 | ||
193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
194 | pub struct Macro(RawId); | 194 | pub(super) struct Macro(RawId); |
195 | impl_arena_id!(Macro); | 195 | impl_arena_id!(Macro); |
196 | 196 | ||
197 | #[derive(Debug, PartialEq, Eq)] | 197 | #[derive(Debug, PartialEq, Eq)] |
198 | pub struct MacroData { | 198 | pub(super) struct MacroData { |
199 | pub ast_id: FileAstId<ast::MacroCall>, | 199 | pub(super) ast_id: FileAstId<ast::MacroCall>, |
200 | pub path: Path, | 200 | pub(super) path: Path, |
201 | pub name: Option<Name>, | 201 | pub(super) name: Option<Name>, |
202 | pub export: bool, | 202 | pub(super) export: bool, |
203 | } | 203 | } |
204 | 204 | ||
205 | struct RawItemsCollector { | 205 | struct RawItemsCollector { |
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs index 60ed3518b..4f9565441 100644 --- a/crates/ra_ide_api/src/completion/complete_postfix.rs +++ b/crates/ra_ide_api/src/completion/complete_postfix.rs | |||
@@ -1,5 +1,9 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{Ty, TypeCtor}; | ||
4 | use ra_syntax::{ast::AstNode, TextRange, TextUnit}; | ||
5 | use ra_text_edit::TextEdit; | ||
6 | |||
3 | use crate::{ | 7 | use crate::{ |
4 | completion::{ | 8 | completion::{ |
5 | completion_context::CompletionContext, | 9 | completion_context::CompletionContext, |
@@ -7,9 +11,53 @@ use crate::{ | |||
7 | }, | 11 | }, |
8 | CompletionItem, | 12 | CompletionItem, |
9 | }; | 13 | }; |
10 | use hir::{Ty, TypeCtor}; | 14 | |
11 | use ra_syntax::{ast::AstNode, TextRange, TextUnit}; | 15 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { |
12 | use ra_text_edit::TextEdit; | 16 | let dot_receiver = match &ctx.dot_receiver { |
17 | Some(it) => it, | ||
18 | None => return, | ||
19 | }; | ||
20 | |||
21 | let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal { | ||
22 | let text = dot_receiver.syntax().text(); | ||
23 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
24 | text.slice(without_dot).to_string() | ||
25 | } else { | ||
26 | dot_receiver.syntax().text().to_string() | ||
27 | }; | ||
28 | |||
29 | let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); | ||
30 | |||
31 | if is_bool_or_unknown(receiver_ty) { | ||
32 | postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) | ||
33 | .add_to(acc); | ||
34 | postfix_snippet( | ||
35 | ctx, | ||
36 | "while", | ||
37 | "while expr {}", | ||
38 | &format!("while {} {{\n$0\n}}", receiver_text), | ||
39 | ) | ||
40 | .add_to(acc); | ||
41 | } | ||
42 | |||
43 | postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | ||
44 | |||
45 | postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); | ||
46 | postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); | ||
47 | |||
48 | postfix_snippet( | ||
49 | ctx, | ||
50 | "match", | ||
51 | "match expr {}", | ||
52 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), | ||
53 | ) | ||
54 | .add_to(acc); | ||
55 | |||
56 | postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); | ||
57 | |||
58 | postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text)) | ||
59 | .add_to(acc); | ||
60 | } | ||
13 | 61 | ||
14 | fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { | 62 | fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { |
15 | let edit = { | 63 | let edit = { |
@@ -24,62 +72,19 @@ fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: | |||
24 | } | 72 | } |
25 | 73 | ||
26 | fn is_bool_or_unknown(ty: Option<Ty>) -> bool { | 74 | fn is_bool_or_unknown(ty: Option<Ty>) -> bool { |
27 | if let Some(ty) = ty { | 75 | match &ty { |
28 | match ty { | 76 | Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true, |
29 | Ty::Apply(at) => match at.ctor { | 77 | Some(Ty::Unknown) | None => true, |
30 | TypeCtor::Bool => true, | 78 | Some(_) => false, |
31 | _ => false, | ||
32 | }, | ||
33 | Ty::Unknown => true, | ||
34 | _ => false, | ||
35 | } | ||
36 | } else { | ||
37 | true | ||
38 | } | ||
39 | } | ||
40 | |||
41 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | ||
42 | if let Some(dot_receiver) = &ctx.dot_receiver { | ||
43 | let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal { | ||
44 | let text = dot_receiver.syntax().text(); | ||
45 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
46 | text.slice(without_dot).to_string() | ||
47 | } else { | ||
48 | dot_receiver.syntax().text().to_string() | ||
49 | }; | ||
50 | let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); | ||
51 | if is_bool_or_unknown(receiver_ty) { | ||
52 | postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) | ||
53 | .add_to(acc); | ||
54 | postfix_snippet( | ||
55 | ctx, | ||
56 | "while", | ||
57 | "while expr {}", | ||
58 | &format!("while {} {{\n$0\n}}", receiver_text), | ||
59 | ) | ||
60 | .add_to(acc); | ||
61 | } | ||
62 | postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | ||
63 | postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); | ||
64 | postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); | ||
65 | postfix_snippet( | ||
66 | ctx, | ||
67 | "match", | ||
68 | "match expr {}", | ||
69 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), | ||
70 | ) | ||
71 | .add_to(acc); | ||
72 | postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); | ||
73 | postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text)) | ||
74 | .add_to(acc); | ||
75 | } | 79 | } |
76 | } | 80 | } |
77 | 81 | ||
78 | #[cfg(test)] | 82 | #[cfg(test)] |
79 | mod tests { | 83 | mod tests { |
80 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
81 | use insta::assert_debug_snapshot; | 84 | use insta::assert_debug_snapshot; |
82 | 85 | ||
86 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
87 | |||
83 | fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { | 88 | fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { |
84 | do_completion(code, CompletionKind::Postfix) | 89 | do_completion(code, CompletionKind::Postfix) |
85 | } | 90 | } |
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index cb55d1875..d861303b7 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | 2 | ||
3 | use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; | 3 | use hir::{db::HirDatabase, Attrs, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::{AttrsOwner, NameOwner}; | 5 | use ra_syntax::ast::NameOwner; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use crate::completion::{ | 8 | use crate::completion::{ |
@@ -18,11 +18,7 @@ impl Completions { | |||
18 | field: hir::StructField, | 18 | field: hir::StructField, |
19 | substs: &hir::Substs, | 19 | substs: &hir::Substs, |
20 | ) { | 20 | ) { |
21 | let ast_node = field.source(ctx.db).ast; | 21 | let is_deprecated = is_deprecated(field, ctx.db); |
22 | let is_deprecated = match ast_node { | ||
23 | hir::FieldSource::Named(m) => is_deprecated(m), | ||
24 | hir::FieldSource::Pos(m) => is_deprecated(m), | ||
25 | }; | ||
26 | CompletionItem::new( | 22 | CompletionItem::new( |
27 | CompletionKind::Reference, | 23 | CompletionKind::Reference, |
28 | ctx.source_range(), | 24 | ctx.source_range(), |
@@ -185,7 +181,7 @@ impl Completions { | |||
185 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) | 181 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) |
186 | .kind(CompletionItemKind::Macro) | 182 | .kind(CompletionItemKind::Macro) |
187 | .set_documentation(docs.clone()) | 183 | .set_documentation(docs.clone()) |
188 | .set_deprecated(is_deprecated(ast_node)) | 184 | .set_deprecated(is_deprecated(macro_, ctx.db)) |
189 | .detail(detail); | 185 | .detail(detail); |
190 | 186 | ||
191 | builder = if ctx.use_item_syntax.is_some() { | 187 | builder = if ctx.use_item_syntax.is_some() { |
@@ -218,7 +214,7 @@ impl Completions { | |||
218 | CompletionItemKind::Function | 214 | CompletionItemKind::Function |
219 | }) | 215 | }) |
220 | .set_documentation(func.docs(ctx.db)) | 216 | .set_documentation(func.docs(ctx.db)) |
221 | .set_deprecated(is_deprecated(ast_node)) | 217 | .set_deprecated(is_deprecated(func, ctx.db)) |
222 | .detail(detail); | 218 | .detail(detail); |
223 | 219 | ||
224 | // Add `<>` for generic types | 220 | // Add `<>` for generic types |
@@ -250,7 +246,7 @@ impl Completions { | |||
250 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | 246 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) |
251 | .kind(CompletionItemKind::Const) | 247 | .kind(CompletionItemKind::Const) |
252 | .set_documentation(constant.docs(ctx.db)) | 248 | .set_documentation(constant.docs(ctx.db)) |
253 | .set_deprecated(is_deprecated(ast_node)) | 249 | .set_deprecated(is_deprecated(constant, ctx.db)) |
254 | .detail(detail) | 250 | .detail(detail) |
255 | .add_to(self); | 251 | .add_to(self); |
256 | } | 252 | } |
@@ -266,13 +262,13 @@ impl Completions { | |||
266 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | 262 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) |
267 | .kind(CompletionItemKind::TypeAlias) | 263 | .kind(CompletionItemKind::TypeAlias) |
268 | .set_documentation(type_alias.docs(ctx.db)) | 264 | .set_documentation(type_alias.docs(ctx.db)) |
269 | .set_deprecated(is_deprecated(type_def)) | 265 | .set_deprecated(is_deprecated(type_alias, ctx.db)) |
270 | .detail(detail) | 266 | .detail(detail) |
271 | .add_to(self); | 267 | .add_to(self); |
272 | } | 268 | } |
273 | 269 | ||
274 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { | 270 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { |
275 | let is_deprecated = is_deprecated(variant.source(ctx.db).ast); | 271 | let is_deprecated = is_deprecated(variant, ctx.db); |
276 | let name = match variant.name(ctx.db) { | 272 | let name = match variant.name(ctx.db) { |
277 | Some(it) => it, | 273 | Some(it) => it, |
278 | None => return, | 274 | None => return, |
@@ -291,8 +287,11 @@ impl Completions { | |||
291 | } | 287 | } |
292 | } | 288 | } |
293 | 289 | ||
294 | fn is_deprecated(node: impl AttrsOwner) -> bool { | 290 | fn is_deprecated(node: impl Attrs, db: &impl HirDatabase) -> bool { |
295 | node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated") | 291 | match node.attrs(db) { |
292 | None => false, | ||
293 | Some(attrs) => attrs.iter().any(|x| x.is_simple_atom("deprecated")), | ||
294 | } | ||
296 | } | 295 | } |
297 | 296 | ||
298 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { | 297 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index dd4d3bf9a..743f6a60a 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -9,7 +9,7 @@ threadpool = "1.7.1" | |||
9 | relative-path = "1.0.0" | 9 | relative-path = "1.0.0" |
10 | serde_json = "1.0.34" | 10 | serde_json = "1.0.34" |
11 | serde = { version = "1.0.83", features = ["derive"] } | 11 | serde = { version = "1.0.83", features = ["derive"] } |
12 | crossbeam-channel = "0.3.5" | 12 | crossbeam-channel = "0.4" |
13 | flexi_logger = "0.14.0" | 13 | flexi_logger = "0.14.0" |
14 | log = "0.4.3" | 14 | log = "0.4.3" |
15 | lsp-types = { version = "0.61.0", features = ["proposed"] } | 15 | lsp-types = { version = "0.61.0", features = ["proposed"] } |
@@ -20,7 +20,7 @@ ra_vfs = "0.5.0" | |||
20 | ra_syntax = { path = "../ra_syntax" } | 20 | ra_syntax = { path = "../ra_syntax" } |
21 | ra_text_edit = { path = "../ra_text_edit" } | 21 | ra_text_edit = { path = "../ra_text_edit" } |
22 | ra_ide_api = { path = "../ra_ide_api" } | 22 | ra_ide_api = { path = "../ra_ide_api" } |
23 | lsp-server = "0.2.0" | 23 | lsp-server = "0.3.0" |
24 | ra_project_model = { path = "../ra_project_model" } | 24 | ra_project_model = { path = "../ra_project_model" } |
25 | ra_prof = { path = "../ra_prof" } | 25 | ra_prof = { path = "../ra_prof" } |
26 | ra_vfs_glob = { path = "../ra_vfs_glob" } | 26 | ra_vfs_glob = { path = "../ra_vfs_glob" } |
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index d4ca94fca..9b2e440fb 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs | |||
@@ -28,7 +28,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { | |||
28 | T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p), | 28 | T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p), |
29 | T![for] => for_type(p), | 29 | T![for] => for_type(p), |
30 | T![impl] => impl_trait_type(p), | 30 | T![impl] => impl_trait_type(p), |
31 | T![dyn ] => dyn_trait_type(p), | 31 | T![dyn] => dyn_trait_type(p), |
32 | // Some path types are not allowed to have bounds (no plus) | 32 | // Some path types are not allowed to have bounds (no plus) |
33 | T![<] => path_type_(p, allow_bounds), | 33 | T![<] => path_type_(p, allow_bounds), |
34 | _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds), | 34 | _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds), |
@@ -234,9 +234,9 @@ fn impl_trait_type(p: &mut Parser) { | |||
234 | // test dyn_trait_type | 234 | // test dyn_trait_type |
235 | // type A = dyn Iterator<Item=Foo<'a>> + 'a; | 235 | // type A = dyn Iterator<Item=Foo<'a>> + 'a; |
236 | fn dyn_trait_type(p: &mut Parser) { | 236 | fn dyn_trait_type(p: &mut Parser) { |
237 | assert!(p.at(T![dyn ])); | 237 | assert!(p.at(T![dyn])); |
238 | let m = p.start(); | 238 | let m = p.start(); |
239 | p.bump(T![dyn ]); | 239 | p.bump(T![dyn]); |
240 | type_params::bounds_without_colon(p); | 240 | type_params::bounds_without_colon(p); |
241 | m.complete(p, DYN_TRAIT_TYPE); | 241 | m.complete(p, DYN_TRAIT_TYPE); |
242 | } | 242 | } |