aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2018-12-28 13:34:00 +0000
committerFlorian Diebold <[email protected]>2019-01-04 18:10:47 +0000
commitae9530addc4c5e9bbfd5c0287d3c3adb2de95e40 (patch)
tree42919bcc1ef1d439a04718aefe2fdc2fe3456afd /crates/ra_hir
parent226e31dae94f2c72f5cf650564e521b792793629 (diff)
Add HIR for impl blocks
Since we need to be able to go from def to containing impl block, as well as the other direction, and to find all impls for a certain type, a design similar to the one for modules, where we collect all impls for the whole crate and keep them in an arena, seemed fitting. The ImplBlock type, which provides the public interface, then consists only of an Arc to the arena containing all impls, and the index into it.
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/db.rs8
-rw-r--r--crates/ra_hir/src/function.rs17
-rw-r--r--crates/ra_hir/src/ids.rs13
-rw-r--r--crates/ra_hir/src/impl_block.rs172
-rw-r--r--crates/ra_hir/src/krate.rs2
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/module.rs15
8 files changed, 225 insertions, 5 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 73a4cdc5c..6d5235ba4 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -4,7 +4,7 @@ use ra_syntax::{SyntaxNode, SourceFileNode};
4use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable}; 4use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, Cancelable};
5 5
6use crate::{ 6use crate::{
7 DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, 7 Crate, DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId,
8 SourceFileItems, SourceItemId, 8 SourceFileItems, SourceItemId,
9 query_definitions, 9 query_definitions,
10 FnScopes, 10 FnScopes,
@@ -13,6 +13,7 @@ use crate::{
13 nameres::{ItemMap, InputModuleItems}}, 13 nameres::{ItemMap, InputModuleItems}},
14 ty::{InferenceResult, Ty}, 14 ty::{InferenceResult, Ty},
15 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData},
16 impl_block::CrateImplBlocks,
16}; 17};
17 18
18salsa::query_group! { 19salsa::query_group! {
@@ -87,6 +88,11 @@ pub trait HirDatabase: SyntaxDatabase
87 type ModuleTreeQuery; 88 type ModuleTreeQuery;
88 use fn crate::module::imp::module_tree; 89 use fn crate::module::imp::module_tree;
89 } 90 }
91
92 fn impls_in_crate(krate: Crate) -> Cancelable<Arc<CrateImplBlocks>> {
93 type ImplsInCrateQuery;
94 use fn crate::impl_block::impls_in_crate;
95 }
90} 96}
91 97
92} 98}
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index 5a44132fc..75ef308ae 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -11,11 +11,11 @@ use ra_syntax::{
11 ast::{self, AstNode, DocCommentsOwner, NameOwner}, 11 ast::{self, AstNode, DocCommentsOwner, NameOwner},
12}; 12};
13 13
14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module}; 14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock};
15 15
16pub use self::scope::FnScopes; 16pub use self::scope::FnScopes;
17 17
18#[derive(Debug)] 18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Function { 19pub struct Function {
20 def_id: DefId, 20 def_id: DefId,
21} 21}
@@ -25,6 +25,10 @@ impl Function {
25 Function { def_id } 25 Function { def_id }
26 } 26 }
27 27
28 pub fn def_id(&self) -> DefId {
29 self.def_id
30 }
31
28 pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { 32 pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode {
29 let def_loc = self.def_id.loc(db); 33 let def_loc = self.def_id.loc(db);
30 assert!(def_loc.kind == DefKind::Function); 34 assert!(def_loc.kind == DefKind::Function);
@@ -48,6 +52,15 @@ impl Function {
48 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { 52 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
49 self.def_id.module(db) 53 self.def_id.module(db)
50 } 54 }
55
56 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
57 self.def_id.krate(db)
58 }
59
60 /// The containing impl block, if this is a method.
61 pub fn impl_block(&self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> {
62 self.def_id.impl_block(db)
63 }
51} 64}
52 65
53#[derive(Debug, Clone)] 66#[derive(Debug, Clone)]
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 66adacc7d..c98be66f9 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -2,7 +2,7 @@ use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId};
2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; 2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id}; 3use ra_arena::{Arena, RawId, impl_arena_id};
4 4
5use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum}; 5use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, ImplBlock, Crate};
6 6
7/// hir makes a heavy use of ids: integer (u32) handlers to various things. You 7/// hir makes a heavy use of ids: integer (u32) handlers to various things. You
8/// can think of id as a pointer (but without a lifetime) or a file descriptor 8/// can think of id as a pointer (but without a lifetime) or a file descriptor
@@ -177,6 +177,17 @@ impl DefId {
177 let loc = self.loc(db); 177 let loc = self.loc(db);
178 Module::new(db, loc.source_root_id, loc.module_id) 178 Module::new(db, loc.source_root_id, loc.module_id)
179 } 179 }
180
181 /// Returns the containing crate.
182 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
183 Ok(self.module(db)?.krate(db))
184 }
185
186 /// Returns the containing impl block, if this is an impl item.
187 pub fn impl_block(self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> {
188 let crate_impls = db.impls_in_crate(ctry!(self.krate(db)?))?;
189 Ok(ImplBlock::containing(crate_impls, self))
190 }
180} 191}
181 192
182impl DefLoc { 193impl DefLoc {
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
new file mode 100644
index 000000000..22f0a4461
--- /dev/null
+++ b/crates/ra_hir/src/impl_block.rs
@@ -0,0 +1,172 @@
1use std::sync::Arc;
2use rustc_hash::FxHashMap;
3
4use ra_arena::{Arena, RawId, impl_arena_id};
5use ra_syntax::ast::{self, AstNode};
6use ra_db::{LocationIntener, Cancelable};
7
8use crate::{
9 Crate, DefId, DefLoc, DefKind, SourceItemId, SourceFileItems,
10 Module, Function,
11 db::HirDatabase,
12 type_ref::TypeRef,
13 module::{ModuleSourceNode},
14};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ImplBlock {
18 crate_impl_blocks: Arc<CrateImplBlocks>,
19 impl_id: ImplId,
20}
21
22impl ImplBlock {
23 pub(crate) fn containing(
24 crate_impl_blocks: Arc<CrateImplBlocks>,
25 def_id: DefId,
26 ) -> Option<ImplBlock> {
27 let impl_id = *crate_impl_blocks.impls_by_def.get(&def_id)?;
28 Some(ImplBlock {
29 crate_impl_blocks,
30 impl_id,
31 })
32 }
33
34 fn impl_data(&self) -> &ImplData {
35 &self.crate_impl_blocks.impls[self.impl_id]
36 }
37
38 pub fn target(&self) -> &TypeRef {
39 &self.impl_data().impl_for
40 }
41
42 pub fn items(&self) -> &[ImplItem] {
43 &self.impl_data().items
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct ImplData {
49 impl_for: TypeRef,
50 items: Vec<ImplItem>,
51}
52
53impl ImplData {
54 pub(crate) fn from_ast(
55 db: &impl AsRef<LocationIntener<DefLoc, DefId>>,
56 file_items: &SourceFileItems,
57 module: &Module,
58 node: ast::ImplBlock,
59 ) -> Self {
60 let impl_for = TypeRef::from_ast_opt(node.target_type());
61 let file_id = module.source().file_id();
62 let items = if let Some(item_list) = node.item_list() {
63 item_list
64 .impl_items()
65 .map(|item_node| {
66 let kind = match item_node {
67 ast::ImplItem::FnDef(..) => DefKind::Function,
68 ast::ImplItem::ConstDef(..) => DefKind::Item,
69 ast::ImplItem::TypeDef(..) => DefKind::Item,
70 };
71 let item_id = file_items.id_of_unchecked(item_node.syntax());
72 let def_loc = DefLoc {
73 kind,
74 source_root_id: module.source_root_id,
75 module_id: module.module_id,
76 source_item_id: SourceItemId {
77 file_id,
78 item_id: Some(item_id),
79 },
80 };
81 let def_id = def_loc.id(db);
82 match item_node {
83 ast::ImplItem::FnDef(..) => ImplItem::Method(Function::new(def_id)),
84 ast::ImplItem::ConstDef(..) => ImplItem::Const(def_id),
85 ast::ImplItem::TypeDef(..) => ImplItem::Type(def_id),
86 }
87 })
88 .collect()
89 } else {
90 Vec::new()
91 };
92 ImplData { impl_for, items }
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub enum ImplItem {
98 Method(Function),
99 // these don't have their own types yet
100 Const(DefId),
101 Type(DefId),
102 // Existential
103}
104
105impl ImplItem {
106 pub fn def_id(&self) -> DefId {
107 match self {
108 ImplItem::Method(f) => f.def_id(),
109 ImplItem::Const(def_id) => *def_id,
110 ImplItem::Type(def_id) => *def_id,
111 }
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
116pub struct ImplId(pub RawId);
117impl_arena_id!(ImplId);
118
119/// We have to collect all impl blocks in a crate, to later be able to find
120/// impls for specific types.
121#[derive(Debug, PartialEq, Eq)]
122pub struct CrateImplBlocks {
123 impls: Arena<ImplId, ImplData>,
124 impls_by_def: FxHashMap<DefId, ImplId>,
125}
126
127impl CrateImplBlocks {
128 fn new() -> Self {
129 CrateImplBlocks {
130 impls: Arena::default(),
131 impls_by_def: FxHashMap::default(),
132 }
133 }
134
135 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> {
136 let module_source_node = module.source().resolve(db);
137 let node = match &module_source_node {
138 ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(),
139 ModuleSourceNode::Module(node) => node.borrowed().syntax(),
140 };
141
142 let source_file_items = db.file_items(module.source().file_id());
143
144 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
145 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast);
146 let id = self.impls.alloc(impl_block);
147 for impl_item in &self.impls[id].items {
148 self.impls_by_def.insert(impl_item.def_id(), id);
149 }
150 }
151
152 for (_, child) in module.children() {
153 self.collect(db, child)?;
154 }
155
156 Ok(())
157 }
158}
159
160pub(crate) fn impls_in_crate(
161 db: &impl HirDatabase,
162 krate: Crate,
163) -> Cancelable<Arc<CrateImplBlocks>> {
164 let mut result = CrateImplBlocks::new();
165 let root_module = if let Some(root) = krate.root_module(db)? {
166 root
167 } else {
168 return Ok(Arc::new(result));
169 };
170 result.collect(db, root_module)?;
171 Ok(Arc::new(result))
172}
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
index a0821d15d..5194e280b 100644
--- a/crates/ra_hir/src/krate.rs
+++ b/crates/ra_hir/src/krate.rs
@@ -5,7 +5,7 @@ use crate::{HirDatabase, Module, Name, AsName, HirFileId};
5/// hir::Crate describes a single crate. It's the main inteface with which 5/// hir::Crate describes a single crate. It's the main inteface with which
6/// crate's dependencies interact. Mostly, it should be just a proxy for the 6/// crate's dependencies interact. Mostly, it should be just a proxy for the
7/// root module. 7/// root module.
8#[derive(Debug)] 8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct Crate { 9pub struct Crate {
10 crate_id: CrateId, 10 crate_id: CrateId,
11} 11}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 344b543b6..2abcec441 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -31,6 +31,7 @@ mod function;
31mod adt; 31mod adt;
32mod type_ref; 32mod type_ref;
33mod ty; 33mod ty;
34mod impl_block;
34 35
35use crate::{ 36use crate::{
36 db::HirDatabase, 37 db::HirDatabase,
@@ -48,6 +49,7 @@ pub use self::{
48 function::{Function, FnScopes}, 49 function::{Function, FnScopes},
49 adt::{Struct, Enum}, 50 adt::{Struct, Enum},
50 ty::Ty, 51 ty::Ty,
52 impl_block::{ImplBlock, ImplItem},
51}; 53};
52 54
53pub use self::function::FnSignatureInfo; 55pub use self::function::FnSignatureInfo;
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 89b18194a..ef245ec7a 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -203,6 +203,7 @@ salsa::database_storage! {
203 fn type_for_field() for db::TypeForFieldQuery; 203 fn type_for_field() for db::TypeForFieldQuery;
204 fn struct_data() for db::StructDataQuery; 204 fn struct_data() for db::StructDataQuery;
205 fn enum_data() for db::EnumDataQuery; 205 fn enum_data() for db::EnumDataQuery;
206 fn impls_in_crate() for db::ImplsInCrateQuery;
206 } 207 }
207 } 208 }
208} 209}
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index c70dc54dd..b9821115c 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -71,6 +71,21 @@ impl Module {
71 }) 71 })
72 } 72 }
73 73
74 /// Returns an iterator of all children of this module.
75 pub fn children<'a>(&'a self) -> impl Iterator<Item = (Name, Module)> + 'a {
76 self.module_id
77 .children(&self.tree)
78 .map(move |(name, module_id)| {
79 (
80 name,
81 Module {
82 module_id,
83 ..self.clone()
84 },
85 )
86 })
87 }
88
74 /// Returns the crate this module is part of. 89 /// Returns the crate this module is part of.
75 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { 90 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
76 let root_id = self.module_id.crate_root(&self.tree); 91 let root_id = self.module_id.crate_root(&self.tree);