aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock8
-rw-r--r--Cargo.toml2
-rw-r--r--crates/ra_assists/src/assists/add_new.rs69
-rw-r--r--crates/ra_db/src/fixture.rs12
-rw-r--r--crates/ra_hir/src/code_model.rs29
-rw-r--r--crates/ra_hir/src/db.rs20
-rw-r--r--crates/ra_hir/src/expr.rs281
-rw-r--r--crates/ra_hir/src/expr/validation.rs137
-rw-r--r--crates/ra_hir/src/from_id.rs15
-rw-r--r--crates/ra_hir/src/from_source.rs78
-rw-r--r--crates/ra_hir/src/impl_block.rs260
-rw-r--r--crates/ra_hir/src/lang_item.rs2
-rw-r--r--crates/ra_hir/src/lib.rs6
-rw-r--r--crates/ra_hir/src/resolve.rs24
-rw-r--r--crates/ra_hir/src/source_binder.rs38
-rw-r--r--crates/ra_hir/src/test_db.rs2
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs80
-rw-r--r--crates/ra_hir/src/ty/tests.rs54
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs6
-rw-r--r--crates/ra_hir_def/src/body/scope.rs219
-rw-r--r--crates/ra_hir_def/src/db.rs23
-rw-r--r--crates/ra_hir_def/src/imp.rs71
-rw-r--r--crates/ra_hir_def/src/lib.rs25
-rw-r--r--crates/ra_hir_def/src/nameres.rs25
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs16
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs29
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs6
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs2
-rw-r--r--crates/ra_hir_expand/src/quote.rs6
-rw-r--r--crates/ra_ide_api/src/change.rs4
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs94
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs54
-rw-r--r--crates/ra_ide_api/src/completion/complete_keyword.rs960
-rw-r--r--crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs95
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs332
-rw-r--r--crates/ra_ide_api/src/completion/complete_pattern.rs60
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs298
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_literal.rs102
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_pattern.rs56
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs56
-rw-r--r--crates/ra_ide_api/src/completion/complete_snippet.rs74
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs160
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs44
-rw-r--r--crates/ra_ide_api/src/display/structure.rs372
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs314
-rw-r--r--crates/ra_ide_api/src/references/classify.rs16
-rw-r--r--crates/ra_ide_api/src/runnables.rs128
-rw-r--r--crates/ra_mbe/Cargo.toml2
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]]
1607name = "smallvec"
1608version = "1.0.0"
1609source = "registry+https://github.com/rust-lang/crates.io-index"
1610
1611[[package]]
1607name = "smol_str" 1612name = "smol_str"
1608version = "0.1.15" 1613version = "0.1.15"
1609source = "registry+https://github.com/rust-lang/crates.io-index" 1614source = "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]
10incremental = true 10incremental = true
11debug = 1 # only line info 11debug = 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)]
188mod tests { 191mod 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 {<|>}
345impl Foo { 349impl 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 {<|>}
357impl Foo { 361impl 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;
376struct Foo<'a, T: Foo<'a>> {}", 380struct 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##"
389pub struct AstId<N: AstNode> {
390 file_id: HirFileId,
391 file_ast_id: FileAstId<N>,
392}
393
394impl<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
400pub struct Source<T> {
401 pub file_id: HirFileId,<|>
402 pub ast: T,
403}
404
405impl<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##"
412pub struct AstId<N: AstNode> {
413 file_id: HirFileId,
414 file_ast_id: FileAstId<N>,
415}
416
417impl<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
423pub struct Source<T> {
424 pub file_id: HirFileId,
425 pub ast: T,
426}
427
428impl<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;
8use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 8use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
9 9
10use crate::{ 10use 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
15pub const WORKSPACE: SourceRootId = SourceRootId(0); 15pub 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
38impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} 46impl<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};
16use hir_expand::{ 16use hir_expand::{
17 diagnostics::DiagnosticSink, 17 diagnostics::DiagnosticSink,
@@ -23,13 +23,12 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
23use crate::{ 23use 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)]
1134pub 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
25pub use hir_def::db::{ 24pub 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};
30pub use hir_expand::db::{ 29pub 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
3pub(crate) mod validation;
4
5use std::sync::Arc; 3use std::sync::Arc;
6 4
5use hir_def::path::known;
6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::ast;
7use ra_syntax::AstPtr; 8use ra_syntax::AstPtr;
9use rustc_hash::FxHashSet;
8 10
9use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; 11use 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
11pub use hir_def::{ 18pub 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)] 53pub(crate) struct ExprValidator<'a, 'b: 'a> {
47mod 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); 59impl<'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 && &params[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
3use std::sync::Arc;
4
5use hir_def::path::known;
6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::ast;
8use rustc_hash::FxHashSet;
9
10use crate::{
11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingOkInTailExpr},
13 expr::AstPtr,
14 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
15 Adt, Function, Name, Path,
16};
17
18use super::{Expr, ExprId, RecordLitField};
19
20pub(crate) struct ExprValidator<'a, 'b: 'a> {
21 func: Function,
22 infer: Arc<InferenceResult>,
23 sink: &'a mut DiagnosticSink<'b>,
24}
25
26impl<'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 && &params[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
6use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; 6use hir_def::{AdtId, AssocItemId, DefWithBodyId, EnumVariantId, ModuleDefId};
7 7
8use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; 8use crate::{Adt, AssocItem, DefWithBody, EnumVariant, ModuleDef};
9 9
10macro_rules! from_id { 10macro_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
76impl 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
3use hir_def::{StructId, StructOrUnionId, UnionId}; 3use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId};
4use hir_expand::name::AsName; 4use hir_expand::name::AsName;
5use ra_syntax::{ 5use ra_syntax::{
6 ast::{self, AstNode, NameOwner}, 6 ast::{self, AstNode, NameOwner},
@@ -10,9 +10,9 @@ use ra_syntax::{
10use crate::{ 10use 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
18pub trait FromSource: Sized { 18pub trait FromSource: Sized {
@@ -82,14 +82,8 @@ impl FromSource for TypeAlias {
82impl FromSource for ImplBlock { 82impl 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
154impl Module { 148impl 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
3use rustc_hash::FxHashMap; 3use hir_def::{type_ref::TypeRef, AstItemDef};
4use std::sync::Arc; 4use ra_syntax::ast::{self};
5
6use hir_def::{attr::Attr, type_ref::TypeRef};
7use hir_expand::hygiene::Hygiene;
8use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
9use ra_cfg::CfgOptions;
10use ra_syntax::{
11 ast::{self, AstNode},
12 AstPtr,
13};
14 5
15use crate::{ 6use 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)]
28pub struct ImplSourceMap {
29 map: ArenaMap<ImplId, Source<AstPtr<ast::ImplBlock>>>,
30}
31
32impl 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)]
46pub struct ImplBlock {
47 module: Module,
48 impl_id: ImplId,
49}
50
51impl HasSource for ImplBlock { 14impl 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
59impl ImplBlock { 21impl 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)]
116pub struct ImplData {
117 target_trait: Option<TypeRef>,
118 target_type: TypeRef,
119 items: Vec<AssocItem>,
120 negative: bool,
121}
122
123impl 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)]
163pub struct ImplId(pub RawId);
164impl_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)]
172pub struct ModuleImplBlocks {
173 pub(crate) module: Module,
174 pub(crate) impls: Arena<ImplId, ImplData>,
175 impls_by_def: FxHashMap<AssocItem, ImplId>,
176}
177
178impl 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(&macro_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(&macro_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)]
55mod marks; 55mod marks;
56 56
57use hir_expand::AstId; 57use crate::resolve::Resolver;
58
59use crate::{ids::MacroFileKind, resolve::Resolver};
60 58
61pub use crate::{ 59pub 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)]
36pub(crate) struct ExprScope { 35pub(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)]
56pub enum TypeNs { 56pub(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)]
71pub enum ResolveValueResult { 71pub(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)]
77pub enum ValueNs { 77pub(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};
22use rustc_hash::FxHashSet;
23 22
24use crate::{ 23use 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
431fn scope_for( 409fn 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 @@
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::CrateModuleId;
9use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
10 9
11use crate::{ 10use 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
20use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; 18use 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)]
41pub struct CrateImplBlocks { 39pub 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
48impl CrateImplBlocks { 44impl 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
126fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayVec<[Crate; 2]>> { 90fn 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;
3146static B: u64 = { let x = 1; x }; 3105static 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)]
173mod 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;
8use crate::{ 8use 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)]
19pub trait InternDatabase: SourceDatabase { 20pub 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
6use std::sync::Arc;
7
8use ra_syntax::ast;
9
10use crate::{
11 db::DefDatabase2, type_ref::TypeRef, AssocItemId, AstItemDef, ConstId, FunctionId, ImplId,
12 LocationCtx, TypeAliasId,
13};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ImplData {
17 target_trait: Option<TypeRef>,
18 target_type: TypeRef,
19 items: Vec<AssocItemId>,
20 negative: bool,
21}
22
23impl 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;
13pub mod type_ref; 13pub mod type_ref;
14pub mod builtin_type; 14pub mod builtin_type;
15pub mod adt; 15pub mod adt;
16pub mod imp;
16pub mod diagnostics; 17pub mod diagnostics;
17pub mod expr; 18pub mod expr;
18pub mod body; 19pub 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)]
326pub struct ImplId(salsa::InternId);
327impl_intern_key!(ImplId);
328impl 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
324macro_rules! impl_froms { 337macro_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
386impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); 399impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId);
400
401#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
402pub 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.
411impl_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
59use std::sync::Arc; 59use std::sync::Arc;
60 60
61use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId}; 61use hir_expand::{ast_id_map::FileAstId, diagnostics::DiagnosticSink, name::Name, MacroDefId};
62use once_cell::sync::Lazy; 62use once_cell::sync::Lazy;
63use ra_arena::Arena; 63use ra_arena::Arena;
64use ra_db::{CrateId, Edition, FileId}; 64use 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)]
129pub(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)]
128pub struct ModuleScope { 134pub 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
263mod diagnostics { 280mod 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
125impl 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.
125type Attrs = Option<Arc<[Attr]>>; 133type 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)]
216pub(super) struct Impl(RawId);
217impl_arena_id!(Impl);
218
219#[derive(Debug, PartialEq, Eq)]
220pub(super) struct ImplData {
221 pub(super) ast_id: FileAstId<ast::ImplBlock>,
222}
223
206struct RawItemsCollector { 224struct 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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::{SourceDatabase, SourceDatabaseExt}; 3use ra_db::SourceDatabaseExt;
4 4
5use super::*; 5use super::*;
6 6
7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { 7fn 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,