diff options
48 files changed, 2387 insertions, 2379 deletions
diff --git a/Cargo.lock b/Cargo.lock index 1dedf9772..d7ec266c0 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1135,7 +1135,7 @@ dependencies = [ | |||
1135 | "ra_syntax 0.1.0", | 1135 | "ra_syntax 0.1.0", |
1136 | "ra_tt 0.1.0", | 1136 | "ra_tt 0.1.0", |
1137 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1137 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1138 | "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", | 1138 | "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1139 | "test_utils 0.1.0", | 1139 | "test_utils 0.1.0", |
1140 | ] | 1140 | ] |
1141 | 1141 | ||
@@ -1604,6 +1604,11 @@ dependencies = [ | |||
1604 | ] | 1604 | ] |
1605 | 1605 | ||
1606 | [[package]] | 1606 | [[package]] |
1607 | name = "smallvec" | ||
1608 | version = "1.0.0" | ||
1609 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1610 | |||
1611 | [[package]] | ||
1607 | name = "smol_str" | 1612 | name = "smol_str" |
1608 | version = "0.1.15" | 1613 | version = "0.1.15" |
1609 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -2007,6 +2012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
2007 | "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" | 2012 | "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" |
2008 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | 2013 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" |
2009 | "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" | 2014 | "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" |
2015 | "checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" | ||
2010 | "checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" | 2016 | "checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" |
2011 | "checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a" | 2017 | "checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a" |
2012 | "checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" | 2018 | "checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" |
diff --git a/Cargo.toml b/Cargo.toml index 5c57020f7..92e3228f0 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -8,6 +8,6 @@ debug = 0 | |||
8 | 8 | ||
9 | [profile.release] | 9 | [profile.release] |
10 | incremental = true | 10 | incremental = true |
11 | debug = 1 # only line info | 11 | debug = 0 # set this to 1 or 2 to get more useful backtraces in debugger |
12 | 12 | ||
13 | [patch.'crates-io'] | 13 | [patch.'crates-io'] |
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs index a8839cfba..2038afdc6 100644 --- a/crates/ra_assists/src/assists/add_new.rs +++ b/crates/ra_assists/src/assists/add_new.rs | |||
@@ -158,9 +158,12 @@ fn find_struct_impl( | |||
158 | let same_ty = blk.target_ty(db) == struct_ty; | 158 | let same_ty = blk.target_ty(db) == struct_ty; |
159 | let not_trait_impl = blk.target_trait(db).is_none(); | 159 | let not_trait_impl = blk.target_trait(db).is_none(); |
160 | 160 | ||
161 | found_new_fn = has_new_fn(impl_blk); | 161 | if !(same_ty && not_trait_impl) { |
162 | return false; | ||
163 | } | ||
162 | 164 | ||
163 | same_ty && not_trait_impl | 165 | found_new_fn = has_new_fn(impl_blk); |
166 | true | ||
164 | }); | 167 | }); |
165 | 168 | ||
166 | if found_new_fn { | 169 | if found_new_fn { |
@@ -186,9 +189,10 @@ fn has_new_fn(imp: &ast::ImplBlock) -> bool { | |||
186 | 189 | ||
187 | #[cfg(test)] | 190 | #[cfg(test)] |
188 | mod tests { | 191 | mod tests { |
189 | use super::*; | ||
190 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 192 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; |
191 | 193 | ||
194 | use super::*; | ||
195 | |||
192 | #[test] | 196 | #[test] |
193 | #[rustfmt::skip] | 197 | #[rustfmt::skip] |
194 | fn test_add_new() { | 198 | fn test_add_new() { |
@@ -345,7 +349,7 @@ struct Foo {<|>} | |||
345 | impl Foo { | 349 | impl Foo { |
346 | fn new() -> Self { | 350 | fn new() -> Self { |
347 | Self | 351 | Self |
348 | } | 352 | } |
349 | }", | 353 | }", |
350 | ); | 354 | ); |
351 | 355 | ||
@@ -357,7 +361,7 @@ struct Foo {<|>} | |||
357 | impl Foo { | 361 | impl Foo { |
358 | fn New() -> Self { | 362 | fn New() -> Self { |
359 | Self | 363 | Self |
360 | } | 364 | } |
361 | }", | 365 | }", |
362 | ); | 366 | ); |
363 | } | 367 | } |
@@ -376,4 +380,59 @@ struct EvenMoreIrrelevant; | |||
376 | struct Foo<'a, T: Foo<'a>> {}", | 380 | struct Foo<'a, T: Foo<'a>> {}", |
377 | ); | 381 | ); |
378 | } | 382 | } |
383 | |||
384 | #[test] | ||
385 | fn test_unrelated_new() { | ||
386 | check_assist( | ||
387 | add_new, | ||
388 | r##" | ||
389 | pub struct AstId<N: AstNode> { | ||
390 | file_id: HirFileId, | ||
391 | file_ast_id: FileAstId<N>, | ||
392 | } | ||
393 | |||
394 | impl<N: AstNode> AstId<N> { | ||
395 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
396 | AstId { file_id, file_ast_id } | ||
397 | } | ||
398 | } | ||
399 | |||
400 | pub struct Source<T> { | ||
401 | pub file_id: HirFileId,<|> | ||
402 | pub ast: T, | ||
403 | } | ||
404 | |||
405 | impl<T> Source<T> { | ||
406 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
407 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
408 | } | ||
409 | } | ||
410 | "##, | ||
411 | r##" | ||
412 | pub struct AstId<N: AstNode> { | ||
413 | file_id: HirFileId, | ||
414 | file_ast_id: FileAstId<N>, | ||
415 | } | ||
416 | |||
417 | impl<N: AstNode> AstId<N> { | ||
418 | pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> { | ||
419 | AstId { file_id, file_ast_id } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | pub struct Source<T> { | ||
424 | pub file_id: HirFileId, | ||
425 | pub ast: T, | ||
426 | } | ||
427 | |||
428 | impl<T> Source<T> { | ||
429 | pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|> | ||
430 | |||
431 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
432 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
433 | } | ||
434 | } | ||
435 | "##, | ||
436 | ); | ||
437 | } | ||
379 | } | 438 | } |
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index ee883b615..ade187629 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -8,8 +8,8 @@ use rustc_hash::FxHashMap; | |||
8 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | 8 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | CrateGraph, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, SourceRoot, | 11 | CrateGraph, CrateId, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, |
12 | SourceRootId, | 12 | SourceRoot, SourceRootId, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | 15 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
@@ -33,6 +33,14 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { | |||
33 | let pos = with_files(&mut db, fixture); | 33 | let pos = with_files(&mut db, fixture); |
34 | (db, pos.unwrap()) | 34 | (db, pos.unwrap()) |
35 | } | 35 | } |
36 | |||
37 | fn test_crate(&self) -> CrateId { | ||
38 | let crate_graph = self.crate_graph(); | ||
39 | let mut it = crate_graph.iter(); | ||
40 | let res = it.next().unwrap(); | ||
41 | assert!(it.next().is_none()); | ||
42 | res | ||
43 | } | ||
36 | } | 44 | } |
37 | 45 | ||
38 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} | 46 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 962d5a8c1..731cc1fff 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -11,7 +11,7 @@ use hir_def::{ | |||
11 | body::scope::ExprScopes, | 11 | body::scope::ExprScopes, |
12 | builtin_type::BuiltinType, | 12 | builtin_type::BuiltinType, |
13 | type_ref::{Mutability, TypeRef}, | 13 | type_ref::{Mutability, TypeRef}, |
14 | CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, | 14 | CrateModuleId, ImplId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, |
15 | }; | 15 | }; |
16 | use hir_expand::{ | 16 | use hir_expand::{ |
17 | diagnostics::DiagnosticSink, | 17 | diagnostics::DiagnosticSink, |
@@ -23,13 +23,12 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | |||
23 | use crate::{ | 23 | use crate::{ |
24 | adt::VariantDef, | 24 | adt::VariantDef, |
25 | db::{AstDatabase, DefDatabase, HirDatabase}, | 25 | db::{AstDatabase, DefDatabase, HirDatabase}, |
26 | expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId}, | 26 | expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, |
27 | generics::{GenericDef, HasGenericParams}, | 27 | generics::{GenericDef, HasGenericParams}, |
28 | ids::{ | 28 | ids::{ |
29 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, | 29 | AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, |
30 | TypeAliasId, | 30 | TypeAliasId, |
31 | }, | 31 | }, |
32 | impl_block::ImplBlock, | ||
33 | resolve::{Resolver, Scope, TypeNs}, | 32 | resolve::{Resolver, Scope, TypeNs}, |
34 | traits::TraitData, | 33 | traits::TraitData, |
35 | ty::{InferenceResult, Namespace, TraitRef}, | 34 | ty::{InferenceResult, Namespace, TraitRef}, |
@@ -157,7 +156,7 @@ impl Module { | |||
157 | } | 156 | } |
158 | 157 | ||
159 | /// Finds a child module with the specified name. | 158 | /// Finds a child module with the specified name. |
160 | pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> { | 159 | pub fn child(self, db: &impl DefDatabase, name: &Name) -> Option<Module> { |
161 | let def_map = db.crate_def_map(self.id.krate); | 160 | let def_map = db.crate_def_map(self.id.krate); |
162 | let child_id = def_map[self.id.module_id].children.get(name)?; | 161 | let child_id = def_map[self.id.module_id].children.get(name)?; |
163 | Some(self.with_module_id(*child_id)) | 162 | Some(self.with_module_id(*child_id)) |
@@ -243,12 +242,8 @@ impl Module { | |||
243 | } | 242 | } |
244 | 243 | ||
245 | pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { | 244 | pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { |
246 | let module_impl_blocks = db.impls_in_module(self); | 245 | let def_map = db.crate_def_map(self.id.krate); |
247 | module_impl_blocks | 246 | def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect() |
248 | .impls | ||
249 | .iter() | ||
250 | .map(|(impl_id, _)| ImplBlock::from_id(self, impl_id)) | ||
251 | .collect() | ||
252 | } | 247 | } |
253 | 248 | ||
254 | fn with_module_id(self, module_id: CrateModuleId) -> Module { | 249 | fn with_module_id(self, module_id: CrateModuleId) -> Module { |
@@ -693,8 +688,7 @@ impl Function { | |||
693 | 688 | ||
694 | /// The containing impl block, if this is a method. | 689 | /// The containing impl block, if this is a method. |
695 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 690 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
696 | let module_impls = db.impls_in_module(self.module(db)); | 691 | ImplBlock::containing(db, self.into()) |
697 | ImplBlock::containing(module_impls, self.into()) | ||
698 | } | 692 | } |
699 | 693 | ||
700 | /// The containing trait, if this is a trait method definition. | 694 | /// The containing trait, if this is a trait method definition. |
@@ -759,8 +753,7 @@ impl Const { | |||
759 | 753 | ||
760 | /// The containing impl block, if this is a method. | 754 | /// The containing impl block, if this is a method. |
761 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 755 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
762 | let module_impls = db.impls_in_module(self.module(db)); | 756 | ImplBlock::containing(db, self.into()) |
763 | ImplBlock::containing(module_impls, self.into()) | ||
764 | } | 757 | } |
765 | 758 | ||
766 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { | 759 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { |
@@ -973,8 +966,7 @@ impl TypeAlias { | |||
973 | 966 | ||
974 | /// The containing impl block, if this is a method. | 967 | /// The containing impl block, if this is a method. |
975 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 968 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
976 | let module_impls = db.impls_in_module(self.module(db)); | 969 | ImplBlock::containing(db, self.into()) |
977 | ImplBlock::containing(module_impls, self.into()) | ||
978 | } | 970 | } |
979 | 971 | ||
980 | /// The containing trait, if this is a trait method definition. | 972 | /// The containing trait, if this is a trait method definition. |
@@ -1137,3 +1129,8 @@ pub struct GenericParam { | |||
1137 | pub(crate) parent: GenericDef, | 1129 | pub(crate) parent: GenericDef, |
1138 | pub(crate) idx: u32, | 1130 | pub(crate) idx: u32, |
1139 | } | 1131 | } |
1132 | |||
1133 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1134 | pub struct ImplBlock { | ||
1135 | pub(crate) id: ImplId, | ||
1136 | } | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index c60029c01..276b0774f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -10,7 +10,6 @@ use crate::{ | |||
10 | debug::HirDebugDatabase, | 10 | debug::HirDebugDatabase, |
11 | generics::{GenericDef, GenericParams}, | 11 | generics::{GenericDef, GenericParams}, |
12 | ids, | 12 | ids, |
13 | impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, | ||
14 | lang_item::{LangItemTarget, LangItems}, | 13 | lang_item::{LangItemTarget, LangItems}, |
15 | traits::TraitData, | 14 | traits::TraitData, |
16 | ty::{ | 15 | ty::{ |
@@ -18,14 +17,14 @@ use crate::{ | |||
18 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, | 17 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, |
19 | }, | 18 | }, |
20 | type_alias::TypeAliasData, | 19 | type_alias::TypeAliasData, |
21 | Const, ConstData, Crate, DefWithBody, FnData, Function, Module, Static, StructField, Trait, | 20 | Const, ConstData, Crate, DefWithBody, FnData, Function, ImplBlock, Module, Static, StructField, |
22 | TypeAlias, | 21 | Trait, TypeAlias, |
23 | }; | 22 | }; |
24 | 23 | ||
25 | pub use hir_def::db::{ | 24 | pub use hir_def::db::{ |
26 | BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, | 25 | BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, |
27 | EnumDataQuery, ExprScopesQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, | 26 | EnumDataQuery, ExprScopesQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage, |
28 | RawItemsWithSourceMapQuery, StructDataQuery, | 27 | RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, |
29 | }; | 28 | }; |
30 | pub use hir_expand::db::{ | 29 | pub use hir_expand::db::{ |
31 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, | 30 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, |
@@ -42,15 +41,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { | |||
42 | #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] | 41 | #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] |
43 | fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; | 42 | fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; |
44 | 43 | ||
45 | #[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)] | ||
46 | fn impls_in_module_with_source_map( | ||
47 | &self, | ||
48 | module: Module, | ||
49 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>); | ||
50 | |||
51 | #[salsa::invoke(ModuleImplBlocks::impls_in_module_query)] | ||
52 | fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; | ||
53 | |||
54 | #[salsa::invoke(crate::generics::GenericParams::generic_params_query)] | 44 | #[salsa::invoke(crate::generics::GenericParams::generic_params_query)] |
55 | fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>; | 45 | fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>; |
56 | 46 | ||
@@ -128,7 +118,7 @@ pub trait HirDatabase: DefDatabase + AstDatabase { | |||
128 | #[salsa::interned] | 118 | #[salsa::interned] |
129 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; | 119 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; |
130 | #[salsa::interned] | 120 | #[salsa::interned] |
131 | fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; | 121 | fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId; |
132 | 122 | ||
133 | #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] | 123 | #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] |
134 | fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc<chalk_rust_ir::AssociatedTyDatum>; | 124 | fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc<chalk_rust_ir::AssociatedTyDatum>; |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 9262325f2..e3733779e 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -1,12 +1,19 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | pub(crate) mod validation; | ||
4 | |||
5 | use std::sync::Arc; | 3 | use std::sync::Arc; |
6 | 4 | ||
5 | use hir_def::path::known; | ||
6 | use hir_expand::diagnostics::DiagnosticSink; | ||
7 | use ra_syntax::ast; | ||
7 | use ra_syntax::AstPtr; | 8 | use ra_syntax::AstPtr; |
9 | use rustc_hash::FxHashSet; | ||
8 | 10 | ||
9 | use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; | 11 | use crate::{ |
12 | db::HirDatabase, | ||
13 | diagnostics::{MissingFields, MissingOkInTailExpr}, | ||
14 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | ||
15 | Adt, DefWithBody, Function, HasBody, Name, Path, Resolver, | ||
16 | }; | ||
10 | 17 | ||
11 | pub use hir_def::{ | 18 | pub use hir_def::{ |
12 | body::{ | 19 | body::{ |
@@ -38,196 +45,126 @@ pub(crate) fn resolver_for_scope( | |||
38 | let scopes = owner.expr_scopes(db); | 45 | let scopes = owner.expr_scopes(db); |
39 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); | 46 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); |
40 | for scope in scope_chain.into_iter().rev() { | 47 | for scope in scope_chain.into_iter().rev() { |
41 | r = r.push_expr_scope(Arc::clone(&scopes), scope); | 48 | r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); |
42 | } | 49 | } |
43 | r | 50 | r |
44 | } | 51 | } |
45 | 52 | ||
46 | #[cfg(test)] | 53 | pub(crate) struct ExprValidator<'a, 'b: 'a> { |
47 | mod tests { | 54 | func: Function, |
48 | use hir_expand::Source; | 55 | infer: Arc<InferenceResult>, |
49 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 56 | sink: &'a mut DiagnosticSink<'b>, |
50 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | 57 | } |
51 | use test_utils::{assert_eq_text, extract_offset}; | ||
52 | |||
53 | use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; | ||
54 | |||
55 | fn do_check(code: &str, expected: &[&str]) { | ||
56 | let (off, code) = extract_offset(code); | ||
57 | let code = { | ||
58 | let mut buf = String::new(); | ||
59 | let off = u32::from(off) as usize; | ||
60 | buf.push_str(&code[..off]); | ||
61 | buf.push_str("marker"); | ||
62 | buf.push_str(&code[off..]); | ||
63 | buf | ||
64 | }; | ||
65 | 58 | ||
66 | let (db, file_id) = TestDB::with_single_file(&code); | 59 | impl<'a, 'b> ExprValidator<'a, 'b> { |
67 | 60 | pub(crate) fn new( | |
68 | let file = db.parse(file_id).ok().unwrap(); | 61 | func: Function, |
69 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 62 | infer: Arc<InferenceResult>, |
70 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); | 63 | sink: &'a mut DiagnosticSink<'b>, |
71 | 64 | ) -> ExprValidator<'a, 'b> { | |
72 | let scopes = analyzer.scopes(); | 65 | ExprValidator { func, infer, sink } |
73 | let expr_id = analyzer | ||
74 | .body_source_map() | ||
75 | .node_expr(Source { file_id: file_id.into(), ast: &marker.into() }) | ||
76 | .unwrap(); | ||
77 | let scope = scopes.scope_for(expr_id); | ||
78 | |||
79 | let actual = scopes | ||
80 | .scope_chain(scope) | ||
81 | .flat_map(|scope| scopes.entries(scope)) | ||
82 | .map(|it| it.name().to_string()) | ||
83 | .collect::<Vec<_>>() | ||
84 | .join("\n"); | ||
85 | let expected = expected.join("\n"); | ||
86 | assert_eq_text!(&expected, &actual); | ||
87 | } | 66 | } |
88 | 67 | ||
89 | #[test] | 68 | pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { |
90 | fn test_lambda_scope() { | 69 | let body = self.func.body(db); |
91 | do_check( | ||
92 | r" | ||
93 | fn quux(foo: i32) { | ||
94 | let f = |bar, baz: i32| { | ||
95 | <|> | ||
96 | }; | ||
97 | }", | ||
98 | &["bar", "baz", "foo"], | ||
99 | ); | ||
100 | } | ||
101 | 70 | ||
102 | #[test] | 71 | for e in body.exprs() { |
103 | fn test_call_scope() { | 72 | if let (id, Expr::RecordLit { path, fields, spread }) = e { |
104 | do_check( | 73 | self.validate_record_literal(id, path, fields, *spread, db); |
105 | r" | 74 | } |
106 | fn quux() { | 75 | } |
107 | f(|x| <|> ); | ||
108 | }", | ||
109 | &["x"], | ||
110 | ); | ||
111 | } | ||
112 | 76 | ||
113 | #[test] | 77 | let body_expr = &body[body.body_expr()]; |
114 | fn test_method_call_scope() { | 78 | if let Expr::Block { statements: _, tail: Some(t) } = body_expr { |
115 | do_check( | 79 | self.validate_results_in_tail_expr(body.body_expr(), *t, db); |
116 | r" | 80 | } |
117 | fn quux() { | ||
118 | z.f(|x| <|> ); | ||
119 | }", | ||
120 | &["x"], | ||
121 | ); | ||
122 | } | 81 | } |
123 | 82 | ||
124 | #[test] | 83 | fn validate_record_literal( |
125 | fn test_loop_scope() { | 84 | &mut self, |
126 | do_check( | 85 | id: ExprId, |
127 | r" | 86 | _path: &Option<Path>, |
128 | fn quux() { | 87 | fields: &[RecordLitField], |
129 | loop { | 88 | spread: Option<ExprId>, |
130 | let x = (); | 89 | db: &impl HirDatabase, |
131 | <|> | 90 | ) { |
132 | }; | 91 | if spread.is_some() { |
133 | }", | 92 | return; |
134 | &["x"], | 93 | } |
135 | ); | 94 | |
136 | } | 95 | let struct_def = match self.infer[id].as_adt() { |
96 | Some((Adt::Struct(s), _)) => s, | ||
97 | _ => return, | ||
98 | }; | ||
137 | 99 | ||
138 | #[test] | 100 | let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); |
139 | fn test_match() { | 101 | let missed_fields: Vec<Name> = struct_def |
140 | do_check( | 102 | .fields(db) |
141 | r" | 103 | .iter() |
142 | fn quux() { | 104 | .filter_map(|f| { |
143 | match () { | 105 | let name = f.name(db); |
144 | Some(x) => { | 106 | if lit_fields.contains(&name) { |
145 | <|> | 107 | None |
108 | } else { | ||
109 | Some(name) | ||
110 | } | ||
111 | }) | ||
112 | .collect(); | ||
113 | if missed_fields.is_empty() { | ||
114 | return; | ||
115 | } | ||
116 | let source_map = self.func.body_source_map(db); | ||
117 | |||
118 | if let Some(source_ptr) = source_map.expr_syntax(id) { | ||
119 | if let Some(expr) = source_ptr.ast.a() { | ||
120 | let root = source_ptr.file_syntax(db); | ||
121 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { | ||
122 | if let Some(field_list) = record_lit.record_field_list() { | ||
123 | self.sink.push(MissingFields { | ||
124 | file: source_ptr.file_id, | ||
125 | field_list: AstPtr::new(&field_list), | ||
126 | missed_fields, | ||
127 | }) | ||
146 | } | 128 | } |
147 | }; | 129 | } |
148 | }", | 130 | } |
149 | &["x"], | 131 | } |
150 | ); | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn test_shadow_variable() { | ||
155 | do_check( | ||
156 | r" | ||
157 | fn foo(x: String) { | ||
158 | let x : &str = &x<|>; | ||
159 | }", | ||
160 | &["x"], | ||
161 | ); | ||
162 | } | 132 | } |
163 | 133 | ||
164 | fn do_check_local_name(code: &str, expected_offset: u32) { | 134 | fn validate_results_in_tail_expr( |
165 | let (off, code) = extract_offset(code); | 135 | &mut self, |
166 | 136 | body_id: ExprId, | |
167 | let (db, file_id) = TestDB::with_single_file(&code); | 137 | id: ExprId, |
168 | let file = db.parse(file_id).ok().unwrap(); | 138 | db: &impl HirDatabase, |
169 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | 139 | ) { |
170 | .expect("failed to find a name at the target offset"); | 140 | // the mismatch will be on the whole block currently |
171 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 141 | let mismatch = match self.infer.type_mismatch_for_expr(body_id) { |
172 | let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); | 142 | Some(m) => m, |
143 | None => return, | ||
144 | }; | ||
173 | 145 | ||
174 | let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap(); | 146 | let std_result_path = known::std_result_result(); |
175 | let local_name = | ||
176 | local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
177 | assert_eq!(local_name.range(), expected_name.syntax().text_range()); | ||
178 | } | ||
179 | 147 | ||
180 | #[test] | 148 | let resolver = self.func.resolver(db); |
181 | fn test_resolve_local_name() { | 149 | let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { |
182 | do_check_local_name( | 150 | Some(it) => it, |
183 | r#" | 151 | _ => return, |
184 | fn foo(x: i32, y: u32) { | 152 | }; |
185 | { | ||
186 | let z = x * 2; | ||
187 | } | ||
188 | { | ||
189 | let t = x<|> * 3; | ||
190 | } | ||
191 | }"#, | ||
192 | 21, | ||
193 | ); | ||
194 | } | ||
195 | 153 | ||
196 | #[test] | 154 | let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum)); |
197 | fn test_resolve_local_name_declaration() { | 155 | let params = match &mismatch.expected { |
198 | do_check_local_name( | 156 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, |
199 | r#" | 157 | _ => return, |
200 | fn foo(x: String) { | 158 | }; |
201 | let x : &str = &x<|>; | ||
202 | }"#, | ||
203 | 21, | ||
204 | ); | ||
205 | } | ||
206 | 159 | ||
207 | #[test] | 160 | if params.len() == 2 && ¶ms[0] == &mismatch.actual { |
208 | fn test_resolve_local_name_shadow() { | 161 | let source_map = self.func.body_source_map(db); |
209 | do_check_local_name( | ||
210 | r" | ||
211 | fn foo(x: String) { | ||
212 | let x : &str = &x; | ||
213 | x<|> | ||
214 | } | ||
215 | ", | ||
216 | 53, | ||
217 | ); | ||
218 | } | ||
219 | 162 | ||
220 | #[test] | 163 | if let Some(source_ptr) = source_map.expr_syntax(id) { |
221 | fn ref_patterns_contribute_bindings() { | 164 | if let Some(expr) = source_ptr.ast.a() { |
222 | do_check_local_name( | 165 | self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); |
223 | r" | ||
224 | fn foo() { | ||
225 | if let Some(&from) = bar() { | ||
226 | from<|>; | ||
227 | } | 166 | } |
228 | } | 167 | } |
229 | ", | 168 | } |
230 | 53, | ||
231 | ); | ||
232 | } | 169 | } |
233 | } | 170 | } |
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs deleted file mode 100644 index 3054f1dce..000000000 --- a/crates/ra_hir/src/expr/validation.rs +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_def::path::known; | ||
6 | use hir_expand::diagnostics::DiagnosticSink; | ||
7 | use ra_syntax::ast; | ||
8 | use rustc_hash::FxHashSet; | ||
9 | |||
10 | use crate::{ | ||
11 | db::HirDatabase, | ||
12 | diagnostics::{MissingFields, MissingOkInTailExpr}, | ||
13 | expr::AstPtr, | ||
14 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | ||
15 | Adt, Function, Name, Path, | ||
16 | }; | ||
17 | |||
18 | use super::{Expr, ExprId, RecordLitField}; | ||
19 | |||
20 | pub(crate) struct ExprValidator<'a, 'b: 'a> { | ||
21 | func: Function, | ||
22 | infer: Arc<InferenceResult>, | ||
23 | sink: &'a mut DiagnosticSink<'b>, | ||
24 | } | ||
25 | |||
26 | impl<'a, 'b> ExprValidator<'a, 'b> { | ||
27 | pub(crate) fn new( | ||
28 | func: Function, | ||
29 | infer: Arc<InferenceResult>, | ||
30 | sink: &'a mut DiagnosticSink<'b>, | ||
31 | ) -> ExprValidator<'a, 'b> { | ||
32 | ExprValidator { func, infer, sink } | ||
33 | } | ||
34 | |||
35 | pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { | ||
36 | let body = self.func.body(db); | ||
37 | |||
38 | for e in body.exprs() { | ||
39 | if let (id, Expr::RecordLit { path, fields, spread }) = e { | ||
40 | self.validate_record_literal(id, path, fields, *spread, db); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | let body_expr = &body[body.body_expr()]; | ||
45 | if let Expr::Block { statements: _, tail: Some(t) } = body_expr { | ||
46 | self.validate_results_in_tail_expr(body.body_expr(), *t, db); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | fn validate_record_literal( | ||
51 | &mut self, | ||
52 | id: ExprId, | ||
53 | _path: &Option<Path>, | ||
54 | fields: &[RecordLitField], | ||
55 | spread: Option<ExprId>, | ||
56 | db: &impl HirDatabase, | ||
57 | ) { | ||
58 | if spread.is_some() { | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | let struct_def = match self.infer[id].as_adt() { | ||
63 | Some((Adt::Struct(s), _)) => s, | ||
64 | _ => return, | ||
65 | }; | ||
66 | |||
67 | let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); | ||
68 | let missed_fields: Vec<Name> = struct_def | ||
69 | .fields(db) | ||
70 | .iter() | ||
71 | .filter_map(|f| { | ||
72 | let name = f.name(db); | ||
73 | if lit_fields.contains(&name) { | ||
74 | None | ||
75 | } else { | ||
76 | Some(name) | ||
77 | } | ||
78 | }) | ||
79 | .collect(); | ||
80 | if missed_fields.is_empty() { | ||
81 | return; | ||
82 | } | ||
83 | let source_map = self.func.body_source_map(db); | ||
84 | |||
85 | if let Some(source_ptr) = source_map.expr_syntax(id) { | ||
86 | if let Some(expr) = source_ptr.ast.a() { | ||
87 | let root = source_ptr.file_syntax(db); | ||
88 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { | ||
89 | if let Some(field_list) = record_lit.record_field_list() { | ||
90 | self.sink.push(MissingFields { | ||
91 | file: source_ptr.file_id, | ||
92 | field_list: AstPtr::new(&field_list), | ||
93 | missed_fields, | ||
94 | }) | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | fn validate_results_in_tail_expr( | ||
102 | &mut self, | ||
103 | body_id: ExprId, | ||
104 | id: ExprId, | ||
105 | db: &impl HirDatabase, | ||
106 | ) { | ||
107 | // the mismatch will be on the whole block currently | ||
108 | let mismatch = match self.infer.type_mismatch_for_expr(body_id) { | ||
109 | Some(m) => m, | ||
110 | None => return, | ||
111 | }; | ||
112 | |||
113 | let std_result_path = known::std_result_result(); | ||
114 | |||
115 | let resolver = self.func.resolver(db); | ||
116 | let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { | ||
117 | Some(it) => it, | ||
118 | _ => return, | ||
119 | }; | ||
120 | |||
121 | let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum)); | ||
122 | let params = match &mismatch.expected { | ||
123 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, | ||
124 | _ => return, | ||
125 | }; | ||
126 | |||
127 | if params.len() == 2 && ¶ms[0] == &mismatch.actual { | ||
128 | let source_map = self.func.body_source_map(db); | ||
129 | |||
130 | if let Some(source_ptr) = source_map.expr_syntax(id) { | ||
131 | if let Some(expr) = source_ptr.ast.a() { | ||
132 | self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | } | ||
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs index 9633ef586..f2203e995 100644 --- a/crates/ra_hir/src/from_id.rs +++ b/crates/ra_hir/src/from_id.rs | |||
@@ -3,9 +3,9 @@ | |||
3 | //! It's unclear if we need this long-term, but it's definitelly useful while we | 3 | //! It's unclear if we need this long-term, but it's definitelly useful while we |
4 | //! are splitting the hir. | 4 | //! are splitting the hir. |
5 | 5 | ||
6 | use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; | 6 | use hir_def::{AdtId, AssocItemId, DefWithBodyId, EnumVariantId, ModuleDefId}; |
7 | 7 | ||
8 | use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; | 8 | use crate::{Adt, AssocItem, DefWithBody, EnumVariant, ModuleDef}; |
9 | 9 | ||
10 | macro_rules! from_id { | 10 | macro_rules! from_id { |
11 | ($(($id:path, $ty:path)),*) => {$( | 11 | ($(($id:path, $ty:path)),*) => {$( |
@@ -27,6 +27,7 @@ from_id![ | |||
27 | (hir_def::StaticId, crate::Static), | 27 | (hir_def::StaticId, crate::Static), |
28 | (hir_def::ConstId, crate::Const), | 28 | (hir_def::ConstId, crate::Const), |
29 | (hir_def::FunctionId, crate::Function), | 29 | (hir_def::FunctionId, crate::Function), |
30 | (hir_def::ImplId, crate::ImplBlock), | ||
30 | (hir_expand::MacroDefId, crate::MacroDef) | 31 | (hir_expand::MacroDefId, crate::MacroDef) |
31 | ]; | 32 | ]; |
32 | 33 | ||
@@ -71,3 +72,13 @@ impl From<DefWithBody> for DefWithBodyId { | |||
71 | } | 72 | } |
72 | } | 73 | } |
73 | } | 74 | } |
75 | |||
76 | impl From<AssocItemId> for AssocItem { | ||
77 | fn from(def: AssocItemId) -> Self { | ||
78 | match def { | ||
79 | AssocItemId::FunctionId(it) => AssocItem::Function(it.into()), | ||
80 | AssocItemId::TypeAliasId(it) => AssocItem::TypeAlias(it.into()), | ||
81 | AssocItemId::ConstId(it) => AssocItem::Const(it.into()), | ||
82 | } | ||
83 | } | ||
84 | } | ||
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 9793af858..ec56dfa6a 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir_def::{StructId, StructOrUnionId, UnionId}; | 3 | use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; |
4 | use hir_expand::name::AsName; | 4 | use hir_expand::name::AsName; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 6 | ast::{self, AstNode, NameOwner}, |
@@ -10,9 +10,9 @@ use ra_syntax::{ | |||
10 | use crate::{ | 10 | use crate::{ |
11 | db::{AstDatabase, DefDatabase, HirDatabase}, | 11 | db::{AstDatabase, DefDatabase, HirDatabase}, |
12 | ids::{AstItemDef, LocationCtx}, | 12 | ids::{AstItemDef, LocationCtx}, |
13 | AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, | 13 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, |
14 | ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, | 14 | Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, |
15 | Union, VariantDef, | 15 | VariantDef, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub trait FromSource: Sized { | 18 | pub trait FromSource: Sized { |
@@ -82,14 +82,8 @@ impl FromSource for TypeAlias { | |||
82 | impl FromSource for ImplBlock { | 82 | impl FromSource for ImplBlock { |
83 | type Ast = ast::ImplBlock; | 83 | type Ast = ast::ImplBlock; |
84 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 84 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
85 | let module_src = crate::ModuleSource::from_child_node( | 85 | let id = from_source(db, src)?; |
86 | db, | 86 | Some(ImplBlock { id }) |
87 | src.file_id.original_file(db), | ||
88 | &src.ast.syntax(), | ||
89 | ); | ||
90 | let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?; | ||
91 | let impls = module.impl_blocks(db); | ||
92 | impls.into_iter().find(|b| b.source(db) == src) | ||
93 | } | 87 | } |
94 | } | 88 | } |
95 | 89 | ||
@@ -152,44 +146,48 @@ impl Local { | |||
152 | } | 146 | } |
153 | 147 | ||
154 | impl Module { | 148 | impl Module { |
155 | pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { | 149 | pub fn from_declaration(db: &impl DefDatabase, src: Source<ast::Module>) -> Option<Self> { |
156 | let src_parent = Source { | 150 | let parent_declaration = src.ast.syntax().ancestors().skip(1).find_map(ast::Module::cast); |
157 | file_id: src.file_id, | 151 | |
158 | ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), | 152 | let parent_module = match parent_declaration { |
159 | }; | 153 | Some(parent_declaration) => { |
160 | let parent_module = Module::from_definition(db, src_parent)?; | 154 | let src_parent = Source { file_id: src.file_id, ast: parent_declaration }; |
155 | Module::from_declaration(db, src_parent) | ||
156 | } | ||
157 | _ => { | ||
158 | let src_parent = Source { | ||
159 | file_id: src.file_id, | ||
160 | ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), | ||
161 | }; | ||
162 | Module::from_definition(db, src_parent) | ||
163 | } | ||
164 | }?; | ||
165 | |||
161 | let child_name = src.ast.name()?; | 166 | let child_name = src.ast.name()?; |
162 | parent_module.child(db, &child_name.as_name()) | 167 | parent_module.child(db, &child_name.as_name()) |
163 | } | 168 | } |
164 | 169 | ||
165 | pub fn from_definition( | 170 | pub fn from_definition(db: &impl DefDatabase, src: Source<ModuleSource>) -> Option<Self> { |
166 | db: &(impl DefDatabase + AstDatabase), | 171 | match src.ast { |
167 | src: Source<ModuleSource>, | ||
168 | ) -> Option<Self> { | ||
169 | let decl_id = match src.ast { | ||
170 | ModuleSource::Module(ref module) => { | 172 | ModuleSource::Module(ref module) => { |
171 | assert!(!module.has_semi()); | 173 | assert!(!module.has_semi()); |
172 | let ast_id_map = db.ast_id_map(src.file_id); | 174 | return Module::from_declaration( |
173 | let item_id = AstId::new(src.file_id, ast_id_map.ast_id(module)); | 175 | db, |
174 | Some(item_id) | 176 | Source { file_id: src.file_id, ast: module.clone() }, |
177 | ); | ||
175 | } | 178 | } |
176 | ModuleSource::SourceFile(_) => None, | 179 | ModuleSource::SourceFile(_) => (), |
177 | }; | 180 | }; |
178 | 181 | ||
179 | db.relevant_crates(src.file_id.original_file(db)).iter().find_map(|&crate_id| { | 182 | let original_file = src.file_id.original_file(db); |
180 | let def_map = db.crate_def_map(crate_id); | ||
181 | |||
182 | let (module_id, _module_data) = | ||
183 | def_map.modules.iter().find(|(_module_id, module_data)| { | ||
184 | if decl_id.is_some() { | ||
185 | module_data.declaration == decl_id | ||
186 | } else { | ||
187 | module_data.definition.map(|it| it.into()) == Some(src.file_id) | ||
188 | } | ||
189 | })?; | ||
190 | 183 | ||
191 | Some(Module::new(Crate { crate_id }, module_id)) | 184 | let (krate, module_id) = |
192 | }) | 185 | db.relevant_crates(original_file).iter().find_map(|&crate_id| { |
186 | let crate_def_map = db.crate_def_map(crate_id); | ||
187 | let local_module_id = crate_def_map.modules_for_file(original_file).next()?; | ||
188 | Some((crate_id, local_module_id)) | ||
189 | })?; | ||
190 | Some(Module { id: ModuleId { krate, module_id } }) | ||
193 | } | 191 | } |
194 | } | 192 | } |
195 | 193 | ||
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index b1a014074..0c2bb8fee 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -1,88 +1,38 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use rustc_hash::FxHashMap; | 3 | use hir_def::{type_ref::TypeRef, AstItemDef}; |
4 | use std::sync::Arc; | 4 | use ra_syntax::ast::{self}; |
5 | |||
6 | use hir_def::{attr::Attr, type_ref::TypeRef}; | ||
7 | use hir_expand::hygiene::Hygiene; | ||
8 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | ||
9 | use ra_cfg::CfgOptions; | ||
10 | use ra_syntax::{ | ||
11 | ast::{self, AstNode}, | ||
12 | AstPtr, | ||
13 | }; | ||
14 | 5 | ||
15 | use crate::{ | 6 | use crate::{ |
16 | code_model::{Module, ModuleSource}, | ||
17 | db::{AstDatabase, DefDatabase, HirDatabase}, | 7 | db::{AstDatabase, DefDatabase, HirDatabase}, |
18 | generics::HasGenericParams, | 8 | generics::HasGenericParams, |
19 | ids::LocationCtx, | ||
20 | ids::MacroCallLoc, | ||
21 | resolve::Resolver, | 9 | resolve::Resolver, |
22 | ty::Ty, | 10 | ty::Ty, |
23 | AssocItem, AstId, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, | 11 | AssocItem, Crate, HasSource, ImplBlock, Module, Source, TraitRef, |
24 | TypeAlias, | ||
25 | }; | 12 | }; |
26 | 13 | ||
27 | #[derive(Debug, Default, PartialEq, Eq)] | ||
28 | pub struct ImplSourceMap { | ||
29 | map: ArenaMap<ImplId, Source<AstPtr<ast::ImplBlock>>>, | ||
30 | } | ||
31 | |||
32 | impl ImplSourceMap { | ||
33 | fn insert(&mut self, impl_id: ImplId, file_id: HirFileId, impl_block: &ast::ImplBlock) { | ||
34 | let source = Source { file_id, ast: AstPtr::new(impl_block) }; | ||
35 | self.map.insert(impl_id, source) | ||
36 | } | ||
37 | |||
38 | pub fn get(&self, db: &impl AstDatabase, impl_id: ImplId) -> Source<ast::ImplBlock> { | ||
39 | let src = self.map[impl_id]; | ||
40 | let root = src.file_syntax(db); | ||
41 | src.map(|ptr| ptr.to_node(&root)) | ||
42 | } | ||
43 | } | ||
44 | |||
45 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
46 | pub struct ImplBlock { | ||
47 | module: Module, | ||
48 | impl_id: ImplId, | ||
49 | } | ||
50 | |||
51 | impl HasSource for ImplBlock { | 14 | impl HasSource for ImplBlock { |
52 | type Ast = ast::ImplBlock; | 15 | type Ast = ast::ImplBlock; |
53 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { | 16 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> { |
54 | let source_map = db.impls_in_module_with_source_map(self.module).1; | 17 | self.id.source(db) |
55 | source_map.get(db, self.impl_id) | ||
56 | } | 18 | } |
57 | } | 19 | } |
58 | 20 | ||
59 | impl ImplBlock { | 21 | impl ImplBlock { |
60 | pub(crate) fn containing( | 22 | pub(crate) fn containing(db: &impl DefDatabase, item: AssocItem) -> Option<ImplBlock> { |
61 | module_impl_blocks: Arc<ModuleImplBlocks>, | 23 | let module = item.module(db); |
62 | item: AssocItem, | 24 | let crate_def_map = db.crate_def_map(module.id.krate); |
63 | ) -> Option<ImplBlock> { | 25 | crate_def_map[module.id.module_id].impls.iter().copied().map(ImplBlock::from).find(|it| { |
64 | let impl_id = *module_impl_blocks.impls_by_def.get(&item)?; | 26 | db.impl_data(it.id).items().iter().copied().map(AssocItem::from).any(|it| it == item) |
65 | Some(ImplBlock { module: module_impl_blocks.module, impl_id }) | 27 | }) |
66 | } | ||
67 | |||
68 | pub(crate) fn from_id(module: Module, impl_id: ImplId) -> ImplBlock { | ||
69 | ImplBlock { module, impl_id } | ||
70 | } | ||
71 | |||
72 | pub fn id(&self) -> ImplId { | ||
73 | self.impl_id | ||
74 | } | ||
75 | |||
76 | pub fn module(&self) -> Module { | ||
77 | self.module | ||
78 | } | 28 | } |
79 | 29 | ||
80 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { | 30 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { |
81 | db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() | 31 | db.impl_data(self.id).target_trait().cloned() |
82 | } | 32 | } |
83 | 33 | ||
84 | pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef { | 34 | pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef { |
85 | db.impls_in_module(self.module).impls[self.impl_id].target_type().clone() | 35 | db.impl_data(self.id).target_type().clone() |
86 | } | 36 | } |
87 | 37 | ||
88 | pub fn target_ty(&self, db: &impl HirDatabase) -> Ty { | 38 | pub fn target_ty(&self, db: &impl HirDatabase) -> Ty { |
@@ -95,15 +45,23 @@ impl ImplBlock { | |||
95 | } | 45 | } |
96 | 46 | ||
97 | pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { | 47 | pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { |
98 | db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() | 48 | db.impl_data(self.id).items().iter().map(|it| (*it).into()).collect() |
99 | } | 49 | } |
100 | 50 | ||
101 | pub fn is_negative(&self, db: &impl DefDatabase) -> bool { | 51 | pub fn is_negative(&self, db: &impl DefDatabase) -> bool { |
102 | db.impls_in_module(self.module).impls[self.impl_id].negative | 52 | db.impl_data(self.id).is_negative() |
53 | } | ||
54 | |||
55 | pub fn module(&self, db: &impl DefDatabase) -> Module { | ||
56 | self.id.module(db).into() | ||
57 | } | ||
58 | |||
59 | pub fn krate(&self, db: &impl DefDatabase) -> Crate { | ||
60 | Crate { crate_id: self.module(db).id.krate } | ||
103 | } | 61 | } |
104 | 62 | ||
105 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { | 63 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { |
106 | let r = self.module().resolver(db); | 64 | let r = self.module(db).resolver(db); |
107 | // add generic params, if present | 65 | // add generic params, if present |
108 | let p = self.generic_params(db); | 66 | let p = self.generic_params(db); |
109 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | 67 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; |
@@ -111,175 +69,3 @@ impl ImplBlock { | |||
111 | r | 69 | r |
112 | } | 70 | } |
113 | } | 71 | } |
114 | |||
115 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
116 | pub struct ImplData { | ||
117 | target_trait: Option<TypeRef>, | ||
118 | target_type: TypeRef, | ||
119 | items: Vec<AssocItem>, | ||
120 | negative: bool, | ||
121 | } | ||
122 | |||
123 | impl ImplData { | ||
124 | pub(crate) fn from_ast( | ||
125 | db: &(impl DefDatabase + AstDatabase), | ||
126 | file_id: HirFileId, | ||
127 | module: Module, | ||
128 | node: &ast::ImplBlock, | ||
129 | ) -> Self { | ||
130 | let target_trait = node.target_trait().map(TypeRef::from_ast); | ||
131 | let target_type = TypeRef::from_ast_opt(node.target_type()); | ||
132 | let ctx = LocationCtx::new(db, module.id, file_id); | ||
133 | let negative = node.is_negative(); | ||
134 | let items = if let Some(item_list) = node.item_list() { | ||
135 | item_list | ||
136 | .impl_items() | ||
137 | .map(|item_node| match item_node { | ||
138 | ast::ImplItem::FnDef(it) => Function { id: ctx.to_def(&it) }.into(), | ||
139 | ast::ImplItem::ConstDef(it) => Const { id: ctx.to_def(&it) }.into(), | ||
140 | ast::ImplItem::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(&it) }.into(), | ||
141 | }) | ||
142 | .collect() | ||
143 | } else { | ||
144 | Vec::new() | ||
145 | }; | ||
146 | ImplData { target_trait, target_type, items, negative } | ||
147 | } | ||
148 | |||
149 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
150 | self.target_trait.as_ref() | ||
151 | } | ||
152 | |||
153 | pub fn target_type(&self) -> &TypeRef { | ||
154 | &self.target_type | ||
155 | } | ||
156 | |||
157 | pub fn items(&self) -> &[AssocItem] { | ||
158 | &self.items | ||
159 | } | ||
160 | } | ||
161 | |||
162 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
163 | pub struct ImplId(pub RawId); | ||
164 | impl_arena_id!(ImplId); | ||
165 | |||
166 | /// The collection of impl blocks is a two-step process: first we collect the | ||
167 | /// blocks per-module; then we build an index of all impl blocks in the crate. | ||
168 | /// This way, we avoid having to do this process for the whole crate whenever | ||
169 | /// a file is changed; as long as the impl blocks in the file don't change, | ||
170 | /// we don't need to do the second step again. | ||
171 | #[derive(Debug, PartialEq, Eq)] | ||
172 | pub struct ModuleImplBlocks { | ||
173 | pub(crate) module: Module, | ||
174 | pub(crate) impls: Arena<ImplId, ImplData>, | ||
175 | impls_by_def: FxHashMap<AssocItem, ImplId>, | ||
176 | } | ||
177 | |||
178 | impl ModuleImplBlocks { | ||
179 | pub(crate) fn impls_in_module_with_source_map_query( | ||
180 | db: &(impl DefDatabase + AstDatabase), | ||
181 | module: Module, | ||
182 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { | ||
183 | let mut source_map = ImplSourceMap::default(); | ||
184 | let crate_graph = db.crate_graph(); | ||
185 | let cfg_options = crate_graph.cfg_options(module.id.krate); | ||
186 | |||
187 | let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map); | ||
188 | (Arc::new(result), Arc::new(source_map)) | ||
189 | } | ||
190 | |||
191 | pub(crate) fn impls_in_module_query( | ||
192 | db: &impl DefDatabase, | ||
193 | module: Module, | ||
194 | ) -> Arc<ModuleImplBlocks> { | ||
195 | db.impls_in_module_with_source_map(module).0 | ||
196 | } | ||
197 | |||
198 | fn collect( | ||
199 | db: &(impl DefDatabase + AstDatabase), | ||
200 | cfg_options: &CfgOptions, | ||
201 | module: Module, | ||
202 | source_map: &mut ImplSourceMap, | ||
203 | ) -> Self { | ||
204 | let mut m = ModuleImplBlocks { | ||
205 | module, | ||
206 | impls: Arena::default(), | ||
207 | impls_by_def: FxHashMap::default(), | ||
208 | }; | ||
209 | |||
210 | let src = m.module.definition_source(db); | ||
211 | match &src.ast { | ||
212 | ModuleSource::SourceFile(node) => { | ||
213 | m.collect_from_item_owner(db, cfg_options, source_map, node, src.file_id) | ||
214 | } | ||
215 | ModuleSource::Module(node) => { | ||
216 | let item_list = node.item_list().expect("inline module should have item list"); | ||
217 | m.collect_from_item_owner(db, cfg_options, source_map, &item_list, src.file_id) | ||
218 | } | ||
219 | }; | ||
220 | m | ||
221 | } | ||
222 | |||
223 | fn collect_from_item_owner( | ||
224 | &mut self, | ||
225 | db: &(impl DefDatabase + AstDatabase), | ||
226 | cfg_options: &CfgOptions, | ||
227 | source_map: &mut ImplSourceMap, | ||
228 | owner: &dyn ast::ModuleItemOwner, | ||
229 | file_id: HirFileId, | ||
230 | ) { | ||
231 | let hygiene = Hygiene::new(db, file_id); | ||
232 | for item in owner.items_with_macros() { | ||
233 | match item { | ||
234 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { | ||
235 | let attrs = Attr::from_attrs_owner(&impl_block_ast, &hygiene); | ||
236 | if attrs.map_or(false, |attrs| { | ||
237 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
238 | }) { | ||
239 | continue; | ||
240 | } | ||
241 | |||
242 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); | ||
243 | let id = self.impls.alloc(impl_block); | ||
244 | for &impl_item in &self.impls[id].items { | ||
245 | self.impls_by_def.insert(impl_item, id); | ||
246 | } | ||
247 | |||
248 | source_map.insert(id, file_id, &impl_block_ast); | ||
249 | } | ||
250 | ast::ItemOrMacro::Item(_) => (), | ||
251 | ast::ItemOrMacro::Macro(macro_call) => { | ||
252 | let attrs = Attr::from_attrs_owner(¯o_call, &hygiene); | ||
253 | if attrs.map_or(false, |attrs| { | ||
254 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
255 | }) { | ||
256 | continue; | ||
257 | } | ||
258 | |||
259 | //FIXME: we should really cut down on the boilerplate required to process a macro | ||
260 | let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(¯o_call)); | ||
261 | if let Some(path) = | ||
262 | macro_call.path().and_then(|path| Path::from_src(path, &hygiene)) | ||
263 | { | ||
264 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) | ||
265 | { | ||
266 | let call_id = db.intern_macro(MacroCallLoc { def: def.id, ast_id }); | ||
267 | let file_id = call_id.as_file(MacroFileKind::Items); | ||
268 | if let Some(item_list) = | ||
269 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) | ||
270 | { | ||
271 | self.collect_from_item_owner( | ||
272 | db, | ||
273 | cfg_options, | ||
274 | source_map, | ||
275 | &item_list, | ||
276 | file_id, | ||
277 | ) | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | } | ||
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs index e1780ed38..fa2ef8a17 100644 --- a/crates/ra_hir/src/lang_item.rs +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -25,7 +25,7 @@ impl LangItemTarget { | |||
25 | Some(match self { | 25 | Some(match self { |
26 | LangItemTarget::Enum(e) => e.module(db).krate(), | 26 | LangItemTarget::Enum(e) => e.module(db).krate(), |
27 | LangItemTarget::Function(f) => f.module(db).krate(), | 27 | LangItemTarget::Function(f) => f.module(db).krate(), |
28 | LangItemTarget::ImplBlock(i) => i.module().krate(), | 28 | LangItemTarget::ImplBlock(i) => i.krate(db), |
29 | LangItemTarget::Static(s) => s.module(db).krate(), | 29 | LangItemTarget::Static(s) => s.module(db).krate(), |
30 | LangItemTarget::Struct(s) => s.module(db).krate(), | 30 | LangItemTarget::Struct(s) => s.module(db).krate(), |
31 | LangItemTarget::Trait(t) => t.module(db).krate(), | 31 | LangItemTarget::Trait(t) => t.module(db).krate(), |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 5ba847d35..da33c9591 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -54,12 +54,11 @@ mod test_db; | |||
54 | #[cfg(test)] | 54 | #[cfg(test)] |
55 | mod marks; | 55 | mod marks; |
56 | 56 | ||
57 | use hir_expand::AstId; | 57 | use crate::resolve::Resolver; |
58 | |||
59 | use crate::{ids::MacroFileKind, resolve::Resolver}; | ||
60 | 58 | ||
61 | pub use crate::{ | 59 | pub use crate::{ |
62 | adt::VariantDef, | 60 | adt::VariantDef, |
61 | code_model::ImplBlock, | ||
63 | code_model::{ | 62 | code_model::{ |
64 | attrs::{AttrDef, Attrs}, | 63 | attrs::{AttrDef, Attrs}, |
65 | docs::{DocDef, Docs, Documentation}, | 64 | docs::{DocDef, Docs, Documentation}, |
@@ -72,7 +71,6 @@ pub use crate::{ | |||
72 | from_source::FromSource, | 71 | from_source::FromSource, |
73 | generics::GenericDef, | 72 | generics::GenericDef, |
74 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, | 73 | ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, |
75 | impl_block::ImplBlock, | ||
76 | resolve::ScopeDef, | 74 | resolve::ScopeDef, |
77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 75 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
78 | ty::{ | 76 | ty::{ |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 2f3e12eb8..79b92180a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -15,9 +15,8 @@ use crate::{ | |||
15 | db::{DefDatabase, HirDatabase}, | 15 | db::{DefDatabase, HirDatabase}, |
16 | expr::{ExprScopes, PatId, ScopeId}, | 16 | expr::{ExprScopes, PatId, ScopeId}, |
17 | generics::GenericParams, | 17 | generics::GenericParams, |
18 | impl_block::ImplBlock, | 18 | Adt, Const, DefWithBody, Enum, EnumVariant, Function, ImplBlock, Local, MacroDef, ModuleDef, |
19 | Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, | 19 | PerNs, Static, Struct, Trait, TypeAlias, |
20 | TypeAlias, | ||
21 | }; | 20 | }; |
22 | 21 | ||
23 | #[derive(Debug, Clone, Default)] | 22 | #[derive(Debug, Clone, Default)] |
@@ -34,6 +33,7 @@ pub(crate) struct ModuleItemMap { | |||
34 | 33 | ||
35 | #[derive(Debug, Clone)] | 34 | #[derive(Debug, Clone)] |
36 | pub(crate) struct ExprScope { | 35 | pub(crate) struct ExprScope { |
36 | owner: DefWithBody, | ||
37 | expr_scopes: Arc<ExprScopes>, | 37 | expr_scopes: Arc<ExprScopes>, |
38 | scope_id: ScopeId, | 38 | scope_id: ScopeId, |
39 | } | 39 | } |
@@ -53,7 +53,7 @@ pub(crate) enum Scope { | |||
53 | } | 53 | } |
54 | 54 | ||
55 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 55 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
56 | pub enum TypeNs { | 56 | pub(crate) enum TypeNs { |
57 | SelfType(ImplBlock), | 57 | SelfType(ImplBlock), |
58 | GenericParam(u32), | 58 | GenericParam(u32), |
59 | Adt(Adt), | 59 | Adt(Adt), |
@@ -68,13 +68,13 @@ pub enum TypeNs { | |||
68 | } | 68 | } |
69 | 69 | ||
70 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 70 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
71 | pub enum ResolveValueResult { | 71 | pub(crate) enum ResolveValueResult { |
72 | ValueNs(ValueNs), | 72 | ValueNs(ValueNs), |
73 | Partial(TypeNs, usize), | 73 | Partial(TypeNs, usize), |
74 | } | 74 | } |
75 | 75 | ||
76 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 76 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
77 | pub enum ValueNs { | 77 | pub(crate) enum ValueNs { |
78 | LocalBinding(PatId), | 78 | LocalBinding(PatId), |
79 | Function(Function), | 79 | Function(Function), |
80 | Const(Const), | 80 | Const(Const), |
@@ -399,10 +399,11 @@ impl Resolver { | |||
399 | 399 | ||
400 | pub(crate) fn push_expr_scope( | 400 | pub(crate) fn push_expr_scope( |
401 | self, | 401 | self, |
402 | owner: DefWithBody, | ||
402 | expr_scopes: Arc<ExprScopes>, | 403 | expr_scopes: Arc<ExprScopes>, |
403 | scope_id: ScopeId, | 404 | scope_id: ScopeId, |
404 | ) -> Resolver { | 405 | ) -> Resolver { |
405 | self.push_scope(Scope::ExprScope(ExprScope { expr_scopes, scope_id })) | 406 | self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })) |
406 | } | 407 | } |
407 | } | 408 | } |
408 | 409 | ||
@@ -413,7 +414,7 @@ pub enum ScopeDef { | |||
413 | GenericParam(u32), | 414 | GenericParam(u32), |
414 | ImplSelfType(ImplBlock), | 415 | ImplSelfType(ImplBlock), |
415 | AdtSelfType(Adt), | 416 | AdtSelfType(Adt), |
416 | LocalBinding(PatId), | 417 | Local(Local), |
417 | Unknown, | 418 | Unknown, |
418 | } | 419 | } |
419 | 420 | ||
@@ -467,9 +468,10 @@ impl Scope { | |||
467 | Scope::AdtScope(i) => { | 468 | Scope::AdtScope(i) => { |
468 | f(name::SELF_TYPE, ScopeDef::AdtSelfType(*i)); | 469 | f(name::SELF_TYPE, ScopeDef::AdtSelfType(*i)); |
469 | } | 470 | } |
470 | Scope::ExprScope(e) => { | 471 | Scope::ExprScope(scope) => { |
471 | e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { | 472 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { |
472 | f(e.name().clone(), ScopeDef::LocalBinding(e.pat())); | 473 | let local = Local { parent: scope.owner, pat_id: e.pat() }; |
474 | f(e.name().clone(), ScopeDef::Local(local)); | ||
473 | }); | 475 | }); |
474 | } | 476 | } |
475 | } | 477 | } |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index ca40e3b54..662d3f880 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -19,7 +19,6 @@ use ra_syntax::{ | |||
19 | SyntaxKind::*, | 19 | SyntaxKind::*, |
20 | SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, | 20 | SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, |
21 | }; | 21 | }; |
22 | use rustc_hash::FxHashSet; | ||
23 | 22 | ||
24 | use crate::{ | 23 | use crate::{ |
25 | db::HirDatabase, | 24 | db::HirDatabase, |
@@ -195,14 +194,6 @@ impl SourceAnalyzer { | |||
195 | Some(self.infer.as_ref()?[pat_id].clone()) | 194 | Some(self.infer.as_ref()?[pat_id].clone()) |
196 | } | 195 | } |
197 | 196 | ||
198 | pub fn type_of_pat_by_id( | ||
199 | &self, | ||
200 | _db: &impl HirDatabase, | ||
201 | pat_id: expr::PatId, | ||
202 | ) -> Option<crate::Ty> { | ||
203 | Some(self.infer.as_ref()?[pat_id].clone()) | ||
204 | } | ||
205 | |||
206 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 197 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
207 | let expr_id = self.expr_id(&call.clone().into())?; | 198 | let expr_id = self.expr_id(&call.clone().into())?; |
208 | self.infer.as_ref()?.method_resolution(expr_id) | 199 | self.infer.as_ref()?.method_resolution(expr_id) |
@@ -293,23 +284,15 @@ impl SourceAnalyzer { | |||
293 | self.resolve_hir_path(db, &hir_path) | 284 | self.resolve_hir_path(db, &hir_path) |
294 | } | 285 | } |
295 | 286 | ||
296 | pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | 287 | fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { |
297 | let mut shadowed = FxHashSet::default(); | ||
298 | let name = name_ref.as_name(); | 288 | let name = name_ref.as_name(); |
299 | let source_map = self.body_source_map.as_ref()?; | 289 | let source_map = self.body_source_map.as_ref()?; |
300 | let scopes = self.scopes.as_ref()?; | 290 | let scopes = self.scopes.as_ref()?; |
301 | let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax()); | 291 | let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?; |
302 | let ret = scopes | 292 | let entry = scopes.resolve_name_in_scope(scope, &name)?; |
303 | .scope_chain(scope) | 293 | Some(ScopeEntryWithSyntax { |
304 | .flat_map(|scope| scopes.entries(scope).iter()) | 294 | name: entry.name().clone(), |
305 | .filter(|entry| shadowed.insert(entry.name())) | 295 | ptr: source_map.pat_syntax(entry.pat())?.ast, |
306 | .filter(|entry| entry.name() == &name) | ||
307 | .nth(0); | ||
308 | ret.and_then(|entry| { | ||
309 | Some(ScopeEntryWithSyntax { | ||
310 | name: entry.name().clone(), | ||
311 | ptr: source_map.pat_syntax(entry.pat())?.ast, | ||
312 | }) | ||
313 | }) | 296 | }) |
314 | } | 297 | } |
315 | 298 | ||
@@ -317,9 +300,9 @@ impl SourceAnalyzer { | |||
317 | self.resolver.process_all_names(db, f) | 300 | self.resolver.process_all_names(db, f) |
318 | } | 301 | } |
319 | 302 | ||
303 | // FIXME: we only use this in `inline_local_variable` assist, ideally, we | ||
304 | // should switch to general reference search infra there. | ||
320 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | 305 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { |
321 | // FIXME: at least, this should work with any DefWithBody, but ideally | ||
322 | // this should be hir-based altogether | ||
323 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | 306 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); |
324 | let ptr = Either::A(AstPtr::new(&ast::Pat::from(pat.clone()))); | 307 | let ptr = Either::A(AstPtr::new(&ast::Pat::from(pat.clone()))); |
325 | fn_def | 308 | fn_def |
@@ -421,11 +404,6 @@ impl SourceAnalyzer { | |||
421 | pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> { | 404 | pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> { |
422 | self.infer.clone().unwrap() | 405 | self.infer.clone().unwrap() |
423 | } | 406 | } |
424 | |||
425 | #[cfg(test)] | ||
426 | pub(crate) fn scopes(&self) -> Arc<ExprScopes> { | ||
427 | self.scopes.clone().unwrap() | ||
428 | } | ||
429 | } | 407 | } |
430 | 408 | ||
431 | fn scope_for( | 409 | fn scope_for( |
diff --git a/crates/ra_hir/src/test_db.rs b/crates/ra_hir/src/test_db.rs index 5237b303a..1caa2e875 100644 --- a/crates/ra_hir/src/test_db.rs +++ b/crates/ra_hir/src/test_db.rs | |||
@@ -81,7 +81,7 @@ impl TestDB { | |||
81 | let crate_graph = self.crate_graph(); | 81 | let crate_graph = self.crate_graph(); |
82 | for krate in crate_graph.iter().next() { | 82 | for krate in crate_graph.iter().next() { |
83 | let crate_def_map = self.crate_def_map(krate); | 83 | let crate_def_map = self.crate_def_map(krate); |
84 | for (module_id, _) in crate_def_map.modules.iter() { | 84 | for module_id in crate_def_map.modules() { |
85 | let module_id = ModuleId { krate, module_id }; | 85 | let module_id = ModuleId { krate, module_id }; |
86 | let module = crate::Module::from(module_id); | 86 | let module = crate::Module::from(module_id); |
87 | module.diagnostics( | 87 | module.diagnostics( |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index eb5ca6769..9aad2d3fe 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -5,16 +5,14 @@ | |||
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::CrateModuleId; | ||
9 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHashMap; |
10 | 9 | ||
11 | use crate::{ | 10 | use crate::{ |
12 | db::HirDatabase, | 11 | db::HirDatabase, |
13 | impl_block::{ImplBlock, ImplId}, | ||
14 | resolve::Resolver, | 12 | resolve::Resolver, |
15 | ty::primitive::{FloatBitness, Uncertain}, | 13 | ty::primitive::{FloatBitness, Uncertain}, |
16 | ty::{Ty, TypeCtor}, | 14 | ty::{Ty, TypeCtor}, |
17 | AssocItem, Crate, Function, Module, Mutability, Name, Trait, | 15 | AssocItem, Crate, Function, ImplBlock, Module, Mutability, Name, Trait, |
18 | }; | 16 | }; |
19 | 17 | ||
20 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | 18 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; |
@@ -39,65 +37,46 @@ impl TyFingerprint { | |||
39 | 37 | ||
40 | #[derive(Debug, PartialEq, Eq)] | 38 | #[derive(Debug, PartialEq, Eq)] |
41 | pub struct CrateImplBlocks { | 39 | pub struct CrateImplBlocks { |
42 | /// To make sense of the CrateModuleIds, we need the source root. | 40 | impls: FxHashMap<TyFingerprint, Vec<ImplBlock>>, |
43 | krate: Crate, | 41 | impls_by_trait: FxHashMap<Trait, Vec<ImplBlock>>, |
44 | impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, | ||
45 | impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>, | ||
46 | } | 42 | } |
47 | 43 | ||
48 | impl CrateImplBlocks { | 44 | impl CrateImplBlocks { |
49 | pub fn lookup_impl_blocks<'a>(&'a self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + 'a { | 45 | pub(crate) fn impls_in_crate_query( |
46 | db: &impl HirDatabase, | ||
47 | krate: Crate, | ||
48 | ) -> Arc<CrateImplBlocks> { | ||
49 | let mut crate_impl_blocks = | ||
50 | CrateImplBlocks { impls: FxHashMap::default(), impls_by_trait: FxHashMap::default() }; | ||
51 | if let Some(module) = krate.root_module(db) { | ||
52 | crate_impl_blocks.collect_recursive(db, module); | ||
53 | } | ||
54 | Arc::new(crate_impl_blocks) | ||
55 | } | ||
56 | pub fn lookup_impl_blocks(&self, ty: &Ty) -> impl Iterator<Item = ImplBlock> + '_ { | ||
50 | let fingerprint = TyFingerprint::for_impl(ty); | 57 | let fingerprint = TyFingerprint::for_impl(ty); |
51 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map( | 58 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() |
52 | move |(module_id, impl_id)| { | ||
53 | let module = Module::new(self.krate, *module_id); | ||
54 | ImplBlock::from_id(module, *impl_id) | ||
55 | }, | ||
56 | ) | ||
57 | } | 59 | } |
58 | 60 | ||
59 | pub fn lookup_impl_blocks_for_trait<'a>( | 61 | pub fn lookup_impl_blocks_for_trait(&self, tr: Trait) -> impl Iterator<Item = ImplBlock> + '_ { |
60 | &'a self, | 62 | self.impls_by_trait.get(&tr).into_iter().flatten().copied() |
61 | tr: Trait, | ||
62 | ) -> impl Iterator<Item = ImplBlock> + 'a { | ||
63 | self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( | ||
64 | move |(module_id, impl_id)| { | ||
65 | let module = Module::new(self.krate, *module_id); | ||
66 | ImplBlock::from_id(module, *impl_id) | ||
67 | }, | ||
68 | ) | ||
69 | } | 63 | } |
70 | 64 | ||
71 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a { | 65 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a { |
72 | self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map( | 66 | self.impls.values().chain(self.impls_by_trait.values()).flatten().copied() |
73 | move |(module_id, impl_id)| { | ||
74 | let module = Module::new(self.krate, *module_id); | ||
75 | ImplBlock::from_id(module, *impl_id) | ||
76 | }, | ||
77 | ) | ||
78 | } | 67 | } |
79 | 68 | ||
80 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { | 69 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { |
81 | let module_impl_blocks = db.impls_in_module(module); | 70 | for impl_block in module.impl_blocks(db) { |
82 | |||
83 | for (impl_id, _) in module_impl_blocks.impls.iter() { | ||
84 | let impl_block = ImplBlock::from_id(module_impl_blocks.module, impl_id); | ||
85 | |||
86 | let target_ty = impl_block.target_ty(db); | 71 | let target_ty = impl_block.target_ty(db); |
87 | 72 | ||
88 | if impl_block.target_trait(db).is_some() { | 73 | if impl_block.target_trait(db).is_some() { |
89 | if let Some(tr) = impl_block.target_trait_ref(db) { | 74 | if let Some(tr) = impl_block.target_trait_ref(db) { |
90 | self.impls_by_trait | 75 | self.impls_by_trait.entry(tr.trait_).or_default().push(impl_block); |
91 | .entry(tr.trait_) | ||
92 | .or_insert_with(Vec::new) | ||
93 | .push((module.id.module_id, impl_id)); | ||
94 | } | 76 | } |
95 | } else { | 77 | } else { |
96 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | 78 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { |
97 | self.impls | 79 | self.impls.entry(target_ty_fp).or_default().push(impl_block); |
98 | .entry(target_ty_fp) | ||
99 | .or_insert_with(Vec::new) | ||
100 | .push((module.id.module_id, impl_id)); | ||
101 | } | 80 | } |
102 | } | 81 | } |
103 | } | 82 | } |
@@ -106,21 +85,6 @@ impl CrateImplBlocks { | |||
106 | self.collect_recursive(db, child); | 85 | self.collect_recursive(db, child); |
107 | } | 86 | } |
108 | } | 87 | } |
109 | |||
110 | pub(crate) fn impls_in_crate_query( | ||
111 | db: &impl HirDatabase, | ||
112 | krate: Crate, | ||
113 | ) -> Arc<CrateImplBlocks> { | ||
114 | let mut crate_impl_blocks = CrateImplBlocks { | ||
115 | krate, | ||
116 | impls: FxHashMap::default(), | ||
117 | impls_by_trait: FxHashMap::default(), | ||
118 | }; | ||
119 | if let Some(module) = krate.root_module(db) { | ||
120 | crate_impl_blocks.collect_recursive(db, module); | ||
121 | } | ||
122 | Arc::new(crate_impl_blocks) | ||
123 | } | ||
124 | } | 88 | } |
125 | 89 | ||
126 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { | 90 | fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 8863c3608..fe9346c78 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -254,7 +254,6 @@ fn test(a: u32, b: isize, c: !, d: &str) { | |||
254 | 1.0f32; | 254 | 1.0f32; |
255 | }"#), | 255 | }"#), |
256 | @r###" | 256 | @r###" |
257 | |||
258 | [9; 10) 'a': u32 | 257 | [9; 10) 'a': u32 |
259 | [17; 18) 'b': isize | 258 | [17; 18) 'b': isize |
260 | [27; 28) 'c': ! | 259 | [27; 28) 'c': ! |
@@ -317,7 +316,6 @@ fn test() { | |||
317 | } | 316 | } |
318 | "#), | 317 | "#), |
319 | @r###" | 318 | @r###" |
320 | |||
321 | [15; 20) '{ 1 }': u32 | 319 | [15; 20) '{ 1 }': u32 |
322 | [17; 18) '1': u32 | 320 | [17; 18) '1': u32 |
323 | [48; 53) '{ 1 }': u32 | 321 | [48; 53) '{ 1 }': u32 |
@@ -354,7 +352,7 @@ fn test() { | |||
354 | [66; 74) 'S::foo()': i32 | 352 | [66; 74) 'S::foo()': i32 |
355 | [80; 88) '<S>::foo': fn foo() -> i32 | 353 | [80; 88) '<S>::foo': fn foo() -> i32 |
356 | [80; 90) '<S>::foo()': i32 | 354 | [80; 90) '<S>::foo()': i32 |
357 | "### | 355 | "### |
358 | ); | 356 | ); |
359 | } | 357 | } |
360 | 358 | ||
@@ -409,7 +407,6 @@ fn test() { | |||
409 | } | 407 | } |
410 | "#), | 408 | "#), |
411 | @r###" | 409 | @r###" |
412 | |||
413 | [72; 154) '{ ...a.c; }': () | 410 | [72; 154) '{ ...a.c; }': () |
414 | [82; 83) 'c': C | 411 | [82; 83) 'c': C |
415 | [86; 87) 'C': C(usize) -> C | 412 | [86; 87) 'C': C(usize) -> C |
@@ -443,7 +440,6 @@ fn test() { | |||
443 | E::V2; | 440 | E::V2; |
444 | }"#), | 441 | }"#), |
445 | @r###" | 442 | @r###" |
446 | |||
447 | [48; 82) '{ E:...:V2; }': () | 443 | [48; 82) '{ E:...:V2; }': () |
448 | [52; 70) 'E::V1 ...d: 1 }': E | 444 | [52; 70) 'E::V1 ...d: 1 }': E |
449 | [67; 68) '1': u32 | 445 | [67; 68) '1': u32 |
@@ -471,7 +467,6 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { | |||
471 | } | 467 | } |
472 | "#), | 468 | "#), |
473 | @r###" | 469 | @r###" |
474 | |||
475 | [9; 10) 'a': &u32 | 470 | [9; 10) 'a': &u32 |
476 | [18; 19) 'b': &mut u32 | 471 | [18; 19) 'b': &mut u32 |
477 | [31; 32) 'c': *const u32 | 472 | [31; 32) 'c': *const u32 |
@@ -524,7 +519,6 @@ fn test() { | |||
524 | } | 519 | } |
525 | "##), | 520 | "##), |
526 | @r###" | 521 | @r###" |
527 | |||
528 | [11; 221) '{ ...o"#; }': () | 522 | [11; 221) '{ ...o"#; }': () |
529 | [17; 21) '5i32': i32 | 523 | [17; 21) '5i32': i32 |
530 | [27; 31) '5f32': f32 | 524 | [27; 31) '5f32': f32 |
@@ -568,7 +562,6 @@ fn test(x: SomeType) { | |||
568 | } | 562 | } |
569 | "#), | 563 | "#), |
570 | @r###" | 564 | @r###" |
571 | |||
572 | [27; 28) 'x': SomeType | 565 | [27; 28) 'x': SomeType |
573 | [40; 272) '{ ...lo"; }': () | 566 | [40; 272) '{ ...lo"; }': () |
574 | [50; 51) 'b': bool | 567 | [50; 51) 'b': bool |
@@ -632,7 +625,6 @@ fn test() -> &mut &f64 { | |||
632 | } | 625 | } |
633 | "#), | 626 | "#), |
634 | @r###" | 627 | @r###" |
635 | |||
636 | [14; 15) 'x': u32 | 628 | [14; 15) 'x': u32 |
637 | [22; 24) '{}': () | 629 | [22; 24) '{}': () |
638 | [78; 231) '{ ...t &c }': &mut &f64 | 630 | [78; 231) '{ ...t &c }': &mut &f64 |
@@ -679,7 +671,6 @@ impl S { | |||
679 | } | 671 | } |
680 | "#), | 672 | "#), |
681 | @r###" | 673 | @r###" |
682 | |||
683 | [34; 38) 'self': &S | 674 | [34; 38) 'self': &S |
684 | [40; 61) '{ ... }': () | 675 | [40; 61) '{ ... }': () |
685 | [50; 54) 'self': &S | 676 | [50; 54) 'self': &S |
@@ -719,7 +710,6 @@ fn test() -> bool { | |||
719 | } | 710 | } |
720 | "#), | 711 | "#), |
721 | @r###" | 712 | @r###" |
722 | |||
723 | [6; 7) 'x': bool | 713 | [6; 7) 'x': bool |
724 | [22; 34) '{ 0i32 }': i32 | 714 | [22; 34) '{ 0i32 }': i32 |
725 | [28; 32) '0i32': i32 | 715 | [28; 32) '0i32': i32 |
@@ -802,7 +792,6 @@ fn test2(a1: *const A, a2: *mut A) { | |||
802 | } | 792 | } |
803 | "#), | 793 | "#), |
804 | @r###" | 794 | @r###" |
805 | |||
806 | [44; 45) 'a': A | 795 | [44; 45) 'a': A |
807 | [50; 213) '{ ...5.b; }': () | 796 | [50; 213) '{ ...5.b; }': () |
808 | [60; 62) 'a1': A | 797 | [60; 62) 'a1': A |
@@ -970,7 +959,7 @@ fn test(a: A<i32>) { | |||
970 | [374; 375) 'B': B<A<i32>>(T) -> B<T> | 959 | [374; 375) 'B': B<A<i32>>(T) -> B<T> |
971 | [374; 378) 'B(a)': B<A<i32>> | 960 | [374; 378) 'B(a)': B<A<i32>> |
972 | [376; 377) 'a': A<i32> | 961 | [376; 377) 'a': A<i32> |
973 | "### | 962 | "### |
974 | ); | 963 | ); |
975 | } | 964 | } |
976 | 965 | ||
@@ -983,7 +972,6 @@ fn test() { | |||
983 | } | 972 | } |
984 | "#), | 973 | "#), |
985 | @r###" | 974 | @r###" |
986 | |||
987 | [11; 37) '{ l... {}; }': () | 975 | [11; 37) '{ l... {}; }': () |
988 | [20; 21) 'x': () | 976 | [20; 21) 'x': () |
989 | [24; 34) 'if true {}': () | 977 | [24; 34) 'if true {}': () |
@@ -1105,7 +1093,6 @@ fn test(a: A) { | |||
1105 | } | 1093 | } |
1106 | "#), | 1094 | "#), |
1107 | @r###" | 1095 | @r###" |
1108 | |||
1109 | [32; 36) 'self': A | 1096 | [32; 36) 'self': A |
1110 | [38; 39) 'x': u32 | 1097 | [38; 39) 'x': u32 |
1111 | [53; 55) '{}': () | 1098 | [53; 55) '{}': () |
@@ -1142,7 +1129,6 @@ fn test() { | |||
1142 | } | 1129 | } |
1143 | "#), | 1130 | "#), |
1144 | @r###" | 1131 | @r###" |
1145 | |||
1146 | [40; 44) 'self': &str | 1132 | [40; 44) 'self': &str |
1147 | [53; 55) '{}': () | 1133 | [53; 55) '{}': () |
1148 | [69; 89) '{ ...o(); }': () | 1134 | [69; 89) '{ ...o(); }': () |
@@ -1166,7 +1152,6 @@ fn test(x: &str, y: isize) { | |||
1166 | } | 1152 | } |
1167 | "#), | 1153 | "#), |
1168 | @r###" | 1154 | @r###" |
1169 | |||
1170 | [9; 10) 'x': &str | 1155 | [9; 10) 'x': &str |
1171 | [18; 19) 'y': isize | 1156 | [18; 19) 'y': isize |
1172 | [28; 170) '{ ...d"); }': () | 1157 | [28; 170) '{ ...d"); }': () |
@@ -1367,7 +1352,6 @@ fn test() { | |||
1367 | } | 1352 | } |
1368 | "#), | 1353 | "#), |
1369 | @r###" | 1354 | @r###" |
1370 | |||
1371 | [28; 79) '{ ...(1); }': () | 1355 | [28; 79) '{ ...(1); }': () |
1372 | [38; 42) 'A(n)': A<i32> | 1356 | [38; 42) 'A(n)': A<i32> |
1373 | [40; 41) 'n': &i32 | 1357 | [40; 41) 'n': &i32 |
@@ -1396,7 +1380,6 @@ fn test() { | |||
1396 | } | 1380 | } |
1397 | "#), | 1381 | "#), |
1398 | @r###" | 1382 | @r###" |
1399 | |||
1400 | [11; 57) '{ ...= v; }': () | 1383 | [11; 57) '{ ...= v; }': () |
1401 | [21; 22) 'v': &(i32, &i32) | 1384 | [21; 22) 'v': &(i32, &i32) |
1402 | [25; 33) '&(1, &2)': &(i32, &i32) | 1385 | [25; 33) '&(1, &2)': &(i32, &i32) |
@@ -1441,7 +1424,6 @@ fn test() { | |||
1441 | } | 1424 | } |
1442 | "#), | 1425 | "#), |
1443 | @r###" | 1426 | @r###" |
1444 | |||
1445 | [68; 289) '{ ... d; }': () | 1427 | [68; 289) '{ ... d; }': () |
1446 | [78; 79) 'e': E | 1428 | [78; 79) 'e': E |
1447 | [82; 95) 'E::A { x: 3 }': E | 1429 | [82; 95) 'E::A { x: 3 }': E |
@@ -1488,7 +1470,6 @@ fn test(a1: A<u32>, i: i32) { | |||
1488 | } | 1470 | } |
1489 | "#), | 1471 | "#), |
1490 | @r###" | 1472 | @r###" |
1491 | |||
1492 | [36; 38) 'a1': A<u32> | 1473 | [36; 38) 'a1': A<u32> |
1493 | [48; 49) 'i': i32 | 1474 | [48; 49) 'i': i32 |
1494 | [56; 147) '{ ...3.x; }': () | 1475 | [56; 147) '{ ...3.x; }': () |
@@ -1569,7 +1550,6 @@ fn test(a1: A<u32>, o: Option<u64>) { | |||
1569 | } | 1550 | } |
1570 | "#), | 1551 | "#), |
1571 | @r###" | 1552 | @r###" |
1572 | |||
1573 | [79; 81) 'a1': A<u32> | 1553 | [79; 81) 'a1': A<u32> |
1574 | [91; 92) 'o': Option<u64> | 1554 | [91; 92) 'o': Option<u64> |
1575 | [107; 244) '{ ... }; }': () | 1555 | [107; 244) '{ ... }; }': () |
@@ -1604,7 +1584,6 @@ fn test() { | |||
1604 | } | 1584 | } |
1605 | "#), | 1585 | "#), |
1606 | @r###" | 1586 | @r###" |
1607 | |||
1608 | [10; 11) 't': T | 1587 | [10; 11) 't': T |
1609 | [21; 26) '{ t }': T | 1588 | [21; 26) '{ t }': T |
1610 | [23; 24) 't': T | 1589 | [23; 24) 't': T |
@@ -1652,7 +1631,6 @@ fn test() -> i128 { | |||
1652 | } | 1631 | } |
1653 | "#), | 1632 | "#), |
1654 | @r###" | 1633 | @r###" |
1655 | |||
1656 | [74; 78) 'self': A<X, Y> | 1634 | [74; 78) 'self': A<X, Y> |
1657 | [85; 107) '{ ... }': X | 1635 | [85; 107) '{ ... }': X |
1658 | [95; 99) 'self': A<X, Y> | 1636 | [95; 99) 'self': A<X, Y> |
@@ -1706,7 +1684,6 @@ fn test(o: Option<u32>) { | |||
1706 | } | 1684 | } |
1707 | "#), | 1685 | "#), |
1708 | @r###" | 1686 | @r###" |
1709 | |||
1710 | [78; 82) 'self': &Option<T> | 1687 | [78; 82) 'self': &Option<T> |
1711 | [98; 100) '{}': () | 1688 | [98; 100) '{}': () |
1712 | [111; 112) 'o': Option<u32> | 1689 | [111; 112) 'o': Option<u32> |
@@ -1744,7 +1721,6 @@ fn test() -> i128 { | |||
1744 | } | 1721 | } |
1745 | "#), | 1722 | "#), |
1746 | @r###" | 1723 | @r###" |
1747 | |||
1748 | [53; 57) 'self': A<T2> | 1724 | [53; 57) 'self': A<T2> |
1749 | [65; 87) '{ ... }': T2 | 1725 | [65; 87) '{ ... }': T2 |
1750 | [75; 79) 'self': A<T2> | 1726 | [75; 79) 'self': A<T2> |
@@ -1921,7 +1897,6 @@ fn test() { | |||
1921 | } | 1897 | } |
1922 | "#), | 1898 | "#), |
1923 | @r###" | 1899 | @r###" |
1924 | |||
1925 | [56; 64) '{ A {} }': A | 1900 | [56; 64) '{ A {} }': A |
1926 | [58; 62) 'A {}': A | 1901 | [58; 62) 'A {}': A |
1927 | [126; 132) '{ 99 }': u32 | 1902 | [126; 132) '{ 99 }': u32 |
@@ -1961,7 +1936,6 @@ fn test() { | |||
1961 | } | 1936 | } |
1962 | "#), | 1937 | "#), |
1963 | @r###" | 1938 | @r###" |
1964 | |||
1965 | [64; 67) 'val': T | 1939 | [64; 67) 'val': T |
1966 | [82; 109) '{ ... }': Gen<T> | 1940 | [82; 109) '{ ... }': Gen<T> |
1967 | [92; 103) 'Gen { val }': Gen<T> | 1941 | [92; 103) 'Gen { val }': Gen<T> |
@@ -2129,7 +2103,6 @@ fn test(x: X) { | |||
2129 | } | 2103 | } |
2130 | "#), | 2104 | "#), |
2131 | @r###" | 2105 | @r###" |
2132 | |||
2133 | [20; 21) 'x': X | 2106 | [20; 21) 'x': X |
2134 | [26; 47) '{ ...eld; }': () | 2107 | [26; 47) '{ ...eld; }': () |
2135 | [32; 33) 'x': X | 2108 | [32; 33) 'x': X |
@@ -2151,7 +2124,6 @@ fn test() { | |||
2151 | } | 2124 | } |
2152 | "#), | 2125 | "#), |
2153 | @r###" | 2126 | @r###" |
2154 | |||
2155 | [11; 89) '{ ... } }': () | 2127 | [11; 89) '{ ... } }': () |
2156 | [17; 21) 'X {}': {unknown} | 2128 | [17; 21) 'X {}': {unknown} |
2157 | [27; 87) 'match ... }': () | 2129 | [27; 87) 'match ... }': () |
@@ -2174,7 +2146,6 @@ fn quux() { | |||
2174 | } | 2146 | } |
2175 | "#), | 2147 | "#), |
2176 | @r###" | 2148 | @r###" |
2177 | |||
2178 | [11; 41) '{ ...+ y; }': () | 2149 | [11; 41) '{ ...+ y; }': () |
2179 | [21; 22) 'y': i32 | 2150 | [21; 22) 'y': i32 |
2180 | [25; 27) '92': i32 | 2151 | [25; 27) '92': i32 |
@@ -2300,7 +2271,6 @@ fn write() { | |||
2300 | } | 2271 | } |
2301 | "#), | 2272 | "#), |
2302 | @r###" | 2273 | @r###" |
2303 | |||
2304 | [54; 139) '{ ... } }': () | 2274 | [54; 139) '{ ... } }': () |
2305 | [60; 137) 'match ... }': () | 2275 | [60; 137) 'match ... }': () |
2306 | [66; 83) 'someth...nknown': Maybe<{unknown}> | 2276 | [66; 83) 'someth...nknown': Maybe<{unknown}> |
@@ -2322,7 +2292,6 @@ fn test_line_buffer() { | |||
2322 | } | 2292 | } |
2323 | "#), | 2293 | "#), |
2324 | @r###" | 2294 | @r###" |
2325 | |||
2326 | [23; 53) '{ ...n']; }': () | 2295 | [23; 53) '{ ...n']; }': () |
2327 | [29; 50) '&[0, b...b'\n']': &[u8;_] | 2296 | [29; 50) '&[0, b...b'\n']': &[u8;_] |
2328 | [30; 50) '[0, b'...b'\n']': [u8;_] | 2297 | [30; 50) '[0, b'...b'\n']': [u8;_] |
@@ -2446,7 +2415,6 @@ fn test<R>(query_response: Canonical<QueryResponse<R>>) { | |||
2446 | } | 2415 | } |
2447 | "#), | 2416 | "#), |
2448 | @r###" | 2417 | @r###" |
2449 | |||
2450 | [92; 106) 'query_response': Canonical<QueryResponse<R>> | 2418 | [92; 106) 'query_response': Canonical<QueryResponse<R>> |
2451 | [137; 167) '{ ...lue; }': () | 2419 | [137; 167) '{ ...lue; }': () |
2452 | [143; 164) '&query....value': &QueryResponse<R> | 2420 | [143; 164) '&query....value': &QueryResponse<R> |
@@ -2472,7 +2440,6 @@ pub fn main_loop() { | |||
2472 | } | 2440 | } |
2473 | "#), | 2441 | "#), |
2474 | @r###" | 2442 | @r###" |
2475 | |||
2476 | [144; 146) '{}': () | 2443 | [144; 146) '{}': () |
2477 | [169; 198) '{ ...t(); }': () | 2444 | [169; 198) '{ ...t(); }': () |
2478 | [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H> | 2445 | [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H> |
@@ -2518,7 +2485,6 @@ fn test() { | |||
2518 | } | 2485 | } |
2519 | "#), | 2486 | "#), |
2520 | @r###" | 2487 | @r###" |
2521 | |||
2522 | [49; 50) '0': u32 | 2488 | [49; 50) '0': u32 |
2523 | [80; 83) '101': u32 | 2489 | [80; 83) '101': u32 |
2524 | [95; 213) '{ ...NST; }': () | 2490 | [95; 213) '{ ...NST; }': () |
@@ -2549,7 +2515,6 @@ fn test() { | |||
2549 | } | 2515 | } |
2550 | "#), | 2516 | "#), |
2551 | @r###" | 2517 | @r###" |
2552 | |||
2553 | [29; 32) '101': u32 | 2518 | [29; 32) '101': u32 |
2554 | [70; 73) '101': u32 | 2519 | [70; 73) '101': u32 |
2555 | [85; 280) '{ ...MUT; }': () | 2520 | [85; 280) '{ ...MUT; }': () |
@@ -2588,7 +2553,6 @@ fn test() { | |||
2588 | } | 2553 | } |
2589 | "#), | 2554 | "#), |
2590 | @r###" | 2555 | @r###" |
2591 | |||
2592 | [31; 35) 'self': &Self | 2556 | [31; 35) 'self': &Self |
2593 | [110; 114) 'self': &Self | 2557 | [110; 114) 'self': &Self |
2594 | [170; 228) '{ ...i128 }': () | 2558 | [170; 228) '{ ...i128 }': () |
@@ -2636,7 +2600,6 @@ mod bar_test { | |||
2636 | } | 2600 | } |
2637 | "#), | 2601 | "#), |
2638 | @r###" | 2602 | @r###" |
2639 | |||
2640 | [63; 67) 'self': &Self | 2603 | [63; 67) 'self': &Self |
2641 | [169; 173) 'self': &Self | 2604 | [169; 173) 'self': &Self |
2642 | [300; 337) '{ ... }': () | 2605 | [300; 337) '{ ... }': () |
@@ -2664,7 +2627,6 @@ fn test() { | |||
2664 | } | 2627 | } |
2665 | "#), | 2628 | "#), |
2666 | @r###" | 2629 | @r###" |
2667 | |||
2668 | [33; 37) 'self': &Self | 2630 | [33; 37) 'self': &Self |
2669 | [92; 111) '{ ...d(); }': () | 2631 | [92; 111) '{ ...d(); }': () |
2670 | [98; 99) 'S': S | 2632 | [98; 99) 'S': S |
@@ -2694,7 +2656,6 @@ fn test() { | |||
2694 | } | 2656 | } |
2695 | "#), | 2657 | "#), |
2696 | @r###" | 2658 | @r###" |
2697 | |||
2698 | [43; 47) 'self': &Self | 2659 | [43; 47) 'self': &Self |
2699 | [82; 86) 'self': &Self | 2660 | [82; 86) 'self': &Self |
2700 | [210; 361) '{ ..., i8 }': () | 2661 | [210; 361) '{ ..., i8 }': () |
@@ -2725,7 +2686,6 @@ fn test() { | |||
2725 | } | 2686 | } |
2726 | "#), | 2687 | "#), |
2727 | @r###" | 2688 | @r###" |
2728 | |||
2729 | [33; 37) 'self': &Self | 2689 | [33; 37) 'self': &Self |
2730 | [102; 127) '{ ...d(); }': () | 2690 | [102; 127) '{ ...d(); }': () |
2731 | [108; 109) 'S': S<u32>(T) -> S<T> | 2691 | [108; 109) 'S': S<u32>(T) -> S<T> |
@@ -3130,7 +3090,6 @@ fn test<T: Iterable<Item=u32>>() { | |||
3130 | } | 3090 | } |
3131 | "#), | 3091 | "#), |
3132 | @r###" | 3092 | @r###" |
3133 | |||
3134 | [67; 100) '{ ...own; }': () | 3093 | [67; 100) '{ ...own; }': () |
3135 | [77; 78) 'y': {unknown} | 3094 | [77; 78) 'y': {unknown} |
3136 | [90; 97) 'unknown': {unknown} | 3095 | [90; 97) 'unknown': {unknown} |
@@ -3146,7 +3105,6 @@ const A: u32 = 1 + 1; | |||
3146 | static B: u64 = { let x = 1; x }; | 3105 | static B: u64 = { let x = 1; x }; |
3147 | "#), | 3106 | "#), |
3148 | @r###" | 3107 | @r###" |
3149 | |||
3150 | [16; 17) '1': u32 | 3108 | [16; 17) '1': u32 |
3151 | [16; 21) '1 + 1': u32 | 3109 | [16; 21) '1 + 1': u32 |
3152 | [20; 21) '1': u32 | 3110 | [20; 21) '1': u32 |
@@ -3170,7 +3128,6 @@ fn test() -> u64 { | |||
3170 | } | 3128 | } |
3171 | "#), | 3129 | "#), |
3172 | @r###" | 3130 | @r###" |
3173 | |||
3174 | [38; 87) '{ ... a.1 }': u64 | 3131 | [38; 87) '{ ... a.1 }': u64 |
3175 | [48; 49) 'a': S | 3132 | [48; 49) 'a': S |
3176 | [52; 53) 'S': S(i32, u64) -> S | 3133 | [52; 53) 'S': S(i32, u64) -> S |
@@ -3225,7 +3182,6 @@ fn indexing_arrays() { | |||
3225 | assert_snapshot!( | 3182 | assert_snapshot!( |
3226 | infer("fn main() { &mut [9][2]; }"), | 3183 | infer("fn main() { &mut [9][2]; }"), |
3227 | @r###" | 3184 | @r###" |
3228 | |||
3229 | [10; 26) '{ &mut...[2]; }': () | 3185 | [10; 26) '{ &mut...[2]; }': () |
3230 | [12; 23) '&mut [9][2]': &mut {unknown} | 3186 | [12; 23) '&mut [9][2]': &mut {unknown} |
3231 | [17; 20) '[9]': [i32;_] | 3187 | [17; 20) '[9]': [i32;_] |
@@ -4822,9 +4778,9 @@ fn main() { | |||
4822 | } | 4778 | } |
4823 | "#), | 4779 | "#), |
4824 | @r###" | 4780 | @r###" |
4825 | ![0; 1) '6': i32 | 4781 | ![0; 1) '6': i32 |
4826 | [64; 88) '{ ...!(); }': () | 4782 | [64; 88) '{ ...!(); }': () |
4827 | [74; 75) 'x': i32 | 4783 | [74; 75) 'x': i32 |
4828 | "### | 4784 | "### |
4829 | ); | 4785 | ); |
4830 | } | 4786 | } |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 75351c17d..68304b950 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -191,11 +191,11 @@ impl ToChalk for Impl { | |||
191 | type Chalk = chalk_ir::ImplId; | 191 | type Chalk = chalk_ir::ImplId; |
192 | 192 | ||
193 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { | 193 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { |
194 | db.intern_impl(self).into() | 194 | db.intern_chalk_impl(self).into() |
195 | } | 195 | } |
196 | 196 | ||
197 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { | 197 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { |
198 | db.lookup_intern_impl(impl_id.into()) | 198 | db.lookup_intern_chalk_impl(impl_id.into()) |
199 | } | 199 | } |
200 | } | 200 | } |
201 | 201 | ||
@@ -630,7 +630,7 @@ fn impl_block_datum( | |||
630 | .target_trait_ref(db) | 630 | .target_trait_ref(db) |
631 | .expect("FIXME handle unresolved impl block trait ref") | 631 | .expect("FIXME handle unresolved impl block trait ref") |
632 | .subst(&bound_vars); | 632 | .subst(&bound_vars); |
633 | let impl_type = if impl_block.module().krate() == krate { | 633 | let impl_type = if impl_block.krate(db) == krate { |
634 | chalk_rust_ir::ImplType::Local | 634 | chalk_rust_ir::ImplType::Local |
635 | } else { | 635 | } else { |
636 | chalk_rust_ir::ImplType::External | 636 | chalk_rust_ir::ImplType::External |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 09a39e721..10cb87d37 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -67,6 +67,11 @@ impl ExprScopes { | |||
67 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) | 67 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) |
68 | } | 68 | } |
69 | 69 | ||
70 | pub fn resolve_name_in_scope(&self, scope: ScopeId, name: &Name) -> Option<&ScopeEntry> { | ||
71 | self.scope_chain(Some(scope)) | ||
72 | .find_map(|scope| self.entries(scope).iter().find(|it| it.name == *name)) | ||
73 | } | ||
74 | |||
70 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | 75 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { |
71 | self.scope_by_expr.get(&expr).copied() | 76 | self.scope_by_expr.get(&expr).copied() |
72 | } | 77 | } |
@@ -163,3 +168,217 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
163 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), | 168 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), |
164 | }; | 169 | }; |
165 | } | 170 | } |
171 | |||
172 | #[cfg(test)] | ||
173 | mod tests { | ||
174 | use hir_expand::{name::AsName, Source}; | ||
175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; | ||
176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | ||
177 | use test_utils::{assert_eq_text, extract_offset}; | ||
178 | |||
179 | use crate::{db::DefDatabase2, test_db::TestDB, FunctionId, ModuleDefId}; | ||
180 | |||
181 | fn find_function(db: &TestDB, file_id: FileId) -> FunctionId { | ||
182 | let krate = db.test_crate(); | ||
183 | let crate_def_map = db.crate_def_map(krate); | ||
184 | |||
185 | let module = crate_def_map.modules_for_file(file_id).next().unwrap(); | ||
186 | let (_, res) = crate_def_map[module].scope.entries().next().unwrap(); | ||
187 | match res.def.take_values().unwrap() { | ||
188 | ModuleDefId::FunctionId(it) => it, | ||
189 | _ => panic!(), | ||
190 | } | ||
191 | } | ||
192 | |||
193 | fn do_check(code: &str, expected: &[&str]) { | ||
194 | let (off, code) = extract_offset(code); | ||
195 | let code = { | ||
196 | let mut buf = String::new(); | ||
197 | let off = u32::from(off) as usize; | ||
198 | buf.push_str(&code[..off]); | ||
199 | buf.push_str("marker"); | ||
200 | buf.push_str(&code[off..]); | ||
201 | buf | ||
202 | }; | ||
203 | |||
204 | let (db, file_id) = TestDB::with_single_file(&code); | ||
205 | |||
206 | let file_syntax = db.parse(file_id).syntax_node(); | ||
207 | let marker: ast::PathExpr = find_node_at_offset(&file_syntax, off).unwrap(); | ||
208 | let function = find_function(&db, file_id); | ||
209 | |||
210 | let scopes = db.expr_scopes(function.into()); | ||
211 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
212 | |||
213 | let expr_id = | ||
214 | source_map.node_expr(Source { file_id: file_id.into(), ast: &marker.into() }).unwrap(); | ||
215 | let scope = scopes.scope_for(expr_id); | ||
216 | |||
217 | let actual = scopes | ||
218 | .scope_chain(scope) | ||
219 | .flat_map(|scope| scopes.entries(scope)) | ||
220 | .map(|it| it.name().to_string()) | ||
221 | .collect::<Vec<_>>() | ||
222 | .join("\n"); | ||
223 | let expected = expected.join("\n"); | ||
224 | assert_eq_text!(&expected, &actual); | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn test_lambda_scope() { | ||
229 | do_check( | ||
230 | r" | ||
231 | fn quux(foo: i32) { | ||
232 | let f = |bar, baz: i32| { | ||
233 | <|> | ||
234 | }; | ||
235 | }", | ||
236 | &["bar", "baz", "foo"], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn test_call_scope() { | ||
242 | do_check( | ||
243 | r" | ||
244 | fn quux() { | ||
245 | f(|x| <|> ); | ||
246 | }", | ||
247 | &["x"], | ||
248 | ); | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn test_method_call_scope() { | ||
253 | do_check( | ||
254 | r" | ||
255 | fn quux() { | ||
256 | z.f(|x| <|> ); | ||
257 | }", | ||
258 | &["x"], | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
263 | fn test_loop_scope() { | ||
264 | do_check( | ||
265 | r" | ||
266 | fn quux() { | ||
267 | loop { | ||
268 | let x = (); | ||
269 | <|> | ||
270 | }; | ||
271 | }", | ||
272 | &["x"], | ||
273 | ); | ||
274 | } | ||
275 | |||
276 | #[test] | ||
277 | fn test_match() { | ||
278 | do_check( | ||
279 | r" | ||
280 | fn quux() { | ||
281 | match () { | ||
282 | Some(x) => { | ||
283 | <|> | ||
284 | } | ||
285 | }; | ||
286 | }", | ||
287 | &["x"], | ||
288 | ); | ||
289 | } | ||
290 | |||
291 | #[test] | ||
292 | fn test_shadow_variable() { | ||
293 | do_check( | ||
294 | r" | ||
295 | fn foo(x: String) { | ||
296 | let x : &str = &x<|>; | ||
297 | }", | ||
298 | &["x"], | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | fn do_check_local_name(code: &str, expected_offset: u32) { | ||
303 | let (off, code) = extract_offset(code); | ||
304 | |||
305 | let (db, file_id) = TestDB::with_single_file(&code); | ||
306 | |||
307 | let file = db.parse(file_id).ok().unwrap(); | ||
308 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | ||
309 | .expect("failed to find a name at the target offset"); | ||
310 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | ||
311 | |||
312 | let function = find_function(&db, file_id); | ||
313 | |||
314 | let scopes = db.expr_scopes(function.into()); | ||
315 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
316 | |||
317 | let expr_scope = { | ||
318 | let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); | ||
319 | let expr_id = | ||
320 | source_map.node_expr(Source { file_id: file_id.into(), ast: &expr_ast }).unwrap(); | ||
321 | scopes.scope_for(expr_id).unwrap() | ||
322 | }; | ||
323 | |||
324 | let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap(); | ||
325 | let pat_src = source_map.pat_syntax(resolved.pat()).unwrap(); | ||
326 | |||
327 | let local_name = pat_src.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
328 | assert_eq!(local_name.range(), expected_name.syntax().text_range()); | ||
329 | } | ||
330 | |||
331 | #[test] | ||
332 | fn test_resolve_local_name() { | ||
333 | do_check_local_name( | ||
334 | r#" | ||
335 | fn foo(x: i32, y: u32) { | ||
336 | { | ||
337 | let z = x * 2; | ||
338 | } | ||
339 | { | ||
340 | let t = x<|> * 3; | ||
341 | } | ||
342 | }"#, | ||
343 | 21, | ||
344 | ); | ||
345 | } | ||
346 | |||
347 | #[test] | ||
348 | fn test_resolve_local_name_declaration() { | ||
349 | do_check_local_name( | ||
350 | r#" | ||
351 | fn foo(x: String) { | ||
352 | let x : &str = &x<|>; | ||
353 | }"#, | ||
354 | 21, | ||
355 | ); | ||
356 | } | ||
357 | |||
358 | #[test] | ||
359 | fn test_resolve_local_name_shadow() { | ||
360 | do_check_local_name( | ||
361 | r" | ||
362 | fn foo(x: String) { | ||
363 | let x : &str = &x; | ||
364 | x<|> | ||
365 | } | ||
366 | ", | ||
367 | 53, | ||
368 | ); | ||
369 | } | ||
370 | |||
371 | #[test] | ||
372 | fn ref_patterns_contribute_bindings() { | ||
373 | do_check_local_name( | ||
374 | r" | ||
375 | fn foo() { | ||
376 | if let Some(&from) = bar() { | ||
377 | from<|>; | ||
378 | } | ||
379 | } | ||
380 | ", | ||
381 | 53, | ||
382 | ); | ||
383 | } | ||
384 | } | ||
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 40b5920d9..348aca07f 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -8,30 +8,32 @@ use ra_syntax::ast; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | adt::{EnumData, StructData}, | 9 | adt::{EnumData, StructData}, |
10 | body::{scope::ExprScopes, Body, BodySourceMap}, | 10 | body::{scope::ExprScopes, Body, BodySourceMap}, |
11 | imp::ImplData, | ||
11 | nameres::{ | 12 | nameres::{ |
12 | raw::{ImportSourceMap, RawItems}, | 13 | raw::{ImportSourceMap, RawItems}, |
13 | CrateDefMap, | 14 | CrateDefMap, |
14 | }, | 15 | }, |
15 | DefWithBodyId, EnumId, StructOrUnionId, | 16 | DefWithBodyId, EnumId, ImplId, ItemLoc, StructOrUnionId, |
16 | }; | 17 | }; |
17 | 18 | ||
18 | #[salsa::query_group(InternDatabaseStorage)] | 19 | #[salsa::query_group(InternDatabaseStorage)] |
19 | pub trait InternDatabase: SourceDatabase { | 20 | pub trait InternDatabase: SourceDatabase { |
20 | #[salsa::interned] | 21 | #[salsa::interned] |
21 | fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId; | 22 | fn intern_function(&self, loc: ItemLoc<ast::FnDef>) -> crate::FunctionId; |
22 | #[salsa::interned] | 23 | #[salsa::interned] |
23 | fn intern_struct_or_union(&self, loc: crate::ItemLoc<ast::StructDef>) | 24 | fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> crate::StructOrUnionId; |
24 | -> crate::StructOrUnionId; | ||
25 | #[salsa::interned] | 25 | #[salsa::interned] |
26 | fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; | 26 | fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> crate::EnumId; |
27 | #[salsa::interned] | 27 | #[salsa::interned] |
28 | fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId; | 28 | fn intern_const(&self, loc: ItemLoc<ast::ConstDef>) -> crate::ConstId; |
29 | #[salsa::interned] | 29 | #[salsa::interned] |
30 | fn intern_static(&self, loc: crate::ItemLoc<ast::StaticDef>) -> crate::StaticId; | 30 | fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> crate::StaticId; |
31 | #[salsa::interned] | 31 | #[salsa::interned] |
32 | fn intern_trait(&self, loc: crate::ItemLoc<ast::TraitDef>) -> crate::TraitId; | 32 | fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> crate::TraitId; |
33 | #[salsa::interned] | 33 | #[salsa::interned] |
34 | fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; | 34 | fn intern_type_alias(&self, loc: ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; |
35 | #[salsa::interned] | ||
36 | fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> crate::ImplId; | ||
35 | } | 37 | } |
36 | 38 | ||
37 | #[salsa::query_group(DefDatabase2Storage)] | 39 | #[salsa::query_group(DefDatabase2Storage)] |
@@ -54,6 +56,9 @@ pub trait DefDatabase2: InternDatabase + AstDatabase { | |||
54 | #[salsa::invoke(EnumData::enum_data_query)] | 56 | #[salsa::invoke(EnumData::enum_data_query)] |
55 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; | 57 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; |
56 | 58 | ||
59 | #[salsa::invoke(ImplData::impl_data_query)] | ||
60 | fn impl_data(&self, e: ImplId) -> Arc<ImplData>; | ||
61 | |||
57 | #[salsa::invoke(Body::body_with_source_map_query)] | 62 | #[salsa::invoke(Body::body_with_source_map_query)] |
58 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); | 63 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); |
59 | 64 | ||
diff --git a/crates/ra_hir_def/src/imp.rs b/crates/ra_hir_def/src/imp.rs new file mode 100644 index 000000000..717991c40 --- /dev/null +++ b/crates/ra_hir_def/src/imp.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | //! Defines hir-level representation of impls. | ||
2 | //! | ||
3 | //! The handling is similar, but is not quite the same as for other items, | ||
4 | //! because `impl`s don't have names. | ||
5 | |||
6 | use std::sync::Arc; | ||
7 | |||
8 | use ra_syntax::ast; | ||
9 | |||
10 | use crate::{ | ||
11 | db::DefDatabase2, type_ref::TypeRef, AssocItemId, AstItemDef, ConstId, FunctionId, ImplId, | ||
12 | LocationCtx, TypeAliasId, | ||
13 | }; | ||
14 | |||
15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
16 | pub struct ImplData { | ||
17 | target_trait: Option<TypeRef>, | ||
18 | target_type: TypeRef, | ||
19 | items: Vec<AssocItemId>, | ||
20 | negative: bool, | ||
21 | } | ||
22 | |||
23 | impl ImplData { | ||
24 | pub(crate) fn impl_data_query(db: &impl DefDatabase2, id: ImplId) -> Arc<ImplData> { | ||
25 | let src = id.source(db); | ||
26 | let items = db.ast_id_map(src.file_id); | ||
27 | |||
28 | let target_trait = src.ast.target_trait().map(TypeRef::from_ast); | ||
29 | let target_type = TypeRef::from_ast_opt(src.ast.target_type()); | ||
30 | let negative = src.ast.is_negative(); | ||
31 | |||
32 | let items = if let Some(item_list) = src.ast.item_list() { | ||
33 | let ctx = LocationCtx::new(db, id.module(db), src.file_id); | ||
34 | item_list | ||
35 | .impl_items() | ||
36 | .map(|item_node| match item_node { | ||
37 | ast::ImplItem::FnDef(it) => { | ||
38 | FunctionId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
39 | } | ||
40 | ast::ImplItem::ConstDef(it) => { | ||
41 | ConstId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
42 | } | ||
43 | ast::ImplItem::TypeAliasDef(it) => { | ||
44 | TypeAliasId::from_ast_id(ctx, items.ast_id(&it)).into() | ||
45 | } | ||
46 | }) | ||
47 | .collect() | ||
48 | } else { | ||
49 | Vec::new() | ||
50 | }; | ||
51 | |||
52 | let res = ImplData { target_trait, target_type, items, negative }; | ||
53 | Arc::new(res) | ||
54 | } | ||
55 | |||
56 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
57 | self.target_trait.as_ref() | ||
58 | } | ||
59 | |||
60 | pub fn target_type(&self) -> &TypeRef { | ||
61 | &self.target_type | ||
62 | } | ||
63 | |||
64 | pub fn items(&self) -> &[AssocItemId] { | ||
65 | &self.items | ||
66 | } | ||
67 | |||
68 | pub fn is_negative(&self) -> bool { | ||
69 | self.negative | ||
70 | } | ||
71 | } | ||
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 3fab7965c..0a59c4ad7 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -13,6 +13,7 @@ pub mod path; | |||
13 | pub mod type_ref; | 13 | pub mod type_ref; |
14 | pub mod builtin_type; | 14 | pub mod builtin_type; |
15 | pub mod adt; | 15 | pub mod adt; |
16 | pub mod imp; | ||
16 | pub mod diagnostics; | 17 | pub mod diagnostics; |
17 | pub mod expr; | 18 | pub mod expr; |
18 | pub mod body; | 19 | pub mod body; |
@@ -321,6 +322,18 @@ impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { | |||
321 | } | 322 | } |
322 | } | 323 | } |
323 | 324 | ||
325 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
326 | pub struct ImplId(salsa::InternId); | ||
327 | impl_intern_key!(ImplId); | ||
328 | impl AstItemDef<ast::ImplBlock> for ImplId { | ||
329 | fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self { | ||
330 | db.intern_impl(loc) | ||
331 | } | ||
332 | fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> { | ||
333 | db.lookup_intern_impl(self) | ||
334 | } | ||
335 | } | ||
336 | |||
324 | macro_rules! impl_froms { | 337 | macro_rules! impl_froms { |
325 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | 338 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { |
326 | $( | 339 | $( |
@@ -384,3 +397,15 @@ pub enum DefWithBodyId { | |||
384 | } | 397 | } |
385 | 398 | ||
386 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); | 399 | impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); |
400 | |||
401 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
402 | pub enum AssocItemId { | ||
403 | FunctionId(FunctionId), | ||
404 | ConstId(ConstId), | ||
405 | TypeAliasId(TypeAliasId), | ||
406 | } | ||
407 | // FIXME: not every function, ... is actually an assoc item. maybe we should make | ||
408 | // sure that you can only turn actual assoc items into AssocItemIds. This would | ||
409 | // require not implementing From, and instead having some checked way of | ||
410 | // casting them, and somehow making the constructors private, which would be annoying. | ||
411 | impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId); | ||
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index d3ecabb9b..49e33ccc4 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -58,7 +58,7 @@ mod tests; | |||
58 | 58 | ||
59 | use std::sync::Arc; | 59 | use std::sync::Arc; |
60 | 60 | ||
61 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId}; | 61 | use hir_expand::{ast_id_map::FileAstId, diagnostics::DiagnosticSink, name::Name, MacroDefId}; |
62 | use once_cell::sync::Lazy; | 62 | use once_cell::sync::Lazy; |
63 | use ra_arena::Arena; | 63 | use ra_arena::Arena; |
64 | use ra_db::{CrateId, Edition, FileId}; | 64 | use ra_db::{CrateId, Edition, FileId}; |
@@ -73,7 +73,7 @@ use crate::{ | |||
73 | diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, | 73 | diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, |
74 | }, | 74 | }, |
75 | path::Path, | 75 | path::Path, |
76 | AstId, CrateModuleId, ModuleDefId, ModuleId, TraitId, | 76 | AstId, CrateModuleId, FunctionId, ImplId, ModuleDefId, ModuleId, TraitId, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /// Contains all top-level defs from a macro-expanded crate | 79 | /// Contains all top-level defs from a macro-expanded crate |
@@ -87,7 +87,7 @@ pub struct CrateDefMap { | |||
87 | prelude: Option<ModuleId>, | 87 | prelude: Option<ModuleId>, |
88 | extern_prelude: FxHashMap<Name, ModuleDefId>, | 88 | extern_prelude: FxHashMap<Name, ModuleDefId>, |
89 | root: CrateModuleId, | 89 | root: CrateModuleId, |
90 | pub modules: Arena<CrateModuleId, ModuleData>, | 90 | modules: Arena<CrateModuleId, ModuleData>, |
91 | 91 | ||
92 | /// Some macros are not well-behavior, which leads to infinite loop | 92 | /// Some macros are not well-behavior, which leads to infinite loop |
93 | /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } | 93 | /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } |
@@ -122,11 +122,17 @@ pub struct ModuleData { | |||
122 | /// | 122 | /// |
123 | /// Note that non-inline modules, by definition, live inside non-macro file. | 123 | /// Note that non-inline modules, by definition, live inside non-macro file. |
124 | pub definition: Option<FileId>, | 124 | pub definition: Option<FileId>, |
125 | pub impls: Vec<ImplId>, | ||
126 | } | ||
127 | |||
128 | #[derive(Default, Debug, PartialEq, Eq, Clone)] | ||
129 | pub(crate) struct Declarations { | ||
130 | fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>, | ||
125 | } | 131 | } |
126 | 132 | ||
127 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 133 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
128 | pub struct ModuleScope { | 134 | pub struct ModuleScope { |
129 | pub items: FxHashMap<Name, Resolution>, | 135 | items: FxHashMap<Name, Resolution>, |
130 | /// Macros visable in current module in legacy textual scope | 136 | /// Macros visable in current module in legacy textual scope |
131 | /// | 137 | /// |
132 | /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. | 138 | /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. |
@@ -258,6 +264,17 @@ impl CrateDefMap { | |||
258 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); | 264 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); |
259 | (res.resolved_def, res.segment_index) | 265 | (res.resolved_def, res.segment_index) |
260 | } | 266 | } |
267 | |||
268 | pub fn modules(&self) -> impl Iterator<Item = CrateModuleId> + '_ { | ||
269 | self.modules.iter().map(|(id, _data)| id) | ||
270 | } | ||
271 | |||
272 | pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = CrateModuleId> + '_ { | ||
273 | self.modules | ||
274 | .iter() | ||
275 | .filter(move |(_id, data)| data.definition == Some(file_id)) | ||
276 | .map(|(id, _data)| id) | ||
277 | } | ||
261 | } | 278 | } |
262 | 279 | ||
263 | mod diagnostics { | 280 | mod diagnostics { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 37d0f3093..c9ccb9023 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, | 19 | per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, |
20 | }, | 20 | }, |
21 | path::{Path, PathKind}, | 21 | path::{Path, PathKind}, |
22 | AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, | 22 | AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, ImplId, |
23 | LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId, | 23 | LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, StructOrUnionId, TraitId, TypeAliasId, |
24 | UnionId, | 24 | UnionId, |
25 | }; | 25 | }; |
@@ -571,6 +571,15 @@ where | |||
571 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), | 571 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), |
572 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), | 572 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), |
573 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 573 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
574 | raw::RawItemKind::Impl(imp) => { | ||
575 | let module = ModuleId { | ||
576 | krate: self.def_collector.def_map.krate, | ||
577 | module_id: self.module_id, | ||
578 | }; | ||
579 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | ||
580 | let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); | ||
581 | self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) | ||
582 | } | ||
574 | } | 583 | } |
575 | } | 584 | } |
576 | } | 585 | } |
@@ -664,7 +673,8 @@ where | |||
664 | let name = def.name.clone(); | 673 | let name = def.name.clone(); |
665 | let def: PerNs = match def.kind { | 674 | let def: PerNs = match def.kind { |
666 | raw::DefKind::Function(ast_id) => { | 675 | raw::DefKind::Function(ast_id) => { |
667 | PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into()) | 676 | let f = FunctionId::from_ast_id(ctx, ast_id); |
677 | PerNs::values(f.into()) | ||
668 | } | 678 | } |
669 | raw::DefKind::Struct(ast_id) => { | 679 | raw::DefKind::Struct(ast_id) => { |
670 | let id = StructOrUnionId::from_ast_id(ctx, ast_id).into(); | 680 | let id = StructOrUnionId::from_ast_id(ctx, ast_id).into(); |
@@ -798,7 +808,7 @@ mod tests { | |||
798 | 808 | ||
799 | fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { | 809 | fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { |
800 | let (db, _file_id) = TestDB::with_single_file(&code); | 810 | let (db, _file_id) = TestDB::with_single_file(&code); |
801 | let krate = db.crate_graph().iter().next().unwrap(); | 811 | let krate = db.test_crate(); |
802 | 812 | ||
803 | let def_map = { | 813 | let def_map = { |
804 | let edition = db.crate_graph().edition(krate); | 814 | let edition = db.crate_graph().edition(krate); |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index f52002bc0..a0a2c7273 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -28,6 +28,7 @@ pub struct RawItems { | |||
28 | imports: Arena<ImportId, ImportData>, | 28 | imports: Arena<ImportId, ImportData>, |
29 | defs: Arena<Def, DefData>, | 29 | defs: Arena<Def, DefData>, |
30 | macros: Arena<Macro, MacroData>, | 30 | macros: Arena<Macro, MacroData>, |
31 | impls: Arena<Impl, ImplData>, | ||
31 | /// items for top-level module | 32 | /// items for top-level module |
32 | items: Vec<RawItem>, | 33 | items: Vec<RawItem>, |
33 | } | 34 | } |
@@ -121,6 +122,13 @@ impl Index<Macro> for RawItems { | |||
121 | } | 122 | } |
122 | } | 123 | } |
123 | 124 | ||
125 | impl Index<Impl> for RawItems { | ||
126 | type Output = ImplData; | ||
127 | fn index(&self, idx: Impl) -> &ImplData { | ||
128 | &self.impls[idx] | ||
129 | } | ||
130 | } | ||
131 | |||
124 | // Avoid heap allocation on items without attributes. | 132 | // Avoid heap allocation on items without attributes. |
125 | type Attrs = Option<Arc<[Attr]>>; | 133 | type Attrs = Option<Arc<[Attr]>>; |
126 | 134 | ||
@@ -142,6 +150,7 @@ pub(super) enum RawItemKind { | |||
142 | Import(ImportId), | 150 | Import(ImportId), |
143 | Def(Def), | 151 | Def(Def), |
144 | Macro(Macro), | 152 | Macro(Macro), |
153 | Impl(Impl), | ||
145 | } | 154 | } |
146 | 155 | ||
147 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -203,6 +212,15 @@ pub(super) struct MacroData { | |||
203 | pub(super) builtin: bool, | 212 | pub(super) builtin: bool, |
204 | } | 213 | } |
205 | 214 | ||
215 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
216 | pub(super) struct Impl(RawId); | ||
217 | impl_arena_id!(Impl); | ||
218 | |||
219 | #[derive(Debug, PartialEq, Eq)] | ||
220 | pub(super) struct ImplData { | ||
221 | pub(super) ast_id: FileAstId<ast::ImplBlock>, | ||
222 | } | ||
223 | |||
206 | struct RawItemsCollector { | 224 | struct RawItemsCollector { |
207 | raw_items: RawItems, | 225 | raw_items: RawItems, |
208 | source_ast_id_map: Arc<AstIdMap>, | 226 | source_ast_id_map: Arc<AstIdMap>, |
@@ -236,8 +254,8 @@ impl RawItemsCollector { | |||
236 | self.add_extern_crate_item(current_module, extern_crate); | 254 | self.add_extern_crate_item(current_module, extern_crate); |
237 | return; | 255 | return; |
238 | } | 256 | } |
239 | ast::ModuleItem::ImplBlock(_) => { | 257 | ast::ModuleItem::ImplBlock(it) => { |
240 | // impls don't participate in name resolution | 258 | self.add_impl(current_module, it); |
241 | return; | 259 | return; |
242 | } | 260 | } |
243 | ast::ModuleItem::StructDef(it) => { | 261 | ast::ModuleItem::StructDef(it) => { |
@@ -376,6 +394,13 @@ impl RawItemsCollector { | |||
376 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | 394 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); |
377 | } | 395 | } |
378 | 396 | ||
397 | fn add_impl(&mut self, current_module: Option<Module>, imp: ast::ImplBlock) { | ||
398 | let attrs = self.parse_attrs(&imp); | ||
399 | let ast_id = self.source_ast_id_map.ast_id(&imp); | ||
400 | let imp = self.raw_items.impls.alloc(ImplData { ast_id }); | ||
401 | self.push_item(current_module, attrs, RawItemKind::Impl(imp)) | ||
402 | } | ||
403 | |||
379 | fn push_import( | 404 | fn push_import( |
380 | &mut self, | 405 | &mut self, |
381 | current_module: Option<Module>, | 406 | current_module: Option<Module>, |
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index 80dcec62f..903a22771 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs | |||
@@ -1,12 +1,12 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | 3 | use ra_db::SourceDatabaseExt; |
4 | 4 | ||
5 | use super::*; | 5 | use super::*; |
6 | 6 | ||
7 | fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { | 7 | fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { |
8 | let (mut db, pos) = TestDB::with_position(initial); | 8 | let (mut db, pos) = TestDB::with_position(initial); |
9 | let krate = db.crate_graph().iter().next().unwrap(); | 9 | let krate = db.test_crate(); |
10 | { | 10 | { |
11 | let events = db.log_executed(|| { | 11 | let events = db.log_executed(|| { |
12 | db.crate_def_map(krate); | 12 | db.crate_def_map(krate); |
@@ -111,7 +111,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
111 | m!(X); | 111 | m!(X); |
112 | ", | 112 | ", |
113 | ); | 113 | ); |
114 | let krate = db.crate_graph().iter().next().unwrap(); | 114 | let krate = db.test_crate(); |
115 | { | 115 | { |
116 | let events = db.log_executed(|| { | 116 | let events = db.log_executed(|| { |
117 | let crate_def_map = db.crate_def_map(krate); | 117 | let crate_def_map = db.crate_def_map(krate); |
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index dee364a14..eb7b85c07 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -656,7 +656,7 @@ fn unresolved_module_diagnostics() { | |||
656 | //- /foo.rs | 656 | //- /foo.rs |
657 | ", | 657 | ", |
658 | ); | 658 | ); |
659 | let krate = db.crate_graph().iter().next().unwrap(); | 659 | let krate = db.test_crate(); |
660 | 660 | ||
661 | let crate_def_map = db.crate_def_map(krate); | 661 | let crate_def_map = db.crate_def_map(krate); |
662 | 662 | ||
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs index 9cd17f0e3..35133d216 100644 --- a/crates/ra_hir_expand/src/quote.rs +++ b/crates/ra_hir_expand/src/quote.rs | |||
@@ -241,10 +241,8 @@ mod tests { | |||
241 | // } | 241 | // } |
242 | let struct_name = mk_ident("Foo"); | 242 | let struct_name = mk_ident("Foo"); |
243 | let fields = [mk_ident("name"), mk_ident("id")]; | 243 | let fields = [mk_ident("name"), mk_ident("id")]; |
244 | let fields = fields | 244 | let fields = |
245 | .into_iter() | 245 | fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten(); |
246 | .map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()) | ||
247 | .flatten(); | ||
248 | 246 | ||
249 | let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() }; | 247 | let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() }; |
250 | 248 | ||
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs index 010b45141..5c9dec13e 100644 --- a/crates/ra_ide_api/src/change.rs +++ b/crates/ra_ide_api/src/change.rs | |||
@@ -271,7 +271,6 @@ impl RootDatabase { | |||
271 | self.query(hir::db::AstIdMapQuery).sweep(sweep); | 271 | self.query(hir::db::AstIdMapQuery).sweep(sweep); |
272 | 272 | ||
273 | self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep); | 273 | self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep); |
274 | self.query(hir::db::ImplsInModuleWithSourceMapQuery).sweep(sweep); | ||
275 | self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); | 274 | self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); |
276 | 275 | ||
277 | self.query(hir::db::ExprScopesQuery).sweep(sweep); | 276 | self.query(hir::db::ExprScopesQuery).sweep(sweep); |
@@ -314,8 +313,6 @@ impl RootDatabase { | |||
314 | hir::db::RawItemsWithSourceMapQuery | 313 | hir::db::RawItemsWithSourceMapQuery |
315 | hir::db::RawItemsQuery | 314 | hir::db::RawItemsQuery |
316 | hir::db::CrateDefMapQuery | 315 | hir::db::CrateDefMapQuery |
317 | hir::db::ImplsInModuleWithSourceMapQuery | ||
318 | hir::db::ImplsInModuleQuery | ||
319 | hir::db::GenericParamsQuery | 316 | hir::db::GenericParamsQuery |
320 | hir::db::FnDataQuery | 317 | hir::db::FnDataQuery |
321 | hir::db::TypeAliasDataQuery | 318 | hir::db::TypeAliasDataQuery |
@@ -340,6 +337,7 @@ impl RootDatabase { | |||
340 | hir::db::TraitDatumQuery | 337 | hir::db::TraitDatumQuery |
341 | hir::db::StructDatumQuery | 338 | hir::db::StructDatumQuery |
342 | hir::db::ImplDatumQuery | 339 | hir::db::ImplDatumQuery |
340 | hir::db::ImplDataQuery | ||
343 | hir::db::TraitSolveQuery | 341 | hir::db::TraitSolveQuery |
344 | ]; | 342 | ]; |
345 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); | 343 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); |
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index b4df6ee2a..4e2c497e1 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs | |||
@@ -88,16 +88,16 @@ mod tests { | |||
88 | ", | 88 | ", |
89 | ), | 89 | ), |
90 | @r###" | 90 | @r###" |
91 | ⋮[ | 91 | [ |
92 | ⋮ CompletionItem { | 92 | CompletionItem { |
93 | ⋮ label: "the_field", | 93 | label: "the_field", |
94 | ⋮ source_range: [94; 94), | 94 | source_range: [94; 94), |
95 | ⋮ delete: [94; 94), | 95 | delete: [94; 94), |
96 | ⋮ insert: "the_field", | 96 | insert: "the_field", |
97 | ⋮ kind: Field, | 97 | kind: Field, |
98 | ⋮ detail: "u32", | 98 | detail: "u32", |
99 | ⋮ }, | 99 | }, |
100 | ⋮] | 100 | ] |
101 | "### | 101 | "### |
102 | ); | 102 | ); |
103 | } | 103 | } |
@@ -349,24 +349,24 @@ mod tests { | |||
349 | ", | 349 | ", |
350 | ), | 350 | ), |
351 | @r###" | 351 | @r###" |
352 | ⋮[ | 352 | [ |
353 | ⋮ CompletionItem { | 353 | CompletionItem { |
354 | ⋮ label: "0", | 354 | label: "0", |
355 | ⋮ source_range: [75; 75), | 355 | source_range: [75; 75), |
356 | ⋮ delete: [75; 75), | 356 | delete: [75; 75), |
357 | ⋮ insert: "0", | 357 | insert: "0", |
358 | ⋮ kind: Field, | 358 | kind: Field, |
359 | ⋮ detail: "i32", | 359 | detail: "i32", |
360 | ⋮ }, | 360 | }, |
361 | ⋮ CompletionItem { | 361 | CompletionItem { |
362 | ⋮ label: "1", | 362 | label: "1", |
363 | ⋮ source_range: [75; 75), | 363 | source_range: [75; 75), |
364 | ⋮ delete: [75; 75), | 364 | delete: [75; 75), |
365 | ⋮ insert: "1", | 365 | insert: "1", |
366 | ⋮ kind: Field, | 366 | kind: Field, |
367 | ⋮ detail: "f64", | 367 | detail: "f64", |
368 | ⋮ }, | 368 | }, |
369 | ⋮] | 369 | ] |
370 | "### | 370 | "### |
371 | ); | 371 | ); |
372 | } | 372 | } |
@@ -419,16 +419,16 @@ mod tests { | |||
419 | ", | 419 | ", |
420 | ), | 420 | ), |
421 | @r###" | 421 | @r###" |
422 | ⋮[ | 422 | [ |
423 | ⋮ CompletionItem { | 423 | CompletionItem { |
424 | ⋮ label: "the_field", | 424 | label: "the_field", |
425 | ⋮ source_range: [106; 106), | 425 | source_range: [106; 106), |
426 | ⋮ delete: [106; 106), | 426 | delete: [106; 106), |
427 | ⋮ insert: "the_field", | 427 | insert: "the_field", |
428 | ⋮ kind: Field, | 428 | kind: Field, |
429 | ⋮ detail: "u32", | 429 | detail: "u32", |
430 | ⋮ }, | 430 | }, |
431 | ⋮] | 431 | ] |
432 | "### | 432 | "### |
433 | ); | 433 | ); |
434 | } | 434 | } |
@@ -452,15 +452,15 @@ mod tests { | |||
452 | } | 452 | } |
453 | "###, CompletionKind::Keyword), | 453 | "###, CompletionKind::Keyword), |
454 | @r###" | 454 | @r###" |
455 | ⋮[ | 455 | [ |
456 | ⋮ CompletionItem { | 456 | CompletionItem { |
457 | ⋮ label: "await", | 457 | label: "await", |
458 | ⋮ source_range: [74; 74), | 458 | source_range: [74; 74), |
459 | ⋮ delete: [74; 74), | 459 | delete: [74; 74), |
460 | ⋮ insert: "await", | 460 | insert: "await", |
461 | ⋮ detail: "expr.await", | 461 | detail: "expr.await", |
462 | ⋮ }, | 462 | }, |
463 | ⋮] | 463 | ] |
464 | "### | 464 | "### |
465 | ) | 465 | ) |
466 | } | 466 | } |
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs index 3e936e3ec..502458706 100644 --- a/crates/ra_ide_api/src/completion/complete_fn_param.rs +++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs | |||
@@ -70,15 +70,15 @@ mod tests { | |||
70 | ", | 70 | ", |
71 | ), | 71 | ), |
72 | @r###" | 72 | @r###" |
73 | ⋮[ | 73 | [ |
74 | ⋮ CompletionItem { | 74 | CompletionItem { |
75 | ⋮ label: "file_id: FileId", | 75 | label: "file_id: FileId", |
76 | ⋮ source_range: [110; 114), | 76 | source_range: [110; 114), |
77 | ⋮ delete: [110; 114), | 77 | delete: [110; 114), |
78 | ⋮ insert: "file_id: FileId", | 78 | insert: "file_id: FileId", |
79 | ⋮ lookup: "file_id", | 79 | lookup: "file_id", |
80 | ⋮ }, | 80 | }, |
81 | ⋮] | 81 | ] |
82 | "### | 82 | "### |
83 | ); | 83 | ); |
84 | } | 84 | } |
@@ -94,15 +94,15 @@ mod tests { | |||
94 | ", | 94 | ", |
95 | ), | 95 | ), |
96 | @r###" | 96 | @r###" |
97 | ⋮[ | 97 | [ |
98 | ⋮ CompletionItem { | 98 | CompletionItem { |
99 | ⋮ label: "file_id: FileId", | 99 | label: "file_id: FileId", |
100 | ⋮ source_range: [110; 114), | 100 | source_range: [110; 114), |
101 | ⋮ delete: [110; 114), | 101 | delete: [110; 114), |
102 | ⋮ insert: "file_id: FileId", | 102 | insert: "file_id: FileId", |
103 | ⋮ lookup: "file_id", | 103 | lookup: "file_id", |
104 | ⋮ }, | 104 | }, |
105 | ⋮] | 105 | ] |
106 | "### | 106 | "### |
107 | ); | 107 | ); |
108 | } | 108 | } |
@@ -121,15 +121,15 @@ mod tests { | |||
121 | ", | 121 | ", |
122 | ), | 122 | ), |
123 | @r###" | 123 | @r###" |
124 | ⋮[ | 124 | [ |
125 | ⋮ CompletionItem { | 125 | CompletionItem { |
126 | ⋮ label: "file_id: FileId", | 126 | label: "file_id: FileId", |
127 | ⋮ source_range: [289; 293), | 127 | source_range: [289; 293), |
128 | ⋮ delete: [289; 293), | 128 | delete: [289; 293), |
129 | ⋮ insert: "file_id: FileId", | 129 | insert: "file_id: FileId", |
130 | ⋮ lookup: "file_id", | 130 | lookup: "file_id", |
131 | ⋮ }, | 131 | }, |
132 | ⋮] | 132 | ] |
133 | "### | 133 | "### |
134 | ); | 134 | ); |
135 | } | 135 | } |
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs index 48c688a08..eb7cd9ac2 100644 --- a/crates/ra_ide_api/src/completion/complete_keyword.rs +++ b/crates/ra_ide_api/src/completion/complete_keyword.rs | |||
@@ -131,29 +131,31 @@ mod tests { | |||
131 | use <|> | 131 | use <|> |
132 | ", | 132 | ", |
133 | ), | 133 | ), |
134 | @r###"[ | 134 | @r###" |
135 | CompletionItem { | 135 | [ |
136 | label: "crate", | 136 | CompletionItem { |
137 | source_range: [21; 21), | 137 | label: "crate", |
138 | delete: [21; 21), | 138 | source_range: [21; 21), |
139 | insert: "crate::", | 139 | delete: [21; 21), |
140 | kind: Keyword, | 140 | insert: "crate::", |
141 | }, | 141 | kind: Keyword, |
142 | CompletionItem { | 142 | }, |
143 | label: "self", | 143 | CompletionItem { |
144 | source_range: [21; 21), | 144 | label: "self", |
145 | delete: [21; 21), | 145 | source_range: [21; 21), |
146 | insert: "self", | 146 | delete: [21; 21), |
147 | kind: Keyword, | 147 | insert: "self", |
148 | }, | 148 | kind: Keyword, |
149 | CompletionItem { | 149 | }, |
150 | label: "super", | 150 | CompletionItem { |
151 | source_range: [21; 21), | 151 | label: "super", |
152 | delete: [21; 21), | 152 | source_range: [21; 21), |
153 | insert: "super::", | 153 | delete: [21; 21), |
154 | kind: Keyword, | 154 | insert: "super::", |
155 | }, | 155 | kind: Keyword, |
156 | ]"### | 156 | }, |
157 | ] | ||
158 | "### | ||
157 | ); | 159 | ); |
158 | 160 | ||
159 | assert_debug_snapshot!( | 161 | assert_debug_snapshot!( |
@@ -162,22 +164,24 @@ mod tests { | |||
162 | use a::<|> | 164 | use a::<|> |
163 | ", | 165 | ", |
164 | ), | 166 | ), |
165 | @r###"[ | 167 | @r###" |
166 | CompletionItem { | 168 | [ |
167 | label: "self", | 169 | CompletionItem { |
168 | source_range: [24; 24), | 170 | label: "self", |
169 | delete: [24; 24), | 171 | source_range: [24; 24), |
170 | insert: "self", | 172 | delete: [24; 24), |
171 | kind: Keyword, | 173 | insert: "self", |
172 | }, | 174 | kind: Keyword, |
173 | CompletionItem { | 175 | }, |
174 | label: "super", | 176 | CompletionItem { |
175 | source_range: [24; 24), | 177 | label: "super", |
176 | delete: [24; 24), | 178 | source_range: [24; 24), |
177 | insert: "super::", | 179 | delete: [24; 24), |
178 | kind: Keyword, | 180 | insert: "super::", |
179 | }, | 181 | kind: Keyword, |
180 | ]"### | 182 | }, |
183 | ] | ||
184 | "### | ||
181 | ); | 185 | ); |
182 | 186 | ||
183 | assert_debug_snapshot!( | 187 | assert_debug_snapshot!( |
@@ -186,22 +190,24 @@ mod tests { | |||
186 | use a::{b, <|>} | 190 | use a::{b, <|>} |
187 | ", | 191 | ", |
188 | ), | 192 | ), |
189 | @r###"[ | 193 | @r###" |
190 | CompletionItem { | 194 | [ |
191 | label: "self", | 195 | CompletionItem { |
192 | source_range: [28; 28), | 196 | label: "self", |
193 | delete: [28; 28), | 197 | source_range: [28; 28), |
194 | insert: "self", | 198 | delete: [28; 28), |
195 | kind: Keyword, | 199 | insert: "self", |
196 | }, | 200 | kind: Keyword, |
197 | CompletionItem { | 201 | }, |
198 | label: "super", | 202 | CompletionItem { |
199 | source_range: [28; 28), | 203 | label: "super", |
200 | delete: [28; 28), | 204 | source_range: [28; 28), |
201 | insert: "super::", | 205 | delete: [28; 28), |
202 | kind: Keyword, | 206 | insert: "super::", |
203 | }, | 207 | kind: Keyword, |
204 | ]"### | 208 | }, |
209 | ] | ||
210 | "### | ||
205 | ); | 211 | ); |
206 | } | 212 | } |
207 | 213 | ||
@@ -215,43 +221,45 @@ mod tests { | |||
215 | } | 221 | } |
216 | ", | 222 | ", |
217 | ), | 223 | ), |
218 | @r###"[ | 224 | @r###" |
219 | CompletionItem { | 225 | [ |
220 | label: "if", | 226 | CompletionItem { |
221 | source_range: [49; 49), | 227 | label: "if", |
222 | delete: [49; 49), | 228 | source_range: [49; 49), |
223 | insert: "if $0 {}", | 229 | delete: [49; 49), |
224 | kind: Keyword, | 230 | insert: "if $0 {}", |
225 | }, | 231 | kind: Keyword, |
226 | CompletionItem { | 232 | }, |
227 | label: "loop", | 233 | CompletionItem { |
228 | source_range: [49; 49), | 234 | label: "loop", |
229 | delete: [49; 49), | 235 | source_range: [49; 49), |
230 | insert: "loop {$0}", | 236 | delete: [49; 49), |
231 | kind: Keyword, | 237 | insert: "loop {$0}", |
232 | }, | 238 | kind: Keyword, |
233 | CompletionItem { | 239 | }, |
234 | label: "match", | 240 | CompletionItem { |
235 | source_range: [49; 49), | 241 | label: "match", |
236 | delete: [49; 49), | 242 | source_range: [49; 49), |
237 | insert: "match $0 {}", | 243 | delete: [49; 49), |
238 | kind: Keyword, | 244 | insert: "match $0 {}", |
239 | }, | 245 | kind: Keyword, |
240 | CompletionItem { | 246 | }, |
241 | label: "return", | 247 | CompletionItem { |
242 | source_range: [49; 49), | 248 | label: "return", |
243 | delete: [49; 49), | 249 | source_range: [49; 49), |
244 | insert: "return;", | 250 | delete: [49; 49), |
245 | kind: Keyword, | 251 | insert: "return;", |
246 | }, | 252 | kind: Keyword, |
247 | CompletionItem { | 253 | }, |
248 | label: "while", | 254 | CompletionItem { |
249 | source_range: [49; 49), | 255 | label: "while", |
250 | delete: [49; 49), | 256 | source_range: [49; 49), |
251 | insert: "while $0 {}", | 257 | delete: [49; 49), |
252 | kind: Keyword, | 258 | insert: "while $0 {}", |
253 | }, | 259 | kind: Keyword, |