diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 138 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 93 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 82 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/incremental.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/source_id.rs | 113 | ||||
-rw-r--r-- | crates/ra_hir/src/traits.rs | 52 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 95 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 12 |
17 files changed, 432 insertions, 314 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 5437133b8..88c13566c 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -17,6 +17,7 @@ use crate::{ | |||
17 | impl_block::ImplBlock, | 17 | impl_block::ImplBlock, |
18 | resolve::Resolver, | 18 | resolve::Resolver, |
19 | diagnostics::DiagnosticSink, | 19 | diagnostics::DiagnosticSink, |
20 | traits::{TraitItem, TraitData}, | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | /// hir::Crate describes a single crate. It's the main interface with which | 23 | /// hir::Crate describes a single crate. It's the main interface with which |
@@ -649,6 +650,18 @@ impl Trait { | |||
649 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | 650 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { |
650 | db.generic_params((*self).into()) | 651 | db.generic_params((*self).into()) |
651 | } | 652 | } |
653 | |||
654 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { | ||
655 | self.trait_data(db).name().clone() | ||
656 | } | ||
657 | |||
658 | pub fn items(self, db: &impl DefDatabase) -> Vec<TraitItem> { | ||
659 | self.trait_data(db).items().to_vec() | ||
660 | } | ||
661 | |||
662 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | ||
663 | db.trait_data(self) | ||
664 | } | ||
652 | } | 665 | } |
653 | 666 | ||
654 | impl Docs for Trait { | 667 | impl Docs for Trait { |
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index 14237060c..790e2b80f 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -76,7 +76,7 @@ impl Module { | |||
76 | import: ImportId, | 76 | import: ImportId, |
77 | ) -> TreeArc<ast::PathSegment> { | 77 | ) -> TreeArc<ast::PathSegment> { |
78 | let (file_id, source) = self.definition_source(db); | 78 | let (file_id, source) = self.definition_source(db); |
79 | let (_, source_map) = db.raw_items_with_source_map(file_id.original_file(db)); | 79 | let (_, source_map) = db.raw_items_with_source_map(file_id); |
80 | source_map.get(&source, import) | 80 | source_map.get(&source, import) |
81 | } | 81 | } |
82 | 82 | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index d3908f8ac..3296b9b31 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; | 3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; |
4 | use ra_db::{SourceDatabase, salsa, FileId}; | 4 | use ra_db::{SourceDatabase, salsa}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner, | 7 | HirFileId, MacroDefId, SourceFileItems, SourceItemId, Crate, Module, HirInterner, |
8 | Function, FnSignature, ExprScopes, TypeAlias, | 8 | Function, FnSignature, ExprScopes, TypeAlias, |
9 | Struct, Enum, StructField, | 9 | Struct, Enum, StructField, |
10 | Const, ConstSignature, Static, | 10 | Const, ConstSignature, Static, |
@@ -14,10 +14,14 @@ use crate::{ | |||
14 | impl_block::{ModuleImplBlocks, ImplSourceMap}, | 14 | impl_block::{ModuleImplBlocks, ImplSourceMap}, |
15 | generics::{GenericParams, GenericDef}, | 15 | generics::{GenericParams, GenericDef}, |
16 | type_ref::TypeRef, | 16 | type_ref::TypeRef, |
17 | traits::TraitData, Trait, ty::TraitRef | ||
17 | }; | 18 | }; |
18 | 19 | ||
19 | #[salsa::query_group(DefDatabaseStorage)] | 20 | #[salsa::query_group(DefDatabaseStorage)] |
20 | pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { | 21 | pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { |
22 | #[salsa::invoke(crate::ids::macro_def_query)] | ||
23 | fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>; | ||
24 | |||
21 | #[salsa::invoke(HirFileId::hir_parse)] | 25 | #[salsa::invoke(HirFileId::hir_parse)] |
22 | fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; | 26 | fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; |
23 | 27 | ||
@@ -27,17 +31,23 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { | |||
27 | #[salsa::invoke(crate::adt::EnumData::enum_data_query)] | 31 | #[salsa::invoke(crate::adt::EnumData::enum_data_query)] |
28 | fn enum_data(&self, e: Enum) -> Arc<EnumData>; | 32 | fn enum_data(&self, e: Enum) -> Arc<EnumData>; |
29 | 33 | ||
30 | #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)] | 34 | #[salsa::invoke(crate::traits::TraitData::trait_data_query)] |
35 | fn trait_data(&self, t: Trait) -> Arc<TraitData>; | ||
36 | |||
37 | #[salsa::invoke(crate::source_id::SourceFileItems::file_items_query)] | ||
31 | fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; | 38 | fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; |
32 | 39 | ||
33 | #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] | 40 | #[salsa::invoke(crate::source_id::SourceFileItems::file_item_query)] |
34 | fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; | 41 | fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; |
35 | 42 | ||
36 | #[salsa::invoke(RawItems::raw_items_query)] | 43 | #[salsa::invoke(RawItems::raw_items_query)] |
37 | fn raw_items(&self, file_id: FileId) -> Arc<RawItems>; | 44 | fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; |
38 | 45 | ||
39 | #[salsa::invoke(RawItems::raw_items_with_source_map_query)] | 46 | #[salsa::invoke(RawItems::raw_items_with_source_map_query)] |
40 | fn raw_items_with_source_map(&self, file_id: FileId) -> (Arc<RawItems>, Arc<ImportSourceMap>); | 47 | fn raw_items_with_source_map( |
48 | &self, | ||
49 | file_id: HirFileId, | ||
50 | ) -> (Arc<RawItems>, Arc<ImportSourceMap>); | ||
41 | 51 | ||
42 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] | 52 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] |
43 | fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; | 53 | fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; |
@@ -98,6 +108,9 @@ pub trait HirDatabase: DefDatabase { | |||
98 | 108 | ||
99 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 109 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
100 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 110 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
111 | |||
112 | #[salsa::invoke(crate::ty::method_resolution::implements)] | ||
113 | fn implements(&self, trait_ref: TraitRef) -> bool; | ||
101 | } | 114 | } |
102 | 115 | ||
103 | #[test] | 116 | #[test] |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 18401f865..e73dd5d21 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -5,12 +5,12 @@ use std::{ | |||
5 | }; | 5 | }; |
6 | 6 | ||
7 | use ra_db::{LocationInterner, FileId}; | 7 | use ra_db::{LocationInterner, FileId}; |
8 | use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; | 8 | use ra_syntax::{TreeArc, SourceFile, AstNode, ast}; |
9 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; | 9 | use ra_arena::{RawId, ArenaId, impl_arena_id}; |
10 | use mbe::MacroRules; | ||
10 | 11 | ||
11 | use crate::{ | 12 | use crate::{ |
12 | Module, | 13 | Module, DefDatabase, SourceItemId, SourceFileItemId, |
13 | DefDatabase, | ||
14 | }; | 14 | }; |
15 | 15 | ||
16 | #[derive(Debug, Default)] | 16 | #[derive(Debug, Default)] |
@@ -100,10 +100,7 @@ fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<Tree | |||
100 | let macro_call = ast::MacroCall::cast(&syntax).unwrap(); | 100 | let macro_call = ast::MacroCall::cast(&syntax).unwrap(); |
101 | let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?; | 101 | let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?; |
102 | 102 | ||
103 | let def_map = db.crate_def_map(loc.module.krate); | 103 | let macro_rules = db.macro_def(loc.def)?; |
104 | let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?; | ||
105 | let def_map = db.crate_def_map(krate); | ||
106 | let macro_rules = &def_map[macro_id]; | ||
107 | let tt = macro_rules.expand(¯o_arg).ok()?; | 104 | let tt = macro_rules.expand(¯o_arg).ok()?; |
108 | Some(mbe::token_tree_to_ast_item_list(&tt)) | 105 | Some(mbe::token_tree_to_ast_item_list(&tt)) |
109 | } | 106 | } |
@@ -126,6 +123,22 @@ impl From<MacroCallId> for HirFileId { | |||
126 | } | 123 | } |
127 | } | 124 | } |
128 | 125 | ||
126 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
127 | pub enum MacroDefId { | ||
128 | MacroByExample { source_item_id: SourceItemId }, | ||
129 | } | ||
130 | |||
131 | pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> { | ||
132 | let syntax_node = match id { | ||
133 | MacroDefId::MacroByExample { source_item_id } => db.file_item(source_item_id), | ||
134 | }; | ||
135 | let macro_call = ast::MacroCall::cast(&syntax_node).unwrap(); | ||
136 | let arg = macro_call.token_tree()?; | ||
137 | let (tt, _) = mbe::ast_to_token_tree(arg)?; | ||
138 | let rules = MacroRules::parse(&tt).ok()?; | ||
139 | Some(Arc::new(rules)) | ||
140 | } | ||
141 | |||
129 | /// `MacroCallId` identifies a particular macro invocation, like | 142 | /// `MacroCallId` identifies a particular macro invocation, like |
130 | /// `println!("Hello, {}", world)`. | 143 | /// `println!("Hello, {}", world)`. |
131 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 144 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -134,7 +147,7 @@ impl_arena_id!(MacroCallId); | |||
134 | 147 | ||
135 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 148 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
136 | pub struct MacroCallLoc { | 149 | pub struct MacroCallLoc { |
137 | pub(crate) module: Module, | 150 | pub(crate) def: MacroDefId, |
138 | pub(crate) source_item_id: SourceItemId, | 151 | pub(crate) source_item_id: SourceItemId, |
139 | } | 152 | } |
140 | 153 | ||
@@ -290,110 +303,3 @@ impl AstItemDef<ast::TypeAliasDef> for TypeId { | |||
290 | &interner.types | 303 | &interner.types |
291 | } | 304 | } |
292 | } | 305 | } |
293 | |||
294 | /// Identifier of item within a specific file. This is stable over reparses, so | ||
295 | /// it's OK to use it as a salsa key/value. | ||
296 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
297 | pub struct SourceFileItemId(RawId); | ||
298 | impl_arena_id!(SourceFileItemId); | ||
299 | |||
300 | impl SourceFileItemId { | ||
301 | pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId { | ||
302 | SourceItemId { file_id, item_id: self } | ||
303 | } | ||
304 | } | ||
305 | |||
306 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
307 | pub struct SourceItemId { | ||
308 | pub(crate) file_id: HirFileId, | ||
309 | pub(crate) item_id: SourceFileItemId, | ||
310 | } | ||
311 | |||
312 | /// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. | ||
313 | #[derive(Debug, PartialEq, Eq)] | ||
314 | pub struct SourceFileItems { | ||
315 | file_id: HirFileId, | ||
316 | arena: Arena<SourceFileItemId, SyntaxNodePtr>, | ||
317 | } | ||
318 | |||
319 | impl SourceFileItems { | ||
320 | pub(crate) fn file_items_query( | ||
321 | db: &impl DefDatabase, | ||
322 | file_id: HirFileId, | ||
323 | ) -> Arc<SourceFileItems> { | ||
324 | let source_file = db.hir_parse(file_id); | ||
325 | Arc::new(SourceFileItems::from_source_file(&source_file, file_id)) | ||
326 | } | ||
327 | |||
328 | pub(crate) fn file_item_query( | ||
329 | db: &impl DefDatabase, | ||
330 | source_item_id: SourceItemId, | ||
331 | ) -> TreeArc<SyntaxNode> { | ||
332 | let source_file = db.hir_parse(source_item_id.file_id); | ||
333 | db.file_items(source_item_id.file_id)[source_item_id.item_id] | ||
334 | .to_node(&source_file) | ||
335 | .to_owned() | ||
336 | } | ||
337 | |||
338 | pub(crate) fn from_source_file( | ||
339 | source_file: &SourceFile, | ||
340 | file_id: HirFileId, | ||
341 | ) -> SourceFileItems { | ||
342 | let mut res = SourceFileItems { file_id, arena: Arena::default() }; | ||
343 | // By walking the tree in bread-first order we make sure that parents | ||
344 | // get lower ids then children. That is, adding a new child does not | ||
345 | // change parent's id. This means that, say, adding a new function to a | ||
346 | // trait does not change ids of top-level items, which helps caching. | ||
347 | bfs(source_file.syntax(), |it| { | ||
348 | if let Some(module_item) = ast::ModuleItem::cast(it) { | ||
349 | res.alloc(module_item.syntax()); | ||
350 | } else if let Some(macro_call) = ast::MacroCall::cast(it) { | ||
351 | res.alloc(macro_call.syntax()); | ||
352 | } | ||
353 | }); | ||
354 | res | ||
355 | } | ||
356 | |||
357 | fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { | ||
358 | self.arena.alloc(SyntaxNodePtr::new(item)) | ||
359 | } | ||
360 | pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { | ||
361 | assert_eq!( | ||
362 | self.file_id, file_id, | ||
363 | "SourceFileItems: wrong file, expected {:?}, got {:?}", | ||
364 | self.file_id, file_id | ||
365 | ); | ||
366 | self.id_of_unchecked(item) | ||
367 | } | ||
368 | pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { | ||
369 | let ptr = SyntaxNodePtr::new(item); | ||
370 | if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) { | ||
371 | return id; | ||
372 | } | ||
373 | panic!( | ||
374 | "Can't find {:?} in SourceFileItems:\n{:?}", | ||
375 | item, | ||
376 | self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), | ||
377 | ); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | impl std::ops::Index<SourceFileItemId> for SourceFileItems { | ||
382 | type Output = SyntaxNodePtr; | ||
383 | fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { | ||
384 | &self.arena[idx] | ||
385 | } | ||
386 | } | ||
387 | |||
388 | /// Walks the subtree in bfs order, calling `f` for each node. | ||
389 | fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) { | ||
390 | let mut curr_layer = vec![node]; | ||
391 | let mut next_layer = vec![]; | ||
392 | while !curr_layer.is_empty() { | ||
393 | curr_layer.drain(..).for_each(|node| { | ||
394 | next_layer.extend(node.children()); | ||
395 | f(node); | ||
396 | }); | ||
397 | std::mem::swap(&mut curr_layer, &mut next_layer); | ||
398 | } | ||
399 | } | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index ce54d7608..ac2585de0 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -23,10 +23,12 @@ pub mod mock; | |||
23 | mod path; | 23 | mod path; |
24 | pub mod source_binder; | 24 | pub mod source_binder; |
25 | 25 | ||
26 | mod source_id; | ||
26 | mod ids; | 27 | mod ids; |
27 | mod name; | 28 | mod name; |
28 | mod nameres; | 29 | mod nameres; |
29 | mod adt; | 30 | mod adt; |
31 | mod traits; | ||
30 | mod type_alias; | 32 | mod type_alias; |
31 | mod type_ref; | 33 | mod type_ref; |
32 | mod ty; | 34 | mod ty; |
@@ -46,13 +48,14 @@ mod marks; | |||
46 | use crate::{ | 48 | use crate::{ |
47 | db::{HirDatabase, DefDatabase}, | 49 | db::{HirDatabase, DefDatabase}, |
48 | name::{AsName, KnownName}, | 50 | name::{AsName, KnownName}, |
49 | ids::{SourceItemId, SourceFileItems}, | 51 | source_id::SourceFileItemId, |
50 | }; | 52 | }; |
51 | 53 | ||
52 | pub use self::{ | 54 | pub use self::{ |
53 | path::{Path, PathKind}, | 55 | path::{Path, PathKind}, |
54 | name::Name, | 56 | name::Name, |
55 | ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, | 57 | source_id::{SourceFileItems, SourceItemId}, |
58 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner}, | ||
56 | nameres::{PerNs, Namespace}, | 59 | nameres::{PerNs, Namespace}, |
57 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, | 60 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, |
58 | impl_block::{ImplBlock, ImplItem}, | 61 | impl_block::{ImplBlock, ImplItem}, |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 56ed872d5..e962bbd31 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -61,9 +61,9 @@ use ra_db::{FileId, Edition}; | |||
61 | use test_utils::tested_by; | 61 | use test_utils::tested_by; |
62 | 62 | ||
63 | use crate::{ | 63 | use crate::{ |
64 | ModuleDef, Name, Crate, Module, | 64 | ModuleDef, Name, Crate, Module, SourceItemId, |
65 | DefDatabase, Path, PathKind, HirFileId, | 65 | DefDatabase, Path, PathKind, HirFileId, Trait, |
66 | ids::{SourceItemId, SourceFileItemId, MacroCallId}, | 66 | ids::MacroDefId, |
67 | diagnostics::DiagnosticSink, | 67 | diagnostics::DiagnosticSink, |
68 | nameres::diagnostics::DefDiagnostic, | 68 | nameres::diagnostics::DefDiagnostic, |
69 | }; | 69 | }; |
@@ -84,9 +84,7 @@ pub struct CrateDefMap { | |||
84 | extern_prelude: FxHashMap<Name, ModuleDef>, | 84 | extern_prelude: FxHashMap<Name, ModuleDef>, |
85 | root: CrateModuleId, | 85 | root: CrateModuleId, |
86 | modules: Arena<CrateModuleId, ModuleData>, | 86 | modules: Arena<CrateModuleId, ModuleData>, |
87 | macros: Arena<CrateMacroId, mbe::MacroRules>, | 87 | public_macros: FxHashMap<Name, MacroDefId>, |
88 | public_macros: FxHashMap<Name, CrateMacroId>, | ||
89 | macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>, | ||
90 | diagnostics: Vec<DefDiagnostic>, | 88 | diagnostics: Vec<DefDiagnostic>, |
91 | } | 89 | } |
92 | 90 | ||
@@ -97,18 +95,6 @@ impl std::ops::Index<CrateModuleId> for CrateDefMap { | |||
97 | } | 95 | } |
98 | } | 96 | } |
99 | 97 | ||
100 | impl std::ops::Index<CrateMacroId> for CrateDefMap { | ||
101 | type Output = mbe::MacroRules; | ||
102 | fn index(&self, id: CrateMacroId) -> &mbe::MacroRules { | ||
103 | &self.macros[id] | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /// An ID of a macro, **local** to a specific crate | ||
108 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
109 | pub(crate) struct CrateMacroId(RawId); | ||
110 | impl_arena_id!(CrateMacroId); | ||
111 | |||
112 | /// An ID of a module, **local** to a specific crate | 98 | /// An ID of a module, **local** to a specific crate |
113 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 99 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
114 | pub(crate) struct CrateModuleId(RawId); | 100 | pub(crate) struct CrateModuleId(RawId); |
@@ -139,6 +125,12 @@ impl ModuleScope { | |||
139 | pub fn get(&self, name: &Name) -> Option<&Resolution> { | 125 | pub fn get(&self, name: &Name) -> Option<&Resolution> { |
140 | self.items.get(name) | 126 | self.items.get(name) |
141 | } | 127 | } |
128 | pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { | ||
129 | self.items.values().filter_map(|r| match r.def.take_types() { | ||
130 | Some(ModuleDef::Trait(t)) => Some(t), | ||
131 | _ => None, | ||
132 | }) | ||
133 | } | ||
142 | } | 134 | } |
143 | 135 | ||
144 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 136 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
@@ -196,9 +188,7 @@ impl CrateDefMap { | |||
196 | prelude: None, | 188 | prelude: None, |
197 | root, | 189 | root, |
198 | modules, | 190 | modules, |
199 | macros: Arena::default(), | ||
200 | public_macros: FxHashMap::default(), | 191 | public_macros: FxHashMap::default(), |
201 | macro_resolutions: FxHashMap::default(), | ||
202 | diagnostics: Vec::new(), | 192 | diagnostics: Vec::new(), |
203 | } | 193 | } |
204 | }; | 194 | }; |
@@ -232,19 +222,11 @@ impl CrateDefMap { | |||
232 | self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) | 222 | self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) |
233 | } | 223 | } |
234 | 224 | ||
235 | pub(crate) fn resolve_macro( | ||
236 | &self, | ||
237 | macro_call_id: MacroCallId, | ||
238 | ) -> Option<(Crate, CrateMacroId)> { | ||
239 | self.macro_resolutions.get(¯o_call_id).map(|&it| it) | ||
240 | } | ||
241 | |||
242 | pub(crate) fn find_module_by_source( | 225 | pub(crate) fn find_module_by_source( |
243 | &self, | 226 | &self, |
244 | file_id: HirFileId, | 227 | file_id: HirFileId, |
245 | decl_id: Option<SourceFileItemId>, | 228 | decl_id: Option<SourceItemId>, |
246 | ) -> Option<CrateModuleId> { | 229 | ) -> Option<CrateModuleId> { |
247 | let decl_id = decl_id.map(|it| it.with_file_id(file_id)); | ||
248 | let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { | 230 | let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { |
249 | if decl_id.is_some() { | 231 | if decl_id.is_some() { |
250 | module_data.declaration == decl_id | 232 | module_data.declaration == decl_id |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 8830b4624..4fb298155 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -6,15 +6,15 @@ use ra_db::FileId; | |||
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, | 8 | Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, |
9 | DefDatabase, HirFileId, Name, Path, Crate, | 9 | DefDatabase, HirFileId, Name, Path, SourceItemId, |
10 | KnownName, | 10 | KnownName, |
11 | nameres::{ | 11 | nameres::{ |
12 | Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, | 12 | Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, |
13 | CrateDefMap, CrateModuleId, ModuleData, CrateMacroId, | 13 | CrateDefMap, CrateModuleId, ModuleData, |
14 | diagnostics::DefDiagnostic, | 14 | diagnostics::DefDiagnostic, |
15 | raw, | 15 | raw, |
16 | }, | 16 | }, |
17 | ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, | 17 | ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId}, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 20 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { |
@@ -51,8 +51,8 @@ struct DefCollector<DB> { | |||
51 | def_map: CrateDefMap, | 51 | def_map: CrateDefMap, |
52 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, | 52 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, |
53 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, | 53 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, |
54 | unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>, | 54 | unexpanded_macros: Vec<(CrateModuleId, SourceItemId, Path)>, |
55 | global_macro_scope: FxHashMap<Name, CrateMacroId>, | 55 | global_macro_scope: FxHashMap<Name, MacroDefId>, |
56 | } | 56 | } |
57 | 57 | ||
58 | impl<'a, DB> DefCollector<&'a DB> | 58 | impl<'a, DB> DefCollector<&'a DB> |
@@ -62,7 +62,7 @@ where | |||
62 | fn collect(&mut self) { | 62 | fn collect(&mut self) { |
63 | let crate_graph = self.db.crate_graph(); | 63 | let crate_graph = self.db.crate_graph(); |
64 | let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); | 64 | let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); |
65 | let raw_items = self.db.raw_items(file_id); | 65 | let raw_items = self.db.raw_items(file_id.into()); |
66 | let module_id = self.def_map.root; | 66 | let module_id = self.def_map.root; |
67 | self.def_map.modules[module_id].definition = Some(file_id); | 67 | self.def_map.modules[module_id].definition = Some(file_id); |
68 | ModCollector { | 68 | ModCollector { |
@@ -93,14 +93,11 @@ where | |||
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) { | 96 | fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) { |
97 | if let Ok(rules) = mbe::MacroRules::parse(tt) { | 97 | if export { |
98 | let macro_id = self.def_map.macros.alloc(rules); | 98 | self.def_map.public_macros.insert(name.clone(), macro_id); |
99 | if export { | ||
100 | self.def_map.public_macros.insert(name.clone(), macro_id); | ||
101 | } | ||
102 | self.global_macro_scope.insert(name, macro_id); | ||
103 | } | 99 | } |
100 | self.global_macro_scope.insert(name, macro_id); | ||
104 | } | 101 | } |
105 | 102 | ||
106 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 103 | fn resolve_imports(&mut self) -> ReachedFixedPoint { |
@@ -296,7 +293,7 @@ where | |||
296 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); | 293 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); |
297 | let mut resolved = Vec::new(); | 294 | let mut resolved = Vec::new(); |
298 | let mut res = ReachedFixedPoint::Yes; | 295 | let mut res = ReachedFixedPoint::Yes; |
299 | macros.retain(|(module_id, call_id, path, tt)| { | 296 | macros.retain(|(module_id, source_item_id, path)| { |
300 | if path.segments.len() != 2 { | 297 | if path.segments.len() != 2 { |
301 | return true; | 298 | return true; |
302 | } | 299 | } |
@@ -312,47 +309,24 @@ where | |||
312 | res = ReachedFixedPoint::No; | 309 | res = ReachedFixedPoint::No; |
313 | let def_map = self.db.crate_def_map(krate); | 310 | let def_map = self.db.crate_def_map(krate); |
314 | if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { | 311 | if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { |
315 | resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone())); | 312 | let call_id = |
313 | MacroCallLoc { def: macro_id, source_item_id: *source_item_id }.id(self.db); | ||
314 | resolved.push((*module_id, call_id)); | ||
316 | } | 315 | } |
317 | false | 316 | false |
318 | }); | 317 | }); |
319 | 318 | ||
320 | for (module_id, macro_call_id, macro_def_id, arg) in resolved { | 319 | for (module_id, macro_call_id) in resolved { |
321 | self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg); | 320 | self.collect_macro_expansion(module_id, macro_call_id); |
322 | } | 321 | } |
323 | res | 322 | res |
324 | } | 323 | } |
325 | 324 | ||
326 | fn collect_macro_expansion( | 325 | fn collect_macro_expansion(&mut self, module_id: CrateModuleId, macro_call_id: MacroCallId) { |
327 | &mut self, | 326 | let file_id: HirFileId = macro_call_id.into(); |
328 | module_id: CrateModuleId, | 327 | let raw_items = self.db.raw_items(file_id); |
329 | macro_call_id: MacroCallId, | 328 | ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } |
330 | macro_def_id: (Crate, CrateMacroId), | 329 | .collect(raw_items.items()) |
331 | macro_arg: tt::Subtree, | ||
332 | ) { | ||
333 | let (macro_krate, macro_id) = macro_def_id; | ||
334 | let dm; | ||
335 | let rules = if macro_krate == self.def_map.krate { | ||
336 | &self.def_map[macro_id] | ||
337 | } else { | ||
338 | dm = self.db.crate_def_map(macro_krate); | ||
339 | &dm[macro_id] | ||
340 | }; | ||
341 | if let Ok(expansion) = rules.expand(¯o_arg) { | ||
342 | self.def_map.macro_resolutions.insert(macro_call_id, macro_def_id); | ||
343 | // XXX: this **does not** go through a database, because we can't | ||
344 | // identify macro_call without adding the whole state of name resolution | ||
345 | // as a parameter to the query. | ||
346 | // | ||
347 | // So, we run the queries "manually" and we must ensure that | ||
348 | // `db.hir_parse(macro_call_id)` returns the same source_file. | ||
349 | let file_id: HirFileId = macro_call_id.into(); | ||
350 | let source_file = mbe::token_tree_to_ast_item_list(&expansion); | ||
351 | |||
352 | let raw_items = raw::RawItems::from_source_file(&source_file, file_id); | ||
353 | ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } | ||
354 | .collect(raw_items.items()) | ||
355 | } | ||
356 | } | 330 | } |
357 | 331 | ||
358 | fn finish(self) -> CrateDefMap { | 332 | fn finish(self) -> CrateDefMap { |
@@ -412,7 +386,7 @@ where | |||
412 | Ok(file_id) => { | 386 | Ok(file_id) => { |
413 | let module_id = | 387 | let module_id = |
414 | self.push_child_module(name.clone(), source_item_id, Some(file_id)); | 388 | self.push_child_module(name.clone(), source_item_id, Some(file_id)); |
415 | let raw_items = self.def_collector.db.raw_items(file_id); | 389 | let raw_items = self.def_collector.db.raw_items(file_id.into()); |
416 | ModCollector { | 390 | ModCollector { |
417 | def_collector: &mut *self.def_collector, | 391 | def_collector: &mut *self.def_collector, |
418 | module_id, | 392 | module_id, |
@@ -484,38 +458,33 @@ where | |||
484 | // Case 1: macro rules, define a macro in crate-global mutable scope | 458 | // Case 1: macro rules, define a macro in crate-global mutable scope |
485 | if is_macro_rules(&mac.path) { | 459 | if is_macro_rules(&mac.path) { |
486 | if let Some(name) = &mac.name { | 460 | if let Some(name) = &mac.name { |
487 | self.def_collector.define_macro(name.clone(), &mac.arg, mac.export) | 461 | let macro_id = MacroDefId::MacroByExample { |
462 | source_item_id: mac.source_item_id.with_file_id(self.file_id), | ||
463 | }; | ||
464 | self.def_collector.define_macro(name.clone(), macro_id, mac.export) | ||
488 | } | 465 | } |
489 | return; | 466 | return; |
490 | } | 467 | } |
491 | 468 | ||
492 | let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; | 469 | let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; |
493 | let macro_call_id = MacroCallLoc { | ||
494 | module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }, | ||
495 | source_item_id, | ||
496 | } | ||
497 | .id(self.def_collector.db); | ||
498 | 470 | ||
499 | // Case 2: try to expand macro_rules from this crate, triggering | 471 | // Case 2: try to expand macro_rules from this crate, triggering |
500 | // recursive item collection. | 472 | // recursive item collection. |
501 | if let Some(¯o_id) = | 473 | if let Some(¯o_id) = |
502 | mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) | 474 | mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) |
503 | { | 475 | { |
504 | self.def_collector.collect_macro_expansion( | 476 | let macro_call_id = |
505 | self.module_id, | 477 | MacroCallLoc { def: macro_id, source_item_id }.id(self.def_collector.db); |
506 | macro_call_id, | 478 | |
507 | (self.def_collector.def_map.krate, macro_id), | 479 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id); |
508 | mac.arg.clone(), | ||
509 | ); | ||
510 | return; | 480 | return; |
511 | } | 481 | } |
512 | 482 | ||
513 | // Case 3: path to a macro from another crate, expand during name resolution | 483 | // Case 3: path to a macro from another crate, expand during name resolution |
514 | self.def_collector.unexpanded_macros.push(( | 484 | self.def_collector.unexpanded_macros.push(( |
515 | self.module_id, | 485 | self.module_id, |
516 | macro_call_id, | 486 | source_item_id, |
517 | mac.path.clone(), | 487 | mac.path.clone(), |
518 | mac.arg.clone(), | ||
519 | )) | 488 | )) |
520 | } | 489 | } |
521 | } | 490 | } |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index f8ba398ec..f32004601 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -4,7 +4,6 @@ use std::{ | |||
4 | }; | 4 | }; |
5 | 5 | ||
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | use ra_db::FileId; | ||
8 | use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap}; | 7 | use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap}; |
9 | use ra_syntax::{ | 8 | use ra_syntax::{ |
10 | AstNode, SourceFile, AstPtr, TreeArc, | 9 | AstNode, SourceFile, AstPtr, TreeArc, |
@@ -13,9 +12,13 @@ use ra_syntax::{ | |||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, | 14 | DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, |
16 | ids::{SourceFileItemId, SourceFileItems}, | 15 | SourceFileItemId, SourceFileItems, |
17 | }; | 16 | }; |
18 | 17 | ||
18 | /// `RawItems` is a set of top-level items in a file (except for impls). | ||
19 | /// | ||
20 | /// It is the input to name resolution algorithm. `RawItems` are not invalidated | ||
21 | /// on most edits. | ||
19 | #[derive(Debug, Default, PartialEq, Eq)] | 22 | #[derive(Debug, Default, PartialEq, Eq)] |
20 | pub struct RawItems { | 23 | pub struct RawItems { |
21 | modules: Arena<Module, ModuleData>, | 24 | modules: Arena<Module, ModuleData>, |
@@ -32,11 +35,11 @@ pub struct ImportSourceMap { | |||
32 | } | 35 | } |
33 | 36 | ||
34 | impl ImportSourceMap { | 37 | impl ImportSourceMap { |
35 | pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { | 38 | fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { |
36 | self.map.insert(import, AstPtr::new(segment)) | 39 | self.map.insert(import, AstPtr::new(segment)) |
37 | } | 40 | } |
38 | 41 | ||
39 | pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { | 42 | pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { |
40 | let file = match source { | 43 | let file = match source { |
41 | ModuleSource::SourceFile(file) => &*file, | 44 | ModuleSource::SourceFile(file) => &*file, |
42 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | 45 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), |
@@ -47,40 +50,27 @@ impl ImportSourceMap { | |||
47 | } | 50 | } |
48 | 51 | ||
49 | impl RawItems { | 52 | impl RawItems { |
50 | pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: FileId) -> Arc<RawItems> { | 53 | pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> { |
51 | db.raw_items_with_source_map(file_id).0 | 54 | db.raw_items_with_source_map(file_id).0 |
52 | } | 55 | } |
53 | 56 | ||
54 | pub(crate) fn raw_items_with_source_map_query( | 57 | pub(crate) fn raw_items_with_source_map_query( |
55 | db: &impl DefDatabase, | 58 | db: &impl DefDatabase, |
56 | file_id: FileId, | 59 | file_id: HirFileId, |
57 | ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { | 60 | ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { |
58 | let mut collector = RawItemsCollector { | 61 | let mut collector = RawItemsCollector { |
59 | raw_items: RawItems::default(), | 62 | raw_items: RawItems::default(), |
60 | source_file_items: db.file_items(file_id.into()), | 63 | source_file_items: db.file_items(file_id.into()), |
61 | source_map: ImportSourceMap::default(), | 64 | source_map: ImportSourceMap::default(), |
62 | }; | 65 | }; |
63 | let source_file = db.parse(file_id); | 66 | let source_file = db.hir_parse(file_id); |
64 | collector.process_module(None, &*source_file); | 67 | collector.process_module(None, &*source_file); |
65 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) | 68 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) |
66 | } | 69 | } |
67 | 70 | ||
68 | pub(crate) fn items(&self) -> &[RawItem] { | 71 | pub(super) fn items(&self) -> &[RawItem] { |
69 | &self.items | 72 | &self.items |
70 | } | 73 | } |
71 | |||
72 | // We can't use queries during name resolution for fear of cycles, so this | ||
73 | // is a query-less variant of the above function. | ||
74 | pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems { | ||
75 | let source_file_items = SourceFileItems::from_source_file(source_file, file_id); | ||
76 | let mut collector = RawItemsCollector { | ||
77 | raw_items: RawItems::default(), | ||
78 | source_file_items: Arc::new(source_file_items), | ||
79 | source_map: ImportSourceMap::default(), | ||
80 | }; | ||
81 | collector.process_module(None, &*source_file); | ||
82 | collector.raw_items | ||
83 | } | ||
84 | } | 74 | } |
85 | 75 | ||
86 | impl Index<Module> for RawItems { | 76 | impl Index<Module> for RawItems { |
@@ -112,7 +102,7 @@ impl Index<Macro> for RawItems { | |||
112 | } | 102 | } |
113 | 103 | ||
114 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 104 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
115 | pub(crate) enum RawItem { | 105 | pub(super) enum RawItem { |
116 | Module(Module), | 106 | Module(Module), |
117 | Import(ImportId), | 107 | Import(ImportId), |
118 | Def(Def), | 108 | Def(Def), |
@@ -120,11 +110,11 @@ pub(crate) enum RawItem { | |||
120 | } | 110 | } |
121 | 111 | ||
122 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 112 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
123 | pub(crate) struct Module(RawId); | 113 | pub(super) struct Module(RawId); |
124 | impl_arena_id!(Module); | 114 | impl_arena_id!(Module); |
125 | 115 | ||
126 | #[derive(Debug, PartialEq, Eq)] | 116 | #[derive(Debug, PartialEq, Eq)] |
127 | pub(crate) enum ModuleData { | 117 | pub(super) enum ModuleData { |
128 | Declaration { name: Name, source_item_id: SourceFileItemId }, | 118 | Declaration { name: Name, source_item_id: SourceFileItemId }, |
129 | Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> }, | 119 | Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> }, |
130 | } | 120 | } |
@@ -135,26 +125,26 @@ impl_arena_id!(ImportId); | |||
135 | 125 | ||
136 | #[derive(Debug, Clone, PartialEq, Eq)] | 126 | #[derive(Debug, Clone, PartialEq, Eq)] |
137 | pub struct ImportData { | 127 | pub struct ImportData { |
138 | pub(crate) path: Path, | 128 | pub(super) path: Path, |
139 | pub(crate) alias: Option<Name>, | 129 | pub(super) alias: Option<Name>, |
140 | pub(crate) is_glob: bool, | 130 | pub(super) is_glob: bool, |
141 | pub(crate) is_prelude: bool, | 131 | pub(super) is_prelude: bool, |
142 | pub(crate) is_extern_crate: bool, | 132 | pub(super) is_extern_crate: bool, |
143 | } | 133 | } |
144 | 134 | ||
145 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 135 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
146 | pub(crate) struct Def(RawId); | 136 | pub(super) struct Def(RawId); |
147 | impl_arena_id!(Def); | 137 | impl_arena_id!(Def); |
148 | 138 | ||
149 | #[derive(Debug, PartialEq, Eq)] | 139 | #[derive(Debug, PartialEq, Eq)] |
150 | pub(crate) struct DefData { | 140 | pub(super) struct DefData { |
151 | pub(crate) source_item_id: SourceFileItemId, | 141 | pub(super) source_item_id: SourceFileItemId, |
152 | pub(crate) name: Name, | 142 | pub(super) name: Name, |
153 | pub(crate) kind: DefKind, | 143 | pub(super) kind: DefKind, |
154 | } | 144 | } |
155 | 145 | ||
156 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 146 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
157 | pub(crate) enum DefKind { | 147 | pub(super) enum DefKind { |
158 | Function, | 148 | Function, |
159 | Struct, | 149 | Struct, |
160 | Enum, | 150 | Enum, |
@@ -165,16 +155,15 @@ pub(crate) enum DefKind { | |||
165 | } | 155 | } |
166 | 156 | ||
167 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 157 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
168 | pub(crate) struct Macro(RawId); | 158 | pub(super) struct Macro(RawId); |
169 | impl_arena_id!(Macro); | 159 | impl_arena_id!(Macro); |
170 | 160 | ||
171 | #[derive(Debug, PartialEq, Eq)] | 161 | #[derive(Debug, PartialEq, Eq)] |
172 | pub(crate) struct MacroData { | 162 | pub(super) struct MacroData { |
173 | pub(crate) source_item_id: SourceFileItemId, | 163 | pub(super) source_item_id: SourceFileItemId, |
174 | pub(crate) path: Path, | 164 | pub(super) path: Path, |
175 | pub(crate) name: Option<Name>, | 165 | pub(super) name: Option<Name>, |
176 | pub(crate) arg: tt::Subtree, | 166 | pub(super) export: bool, |
177 | pub(crate) export: bool, | ||
178 | } | 167 | } |
179 | 168 | ||
180 | struct RawItemsCollector { | 169 | struct RawItemsCollector { |
@@ -291,18 +280,15 @@ impl RawItemsCollector { | |||
291 | } | 280 | } |
292 | 281 | ||
293 | fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) { | 282 | fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) { |
294 | let (path, arg) = match ( | 283 | let path = match m.path().and_then(Path::from_ast) { |
295 | m.path().and_then(Path::from_ast), | 284 | Some(it) => it, |
296 | m.token_tree().and_then(mbe::ast_to_token_tree), | ||
297 | ) { | ||
298 | (Some(path), Some((token_tree, _token_map))) => (path, token_tree), | ||
299 | _ => return, | 285 | _ => return, |
300 | }; | 286 | }; |
301 | 287 | ||
302 | let name = m.name().map(|it| it.as_name()); | 288 | let name = m.name().map(|it| it.as_name()); |
303 | let source_item_id = self.source_file_items.id_of_unchecked(m.syntax()); | 289 | let source_item_id = self.source_file_items.id_of_unchecked(m.syntax()); |
304 | let export = m.has_atom_attr("macro_export"); | 290 | let export = m.has_atom_attr("macro_export"); |
305 | let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export }); | 291 | let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, name, export }); |
306 | self.push_item(current_module, RawItem::Macro(m)); | 292 | self.push_item(current_module, RawItem::Macro(m)); |
307 | } | 293 | } |
308 | 294 | ||
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs index 698781923..a059634e2 100644 --- a/crates/ra_hir/src/nameres/tests/incremental.rs +++ b/crates/ra_hir/src/nameres/tests/incremental.rs | |||
@@ -90,34 +90,27 @@ fn adding_inner_items_should_not_invalidate_def_map() { | |||
90 | ); | 90 | ); |
91 | } | 91 | } |
92 | 92 | ||
93 | // It would be awesome to make this work, but it's unclear how | ||
94 | #[test] | 93 | #[test] |
95 | #[ignore] | 94 | fn typing_inside_a_macro_should_not_invalidate_def_map() { |
96 | fn typing_inside_a_function_inside_a_macro_should_not_invalidate_def_map() { | ||
97 | check_def_map_is_not_recomputed( | 95 | check_def_map_is_not_recomputed( |
98 | " | 96 | " |
99 | //- /lib.rs | 97 | //- /lib.rs |
98 | macro_rules! m { | ||
99 | ($ident:ident) => { | ||
100 | struct Foo; | ||
101 | } | ||
102 | } | ||
100 | mod foo; | 103 | mod foo; |
101 | 104 | ||
102 | use crate::foo::bar::Baz; | ||
103 | |||
104 | //- /foo/mod.rs | 105 | //- /foo/mod.rs |
105 | pub mod bar; | 106 | pub mod bar; |
106 | 107 | ||
107 | //- /foo/bar.rs | 108 | //- /foo/bar.rs |
108 | <|> | 109 | <|> |
109 | salsa::query_group! { | 110 | m!(X); |
110 | trait Baz { | ||
111 | fn foo() -> i32 { 1 + 1 } | ||
112 | } | ||
113 | } | ||
114 | ", | 111 | ", |
115 | " | 112 | " |
116 | salsa::query_group! { | 113 | m!(Y); |
117 | trait Baz { | ||
118 | fn foo() -> i32 { 92 } | ||
119 | } | ||
120 | } | ||
121 | ", | 114 | ", |
122 | ); | 115 | ); |
123 | } | 116 | } |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index f28154517..2609585b1 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | generics::GenericParams, | 11 | generics::GenericParams, |
12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, | 12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, |
13 | impl_block::ImplBlock, | 13 | impl_block::ImplBlock, |
14 | path::Path, | 14 | path::Path, Trait |
15 | }; | 15 | }; |
16 | 16 | ||
17 | #[derive(Debug, Clone, Default)] | 17 | #[derive(Debug, Clone, Default)] |
@@ -175,6 +175,21 @@ impl Resolver { | |||
175 | names | 175 | names |
176 | } | 176 | } |
177 | 177 | ||
178 | pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { | ||
179 | // FIXME prelude | ||
180 | self.scopes | ||
181 | .iter() | ||
182 | .rev() | ||
183 | .flat_map(|scope| { | ||
184 | match scope { | ||
185 | Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()), | ||
186 | _ => None, | ||
187 | } | ||
188 | .into_iter() | ||
189 | }) | ||
190 | .flatten() | ||
191 | } | ||
192 | |||
178 | fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { | 193 | fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { |
179 | self.scopes.iter().rev().find_map(|scope| match scope { | 194 | self.scopes.iter().rev().find_map(|scope| match scope { |
180 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), | 195 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 3645b73b4..db9e3a22e 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -13,9 +13,9 @@ use ra_syntax::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | HirDatabase, Function, Struct, Enum, | 16 | HirDatabase, Function, Struct, Enum, SourceItemId, |
17 | AsName, Module, HirFileId, Crate, Trait, Resolver, | 17 | AsName, Module, HirFileId, Crate, Trait, Resolver, |
18 | ids::{LocationCtx, SourceFileItemId}, | 18 | ids::LocationCtx, |
19 | expr | 19 | expr |
20 | }; | 20 | }; |
21 | 21 | ||
@@ -55,7 +55,7 @@ fn module_from_inline( | |||
55 | assert!(!module.has_semi()); | 55 | assert!(!module.has_semi()); |
56 | let file_id = file_id.into(); | 56 | let file_id = file_id.into(); |
57 | let file_items = db.file_items(file_id); | 57 | let file_items = db.file_items(file_id); |
58 | let item_id = file_items.id_of(file_id, module.syntax()); | 58 | let item_id = file_items.id_of(file_id, module.syntax()).with_file_id(file_id); |
59 | module_from_source(db, file_id, Some(item_id)) | 59 | module_from_source(db, file_id, Some(item_id)) |
60 | } | 60 | } |
61 | 61 | ||
@@ -75,7 +75,7 @@ pub fn module_from_child_node( | |||
75 | fn module_from_source( | 75 | fn module_from_source( |
76 | db: &impl HirDatabase, | 76 | db: &impl HirDatabase, |
77 | file_id: HirFileId, | 77 | file_id: HirFileId, |
78 | decl_id: Option<SourceFileItemId>, | 78 | decl_id: Option<SourceItemId>, |
79 | ) -> Option<Module> { | 79 | ) -> Option<Module> { |
80 | let source_root_id = db.file_source_root(file_id.as_original_file()); | 80 | let source_root_id = db.file_source_root(file_id.as_original_file()); |
81 | db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( | 81 | db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( |
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs new file mode 100644 index 000000000..62707ba6a --- /dev/null +++ b/crates/ra_hir/src/source_id.rs | |||
@@ -0,0 +1,113 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
4 | use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast}; | ||
5 | |||
6 | use crate::{HirFileId, DefDatabase}; | ||
7 | |||
8 | /// Identifier of item within a specific file. This is stable over reparses, so | ||
9 | /// it's OK to use it as a salsa key/value. | ||
10 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
11 | pub(crate) struct SourceFileItemId(RawId); | ||
12 | impl_arena_id!(SourceFileItemId); | ||
13 | |||
14 | impl SourceFileItemId { | ||
15 | pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId { | ||
16 | SourceItemId { file_id, item_id: self } | ||
17 | } | ||
18 | } | ||
19 | |||
20 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
21 | pub struct SourceItemId { | ||
22 | pub(crate) file_id: HirFileId, | ||
23 | pub(crate) item_id: SourceFileItemId, | ||
24 | } | ||
25 | |||
26 | /// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. | ||
27 | #[derive(Debug, PartialEq, Eq)] | ||
28 | pub struct SourceFileItems { | ||
29 | file_id: HirFileId, | ||
30 | arena: Arena<SourceFileItemId, SyntaxNodePtr>, | ||
31 | } | ||
32 | |||
33 | impl SourceFileItems { | ||
34 | pub(crate) fn file_items_query( | ||
35 | db: &impl DefDatabase, | ||
36 | file_id: HirFileId, | ||
37 | ) -> Arc<SourceFileItems> { | ||
38 | let source_file = db.hir_parse(file_id); | ||
39 | Arc::new(SourceFileItems::from_source_file(&source_file, file_id)) | ||
40 | } | ||
41 | |||
42 | pub(crate) fn file_item_query( | ||
43 | db: &impl DefDatabase, | ||
44 | source_item_id: SourceItemId, | ||
45 | ) -> TreeArc<SyntaxNode> { | ||
46 | let source_file = db.hir_parse(source_item_id.file_id); | ||
47 | db.file_items(source_item_id.file_id)[source_item_id.item_id] | ||
48 | .to_node(&source_file) | ||
49 | .to_owned() | ||
50 | } | ||
51 | |||
52 | pub(crate) fn from_source_file( | ||
53 | source_file: &SourceFile, | ||
54 | file_id: HirFileId, | ||
55 | ) -> SourceFileItems { | ||
56 | let mut res = SourceFileItems { file_id, arena: Arena::default() }; | ||
57 | // By walking the tree in bread-first order we make sure that parents | ||
58 | // get lower ids then children. That is, adding a new child does not | ||
59 | // change parent's id. This means that, say, adding a new function to a | ||
60 | // trait does not change ids of top-level items, which helps caching. | ||
61 | bfs(source_file.syntax(), |it| { | ||
62 | if let Some(module_item) = ast::ModuleItem::cast(it) { | ||
63 | res.alloc(module_item.syntax()); | ||
64 | } else if let Some(macro_call) = ast::MacroCall::cast(it) { | ||
65 | res.alloc(macro_call.syntax()); | ||
66 | } | ||
67 | }); | ||
68 | res | ||
69 | } | ||
70 | |||
71 | fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { | ||
72 | self.arena.alloc(SyntaxNodePtr::new(item)) | ||
73 | } | ||
74 | pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { | ||
75 | assert_eq!( | ||
76 | self.file_id, file_id, | ||
77 | "SourceFileItems: wrong file, expected {:?}, got {:?}", | ||
78 | self.file_id, file_id | ||
79 | ); | ||
80 | self.id_of_unchecked(item) | ||
81 | } | ||
82 | pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { | ||
83 | let ptr = SyntaxNodePtr::new(item); | ||
84 | if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) { | ||
85 | return id; | ||
86 | } | ||
87 | panic!( | ||
88 | "Can't find {:?} in SourceFileItems:\n{:?}", | ||
89 | item, | ||
90 | self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), | ||
91 | ); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | impl std::ops::Index<SourceFileItemId> for SourceFileItems { | ||
96 | type Output = SyntaxNodePtr; | ||
97 | fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { | ||
98 | &self.arena[idx] | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /// Walks the subtree in bfs order, calling `f` for each node. | ||
103 | fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) { | ||
104 | let mut curr_layer = vec![node]; | ||
105 | let mut next_layer = vec![]; | ||
106 | while !curr_layer.is_empty() { | ||
107 | curr_layer.drain(..).for_each(|node| { | ||
108 | next_layer.extend(node.children()); | ||
109 | f(node); | ||
110 | }); | ||
111 | std::mem::swap(&mut curr_layer, &mut next_layer); | ||
112 | } | ||
113 | } | ||
diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs new file mode 100644 index 000000000..725bdd5cb --- /dev/null +++ b/crates/ra_hir/src/traits.rs | |||
@@ -0,0 +1,52 @@ | |||
1 | //! HIR for trait definitions. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use ra_syntax::ast::{self, NameOwner}; | ||
6 | |||
7 | use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName}; | ||
8 | |||
9 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
10 | pub struct TraitData { | ||
11 | name: Option<Name>, | ||
12 | items: Vec<TraitItem>, | ||
13 | } | ||
14 | |||
15 | impl TraitData { | ||
16 | pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: Trait) -> Arc<TraitData> { | ||
17 | let (file_id, node) = tr.source(db); | ||
18 | let name = node.name().map(|n| n.as_name()); | ||
19 | let module = tr.module(db); | ||
20 | let ctx = LocationCtx::new(db, module, file_id); | ||
21 | let items = if let Some(item_list) = node.item_list() { | ||
22 | item_list | ||
23 | .impl_items() | ||
24 | .map(|item_node| match item_node.kind() { | ||
25 | ast::ImplItemKind::FnDef(it) => Function { id: ctx.to_def(it) }.into(), | ||
26 | ast::ImplItemKind::ConstDef(it) => Const { id: ctx.to_def(it) }.into(), | ||
27 | ast::ImplItemKind::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(it) }.into(), | ||
28 | }) | ||
29 | .collect() | ||
30 | } else { | ||
31 | Vec::new() | ||
32 | }; | ||
33 | Arc::new(TraitData { name, items }) | ||
34 | } | ||
35 | |||
36 | pub(crate) fn name(&self) -> &Option<Name> { | ||
37 | &self.name | ||
38 | } | ||
39 | |||
40 | pub(crate) fn items(&self) -> &[TraitItem] { | ||
41 | &self.items | ||
42 | } | ||
43 | } | ||
44 | |||
45 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
46 | pub enum TraitItem { | ||
47 | Function(Function), | ||
48 | Const(Const), | ||
49 | TypeAlias(TypeAlias), | ||
50 | // Existential | ||
51 | } | ||
52 | impl_froms!(TraitItem: Function, Const, TypeAlias); | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 7d25ade47..d42c61e9d 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -14,7 +14,7 @@ pub(crate) mod display; | |||
14 | use std::sync::Arc; | 14 | use std::sync::Arc; |
15 | use std::{fmt, mem}; | 15 | use std::{fmt, mem}; |
16 | 16 | ||
17 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase}; | 17 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait}; |
18 | 18 | ||
19 | pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; | 19 | pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; |
20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; | 20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; |
@@ -91,7 +91,7 @@ pub enum TypeCtor { | |||
91 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 91 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
92 | /// type like `bool`, a struct, tuple, function pointer, reference or | 92 | /// type like `bool`, a struct, tuple, function pointer, reference or |
93 | /// several other things. | 93 | /// several other things. |
94 | #[derive(Clone, PartialEq, Eq, Debug)] | 94 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
95 | pub struct ApplicationTy { | 95 | pub struct ApplicationTy { |
96 | pub ctor: TypeCtor, | 96 | pub ctor: TypeCtor, |
97 | pub parameters: Substs, | 97 | pub parameters: Substs, |
@@ -103,7 +103,7 @@ pub struct ApplicationTy { | |||
103 | /// the same thing (but in a different way). | 103 | /// the same thing (but in a different way). |
104 | /// | 104 | /// |
105 | /// This should be cheap to clone. | 105 | /// This should be cheap to clone. |
106 | #[derive(Clone, PartialEq, Eq, Debug)] | 106 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
107 | pub enum Ty { | 107 | pub enum Ty { |
108 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 108 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
109 | /// type like `bool`, a struct, tuple, function pointer, reference or | 109 | /// type like `bool`, a struct, tuple, function pointer, reference or |
@@ -132,7 +132,7 @@ pub enum Ty { | |||
132 | } | 132 | } |
133 | 133 | ||
134 | /// A list of substitutions for generic parameters. | 134 | /// A list of substitutions for generic parameters. |
135 | #[derive(Clone, PartialEq, Eq, Debug)] | 135 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
136 | pub struct Substs(Arc<[Ty]>); | 136 | pub struct Substs(Arc<[Ty]>); |
137 | 137 | ||
138 | impl Substs { | 138 | impl Substs { |
@@ -169,6 +169,21 @@ impl Substs { | |||
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
172 | /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. | ||
173 | /// Name to be bikeshedded: TraitBound? TraitImplements? | ||
174 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
175 | pub struct TraitRef { | ||
176 | /// FIXME name? | ||
177 | trait_: Trait, | ||
178 | substs: Substs, | ||
179 | } | ||
180 | |||
181 | impl TraitRef { | ||
182 | pub fn self_ty(&self) -> &Ty { | ||
183 | &self.substs.0[0] | ||
184 | } | ||
185 | } | ||
186 | |||
172 | /// A function signature as seen by type inference: Several parameter types and | 187 | /// A function signature as seen by type inference: Several parameter types and |
173 | /// one return type. | 188 | /// one return type. |
174 | #[derive(Clone, PartialEq, Eq, Debug)] | 189 | #[derive(Clone, PartialEq, Eq, Debug)] |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 5fd602a9e..573115321 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -821,7 +821,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
821 | } | 821 | } |
822 | Expr::MethodCall { receiver, args, method_name, generic_args } => { | 822 | Expr::MethodCall { receiver, args, method_name, generic_args } => { |
823 | let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); | 823 | let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); |
824 | let resolved = receiver_ty.clone().lookup_method(self.db, method_name); | 824 | let resolved = |
825 | receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); | ||
825 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { | 826 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { |
826 | Some((ty, func)) => { | 827 | Some((ty, func)) => { |
827 | self.write_method_resolution(tgt_expr, func); | 828 | self.write_method_resolution(tgt_expr, func); |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index b1684acf9..3ac8dc46b 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -8,12 +8,12 @@ use rustc_hash::FxHashMap; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | HirDatabase, Module, Crate, Name, Function, Trait, | 10 | HirDatabase, Module, Crate, Name, Function, Trait, |
11 | ids::TraitId, | ||
12 | impl_block::{ImplId, ImplBlock, ImplItem}, | 11 | impl_block::{ImplId, ImplBlock, ImplItem}, |
13 | ty::{Ty, TypeCtor}, | 12 | ty::{Ty, TypeCtor}, |
14 | nameres::CrateModuleId, | 13 | nameres::CrateModuleId, resolve::Resolver, traits::TraitItem |
15 | 14 | ||
16 | }; | 15 | }; |
16 | use super::{ TraitRef, Substs}; | ||
17 | 17 | ||
18 | /// This is used as a key for indexing impls. | 18 | /// This is used as a key for indexing impls. |
19 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 19 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
@@ -38,7 +38,7 @@ pub struct CrateImplBlocks { | |||
38 | /// To make sense of the CrateModuleIds, we need the source root. | 38 | /// To make sense of the CrateModuleIds, we need the source root. |
39 | krate: Crate, | 39 | krate: Crate, |
40 | impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, | 40 | impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, |
41 | impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>, | 41 | impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>, |
42 | } | 42 | } |
43 | 43 | ||
44 | impl CrateImplBlocks { | 44 | impl CrateImplBlocks { |
@@ -56,8 +56,7 @@ impl CrateImplBlocks { | |||
56 | &'a self, | 56 | &'a self, |
57 | tr: &Trait, | 57 | tr: &Trait, |
58 | ) -> impl Iterator<Item = ImplBlock> + 'a { | 58 | ) -> impl Iterator<Item = ImplBlock> + 'a { |
59 | let id = tr.id; | 59 | self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( |
60 | self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map( | ||
61 | move |(module_id, impl_id)| { | 60 | move |(module_id, impl_id)| { |
62 | let module = Module { krate: self.krate, module_id: *module_id }; | 61 | let module = Module { krate: self.krate, module_id: *module_id }; |
63 | ImplBlock::from_id(module, *impl_id) | 62 | ImplBlock::from_id(module, *impl_id) |
@@ -73,18 +72,18 @@ impl CrateImplBlocks { | |||
73 | 72 | ||
74 | let target_ty = impl_block.target_ty(db); | 73 | let target_ty = impl_block.target_ty(db); |
75 | 74 | ||
76 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | ||
77 | self.impls | ||
78 | .entry(target_ty_fp) | ||
79 | .or_insert_with(Vec::new) | ||
80 | .push((module.module_id, impl_id)); | ||
81 | } | ||
82 | |||
83 | if let Some(tr) = impl_block.target_trait(db) { | 75 | if let Some(tr) = impl_block.target_trait(db) { |
84 | self.impls_by_trait | 76 | self.impls_by_trait |
85 | .entry(tr.id) | 77 | .entry(tr) |
86 | .or_insert_with(Vec::new) | 78 | .or_insert_with(Vec::new) |
87 | .push((module.module_id, impl_id)); | 79 | .push((module.module_id, impl_id)); |
80 | } else { | ||
81 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | ||
82 | self.impls | ||
83 | .entry(target_ty_fp) | ||
84 | .or_insert_with(Vec::new) | ||
85 | .push((module.module_id, impl_id)); | ||
86 | } | ||
88 | } | 87 | } |
89 | } | 88 | } |
90 | 89 | ||
@@ -109,6 +108,20 @@ impl CrateImplBlocks { | |||
109 | } | 108 | } |
110 | } | 109 | } |
111 | 110 | ||
111 | /// Rudimentary check whether an impl exists for a given type and trait; this | ||
112 | /// will actually be done by chalk. | ||
113 | pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool { | ||
114 | // FIXME use all trait impls in the whole crate graph | ||
115 | let krate = trait_ref.trait_.module(db).krate(db); | ||
116 | let krate = match krate { | ||
117 | Some(krate) => krate, | ||
118 | None => return false, | ||
119 | }; | ||
120 | let crate_impl_blocks = db.impls_in_crate(krate); | ||
121 | let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_); | ||
122 | impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty()) | ||
123 | } | ||
124 | |||
112 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | 125 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { |
113 | match ty { | 126 | match ty { |
114 | Ty::Apply(a_ty) => match a_ty.ctor { | 127 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -120,20 +133,64 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | |||
120 | } | 133 | } |
121 | 134 | ||
122 | impl Ty { | 135 | impl Ty { |
123 | // FIXME: cache this as a query? | ||
124 | // - if so, what signature? (TyFingerprint, Name)? | ||
125 | // - or maybe cache all names and def_ids of methods per fingerprint? | ||
126 | /// Look up the method with the given name, returning the actual autoderefed | 136 | /// Look up the method with the given name, returning the actual autoderefed |
127 | /// receiver type (but without autoref applied yet). | 137 | /// receiver type (but without autoref applied yet). |
128 | pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { | 138 | pub fn lookup_method( |
129 | self.iterate_methods(db, |ty, f| { | 139 | self, |
140 | db: &impl HirDatabase, | ||
141 | name: &Name, | ||
142 | resolver: &Resolver, | ||
143 | ) -> Option<(Ty, Function)> { | ||
144 | // FIXME: trait methods should be used before autoderefs | ||
145 | let inherent_method = self.clone().iterate_methods(db, |ty, f| { | ||
130 | let sig = f.signature(db); | 146 | let sig = f.signature(db); |
131 | if sig.name() == name && sig.has_self_param() { | 147 | if sig.name() == name && sig.has_self_param() { |
132 | Some((ty.clone(), f)) | 148 | Some((ty.clone(), f)) |
133 | } else { | 149 | } else { |
134 | None | 150 | None |
135 | } | 151 | } |
136 | }) | 152 | }); |
153 | inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver)) | ||
154 | } | ||
155 | |||
156 | fn lookup_trait_method( | ||
157 | self, | ||
158 | db: &impl HirDatabase, | ||
159 | name: &Name, | ||
160 | resolver: &Resolver, | ||
161 | ) -> Option<(Ty, Function)> { | ||
162 | let mut candidates = Vec::new(); | ||
163 | for t in resolver.traits_in_scope() { | ||
164 | let data = t.trait_data(db); | ||
165 | for item in data.items() { | ||
166 | match item { | ||
167 | &TraitItem::Function(m) => { | ||
168 | let sig = m.signature(db); | ||
169 | if sig.name() == name && sig.has_self_param() { | ||
170 | candidates.push((t, m)); | ||
171 | } | ||
172 | } | ||
173 | _ => {} | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | // FIXME: | ||
178 | // - we might not actually be able to determine fully that the type | ||
179 | // implements the trait here; it's enough if we (well, Chalk) determine | ||
180 | // that it's possible. | ||
181 | // - when the trait method is picked, we need to register an | ||
182 | // 'obligation' somewhere so that we later check that it's really | ||
183 | // implemented | ||
184 | // - both points go for additional requirements from where clauses as | ||
185 | // well (in fact, the 'implements' condition could just be considered a | ||
186 | // 'where Self: Trait' clause) | ||
187 | candidates.retain(|(t, _m)| { | ||
188 | let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; | ||
189 | db.implements(trait_ref) | ||
190 | }); | ||
191 | // FIXME if there's multiple candidates here, that's an ambiguity error | ||
192 | let (_chosen_trait, chosen_method) = candidates.first()?; | ||
193 | Some((self.clone(), *chosen_method)) | ||
137 | } | 194 | } |
138 | 195 | ||
139 | // This would be nicer if it just returned an iterator, but that runs into | 196 | // This would be nicer if it just returned an iterator, but that runs into |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3aedba243..655f3c522 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1272,8 +1272,8 @@ fn test() { | |||
1272 | [241; 252) 'Struct::FOO': u32 | 1272 | [241; 252) 'Struct::FOO': u32 |
1273 | [262; 263) 'y': u32 | 1273 | [262; 263) 'y': u32 |
1274 | [266; 275) 'Enum::BAR': u32 | 1274 | [266; 275) 'Enum::BAR': u32 |
1275 | [285; 286) 'z': u32 | 1275 | [285; 286) 'z': {unknown} |
1276 | [289; 302) 'TraitTest::ID': u32"### | 1276 | [289; 302) 'TraitTest::ID': {unknown}"### |
1277 | ); | 1277 | ); |
1278 | } | 1278 | } |
1279 | 1279 | ||
@@ -1918,9 +1918,9 @@ fn test() { | |||
1918 | [110; 114) 'self': &{unknown} | 1918 | [110; 114) 'self': &{unknown} |
1919 | [170; 228) '{ ...i128 }': () | 1919 | [170; 228) '{ ...i128 }': () |
1920 | [176; 178) 'S1': S1 | 1920 | [176; 178) 'S1': S1 |
1921 | [176; 187) 'S1.method()': {unknown} | 1921 | [176; 187) 'S1.method()': u32 |
1922 | [203; 205) 'S2': S2 | 1922 | [203; 205) 'S2': S2 |
1923 | [203; 214) 'S2.method()': {unknown}"### | 1923 | [203; 214) 'S2.method()': i128"### |
1924 | ); | 1924 | ); |
1925 | } | 1925 | } |
1926 | 1926 | ||
@@ -1964,10 +1964,10 @@ mod bar_test { | |||
1964 | [169; 173) 'self': &{unknown} | 1964 | [169; 173) 'self': &{unknown} |
1965 | [300; 337) '{ ... }': () | 1965 | [300; 337) '{ ... }': () |
1966 | [310; 311) 'S': S | 1966 | [310; 311) 'S': S |
1967 | [310; 320) 'S.method()': {unknown} | 1967 | [310; 320) 'S.method()': u32 |
1968 | [416; 454) '{ ... }': () | 1968 | [416; 454) '{ ... }': () |
1969 | [426; 427) 'S': S | 1969 | [426; 427) 'S': S |
1970 | [426; 436) 'S.method()': {unknown}"### | 1970 | [426; 436) 'S.method()': i128"### |
1971 | ); | 1971 | ); |
1972 | } | 1972 | } |
1973 | 1973 | ||