aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/impl_block.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 14:51:10 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 14:51:10 +0000
commitcf0ce14351af03c620aca784ee2c03aad86b866e (patch)
treebffd84981df9cca1143807796dc6772ddcfe8e0b /crates/ra_hir/src/impl_block.rs
parenteaf553dade9a28b41631387d7c88b09fd0ba64e2 (diff)
parent733383446fc229a35d4432d14c295c5a01e5a87f (diff)
Merge #429
429: Reorganize hir public API in terms of code model r=matklad a=matklad Recently, I've been thinking about introducing "object orient code model" API for rust: a set of APIs with types like `Function`, `Module`, etc, with methods like `get_containing_declaration()`, `get_type()`, etc. Here's how a similar API might look like in .Net land: https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.semanticmodel?view=roslyn-dotnet https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.imethodsymbol?view=roslyn-dotnet The main feature of such API is that it can be powered by different backends. For example, one can imagine a backend based on salsa, and a backend which reads all the data from a specially prepared JSON file. The "OO" bit is interesting mostly in this "can swap implementations via dynamic dispatch" aspect, the actual API could have a more database/ECS flavored feeling. It's not clear at this moment how exactly should we implement such a dynamically (or if we even need dynamism in the first pace) swapable API in Rust, but I'd love to experiment with this a bit. For starters, I propose creating a `code_model_api` which contains various definition types and their public methods (mandatory implemented as one-liners, so that the API has a header-file feel). Specifically, I propose that each type is a wrapper around some integer ID, and that all methods of it accept a `&db` argument. The actual impl goes elsewhere: into the db queries or, absent a better place, into the `code_model_api_impl`. In the first commit, I've moved the simplest type, `Crate`, over to this pattern. I *think* that we, at least initially, will be used types from `code_model_api` *inside* `hir` as well, but this is not required: we might pick a different implementation down the line, while preserving the API. Long term I'd love to replace the `db: &impl HirDatabase` argument by a `mp: &dyn ModelProvider`, implement `ModelProvider` for `T: HirDatabase`, and move `code_model_api` into the separate crate, which does not depend on `hir`. @flodiebold you've recently done some `Def`s work, would do you think of this plan? Could it become a good API in the future, or is it just a useless boilerplate duplicating method signatures between `code_model_api` and `code_model_impl`? Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/impl_block.rs')
-rw-r--r--crates/ra_hir/src/impl_block.rs32
1 files changed, 17 insertions, 15 deletions
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 01afa84c4..7ce8d17e6 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -7,12 +7,14 @@ use ra_db::{LocationIntener, Cancelable, SourceRootId};
7 7
8use crate::{ 8use crate::{
9 DefId, DefLoc, DefKind, SourceItemId, SourceFileItems, 9 DefId, DefLoc, DefKind, SourceItemId, SourceFileItems,
10 Module, Function, 10 Function,
11 db::HirDatabase, 11 db::HirDatabase,
12 type_ref::TypeRef, 12 type_ref::TypeRef,
13 module::{ModuleSourceNode, ModuleId}, 13 module_tree::ModuleId,
14}; 14};
15 15
16use crate::code_model_api::{Module, ModuleSource};
17
16#[derive(Debug, Clone, PartialEq, Eq)] 18#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ImplBlock { 19pub struct ImplBlock {
18 module_impl_blocks: Arc<ModuleImplBlocks>, 20 module_impl_blocks: Arc<ModuleImplBlocks>,
@@ -64,7 +66,7 @@ impl ImplData {
64 ) -> Self { 66 ) -> Self {
65 let target_trait = node.target_type().map(TypeRef::from_ast); 67 let target_trait = node.target_type().map(TypeRef::from_ast);
66 let target_type = TypeRef::from_ast_opt(node.target_type()); 68 let target_type = TypeRef::from_ast_opt(node.target_type());
67 let file_id = module.source().file_id(); 69 let module_loc = module.def_id.loc(db);
68 let items = if let Some(item_list) = node.item_list() { 70 let items = if let Some(item_list) = node.item_list() {
69 item_list 71 item_list
70 .impl_items() 72 .impl_items()
@@ -75,14 +77,14 @@ impl ImplData {
75 ast::ImplItem::TypeDef(..) => DefKind::Item, 77 ast::ImplItem::TypeDef(..) => DefKind::Item,
76 }; 78 };
77 let item_id = file_items.id_of_unchecked(item_node.syntax()); 79 let item_id = file_items.id_of_unchecked(item_node.syntax());
80 let source_item_id = SourceItemId {
81 file_id: module_loc.source_item_id.file_id,
82 item_id: Some(item_id),
83 };
78 let def_loc = DefLoc { 84 let def_loc = DefLoc {
79 kind, 85 kind,
80 source_root_id: module.source_root_id, 86 source_item_id,
81 module_id: module.module_id, 87 ..module_loc
82 source_item_id: SourceItemId {
83 file_id,
84 item_id: Some(item_id),
85 },
86 }; 88 };
87 let def_id = def_loc.id(db); 89 let def_id = def_loc.id(db);
88 match item_node { 90 match item_node {
@@ -148,13 +150,13 @@ impl ModuleImplBlocks {
148 } 150 }
149 151
150 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> { 152 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> {
151 let module_source_node = module.source().resolve(db); 153 let (file_id, module_source) = module.defenition_source(db)?;
152 let node = match &module_source_node { 154 let node = match &module_source {
153 ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(), 155 ModuleSource::SourceFile(node) => node.borrowed().syntax(),
154 ModuleSourceNode::Module(node) => node.borrowed().syntax(), 156 ModuleSource::Module(node) => node.borrowed().syntax(),
155 }; 157 };
156 158
157 let source_file_items = db.file_items(module.source().file_id()); 159 let source_file_items = db.file_items(file_id.into());
158 160
159 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { 161 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
160 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast); 162 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast);
@@ -174,7 +176,7 @@ pub(crate) fn impls_in_module(
174 module_id: ModuleId, 176 module_id: ModuleId,
175) -> Cancelable<Arc<ModuleImplBlocks>> { 177) -> Cancelable<Arc<ModuleImplBlocks>> {
176 let mut result = ModuleImplBlocks::new(); 178 let mut result = ModuleImplBlocks::new();
177 let module = Module::new(db, source_root_id, module_id)?; 179 let module = Module::from_module_id(db, source_root_id, module_id)?;
178 result.collect(db, module)?; 180 result.collect(db, module)?;
179 Ok(Arc::new(result)) 181 Ok(Arc::new(result))
180} 182}