aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--crates/ra_analysis/src/db.rs1
-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
-rw-r--r--crates/ra_syntax/src/ast/generated.rs40
-rw-r--r--crates/ra_syntax/src/grammar.ron6
11 files changed, 269 insertions, 8 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index d7740f0c4..d7e51a597 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -105,6 +105,7 @@ salsa::database_storage! {
105 fn type_for_field() for hir::db::TypeForFieldQuery; 105 fn type_for_field() for hir::db::TypeForFieldQuery;
106 fn struct_data() for hir::db::StructDataQuery; 106 fn struct_data() for hir::db::StructDataQuery;
107 fn enum_data() for hir::db::EnumDataQuery; 107 fn enum_data() for hir::db::EnumDataQuery;
108 fn impls_in_crate() for hir::db::ImplsInCrateQuery;
108 } 109 }
109 } 110 }
110} 111}
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);
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index c1c63f555..91de17ddf 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1442,7 +1442,39 @@ impl<R: TreeRoot<RaTypes>> ImplBlockNode<R> {
1442} 1442}
1443 1443
1444 1444
1445impl<'a> ImplBlock<'a> {} 1445impl<'a> ImplBlock<'a> {
1446 pub fn item_list(self) -> Option<ItemList<'a>> {
1447 super::child_opt(self)
1448 }
1449}
1450
1451// ImplItem
1452#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1453pub enum ImplItem<'a> {
1454 FnDef(FnDef<'a>),
1455 TypeDef(TypeDef<'a>),
1456 ConstDef(ConstDef<'a>),
1457}
1458
1459impl<'a> AstNode<'a> for ImplItem<'a> {
1460 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
1461 match syntax.kind() {
1462 FN_DEF => Some(ImplItem::FnDef(FnDef { syntax })),
1463 TYPE_DEF => Some(ImplItem::TypeDef(TypeDef { syntax })),
1464 CONST_DEF => Some(ImplItem::ConstDef(ConstDef { syntax })),
1465 _ => None,
1466 }
1467 }
1468 fn syntax(self) -> SyntaxNodeRef<'a> {
1469 match self {
1470 ImplItem::FnDef(inner) => inner.syntax(),
1471 ImplItem::TypeDef(inner) => inner.syntax(),
1472 ImplItem::ConstDef(inner) => inner.syntax(),
1473 }
1474 }
1475}
1476
1477impl<'a> ImplItem<'a> {}
1446 1478
1447// ImplTraitType 1479// ImplTraitType
1448#[derive(Debug, Clone, Copy,)] 1480#[derive(Debug, Clone, Copy,)]
@@ -1555,7 +1587,11 @@ impl<R: TreeRoot<RaTypes>> ItemListNode<R> {
1555 1587
1556impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {} 1588impl<'a> ast::FnDefOwner<'a> for ItemList<'a> {}
1557impl<'a> ast::ModuleItemOwner<'a> for ItemList<'a> {} 1589impl<'a> ast::ModuleItemOwner<'a> for ItemList<'a> {}
1558impl<'a> ItemList<'a> {} 1590impl<'a> ItemList<'a> {
1591 pub fn impl_items(self) -> impl Iterator<Item = ImplItem<'a>> + 'a {
1592 super::children(self)
1593 }
1594}
1559 1595
1560// Label 1596// Label
1561#[derive(Debug, Clone, Copy,)] 1597#[derive(Debug, Clone, Copy,)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 9a4a96fac..688a4af1e 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -284,6 +284,7 @@ Grammar(
284 options: [ "ItemList" ] 284 options: [ "ItemList" ]
285 ), 285 ),
286 "ItemList": ( 286 "ItemList": (
287 collections: [["impl_items", "ImplItem"]],
287 traits: [ "FnDefOwner", "ModuleItemOwner" ], 288 traits: [ "FnDefOwner", "ModuleItemOwner" ],
288 ), 289 ),
289 "ConstDef": ( traits: [ 290 "ConstDef": ( traits: [
@@ -307,7 +308,7 @@ Grammar(
307 "AttrsOwner", 308 "AttrsOwner",
308 "DocCommentsOwner" 309 "DocCommentsOwner"
309 ] ), 310 ] ),
310 "ImplBlock": (collections: []), 311 "ImplBlock": (options: ["ItemList"]),
311 312
312 "ParenType": (options: ["TypeRef"]), 313 "ParenType": (options: ["TypeRef"]),
313 "TupleType": ( collections: [["fields", "TypeRef"]] ), 314 "TupleType": ( collections: [["fields", "TypeRef"]] ),
@@ -351,6 +352,9 @@ Grammar(
351 enum: ["StructDef", "EnumDef", "FnDef", "TraitDef", "TypeDef", "ImplBlock", 352 enum: ["StructDef", "EnumDef", "FnDef", "TraitDef", "TypeDef", "ImplBlock",
352 "UseItem", "ExternCrateItem", "ConstDef", "StaticDef", "Module" ] 353 "UseItem", "ExternCrateItem", "ConstDef", "StaticDef", "Module" ]
353 ), 354 ),
355 "ImplItem": (
356 enum: ["FnDef", "TypeDef", "ConstDef"]
357 ),
354 358
355 "TupleExpr": (), 359 "TupleExpr": (),
356 "ArrayExpr": (), 360 "ArrayExpr": (),