aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model_api.rs23
-rw-r--r--crates/ra_hir/src/code_model_impl/krate.rs4
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs104
-rw-r--r--crates/ra_hir/src/db.rs44
-rw-r--r--crates/ra_hir/src/ids.rs64
-rw-r--r--crates/ra_hir/src/impl_block.rs5
-rw-r--r--crates/ra_hir/src/lib.rs7
-rw-r--r--crates/ra_hir/src/macros.rs135
-rw-r--r--crates/ra_hir/src/marks.rs3
-rw-r--r--crates/ra_hir/src/module_tree.rs331
-rw-r--r--crates/ra_hir/src/name.rs3
-rw-r--r--crates/ra_hir/src/nameres.rs743
-rw-r--r--crates/ra_hir/src/nameres/collector.rs564
-rw-r--r--crates/ra_hir/src/nameres/lower.rs222
-rw-r--r--crates/ra_hir/src/nameres/per_ns.rs78
-rw-r--r--crates/ra_hir/src/nameres/raw.rs322
-rw-r--r--crates/ra_hir/src/nameres/tests.rs784
-rw-r--r--crates/ra_hir/src/nameres/tests/globs.rs118
-rw-r--r--crates/ra_hir/src/nameres/tests/incremental.rs123
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs94
-rw-r--r--crates/ra_hir/src/resolve.rs36
-rw-r--r--crates/ra_hir/src/source_binder.rs46
-rw-r--r--crates/ra_hir/src/ty.rs173
-rw-r--r--crates/ra_hir/src/ty/display.rs56
-rw-r--r--crates/ra_hir/src/ty/infer.rs31
-rw-r--r--crates/ra_hir/src/ty/lower.rs99
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs10
-rw-r--r--crates/ra_hir/src/ty/primitive.rs64
-rw-r--r--crates/ra_hir/src/ty/tests.rs5
29 files changed, 2281 insertions, 2010 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index dd7eeebd0..b00481cd5 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -8,13 +8,12 @@ use crate::{
8 Name, ScopesWithSourceMap, Ty, HirFileId, 8 Name, ScopesWithSourceMap, Ty, HirFileId,
9 HirDatabase, PersistentHirDatabase, 9 HirDatabase, PersistentHirDatabase,
10 type_ref::TypeRef, 10 type_ref::TypeRef,
11 nameres::{ModuleScope, Namespace, lower::ImportId}, 11 nameres::{ModuleScope, Namespace, ImportId, CrateModuleId},
12 expr::{Body, BodySourceMap}, 12 expr::{Body, BodySourceMap},
13 ty::InferenceResult, 13 ty::InferenceResult,
14 adt::{EnumVariantId, StructFieldId, VariantDef}, 14 adt::{EnumVariantId, StructFieldId, VariantDef},
15 generics::GenericParams, 15 generics::GenericParams,
16 docs::{Documentation, Docs, docs_from_ast}, 16 docs::{Documentation, Docs, docs_from_ast},
17 module_tree::ModuleId,
18 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, 17 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId},
19 impl_block::ImplBlock, 18 impl_block::ImplBlock,
20 resolve::Resolver, 19 resolve::Resolver,
@@ -65,11 +64,11 @@ impl Crate {
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub struct Module { 65pub struct Module {
67 pub(crate) krate: Crate, 66 pub(crate) krate: Crate,
68 pub(crate) module_id: ModuleId, 67 pub(crate) module_id: CrateModuleId,
69} 68}
70 69
71/// The defs which can be visible in the module. 70/// The defs which can be visible in the module.
72#[derive(Debug, Clone, Copy, PartialEq, Eq)] 71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
73pub enum ModuleDef { 72pub enum ModuleDef {
74 Module(Module), 73 Module(Module),
75 Function(Function), 74 Function(Function),
@@ -173,7 +172,7 @@ impl Module {
173 172
174 /// Returns a `ModuleScope`: a set of items, visible in this module. 173 /// Returns a `ModuleScope`: a set of items, visible in this module.
175 pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope { 174 pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope {
176 db.item_map(self.krate)[self.module_id].clone() 175 db.crate_def_map(self.krate)[self.module_id].scope.clone()
177 } 176 }
178 177
179 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { 178 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
@@ -181,16 +180,16 @@ impl Module {
181 } 180 }
182 181
183 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 182 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
184 let item_map = db.item_map(self.krate); 183 let def_map = db.crate_def_map(self.krate);
185 Resolver::default().push_module_scope(item_map, *self) 184 Resolver::default().push_module_scope(def_map, self.module_id)
186 } 185 }
187 186
188 pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> { 187 pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> {
189 let lowered_module = db.lower_module(self); 188 let def_map = db.crate_def_map(self.krate);
190 lowered_module 189 def_map[self.module_id]
191 .declarations 190 .scope
192 .values() 191 .entries()
193 .cloned() 192 .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None })
194 .flat_map(|per_ns| { 193 .flat_map(|per_ns| {
195 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter()) 194 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
196 }) 195 })
diff --git a/crates/ra_hir/src/code_model_impl/krate.rs b/crates/ra_hir/src/code_model_impl/krate.rs
index 161ae6e18..cc87c6f14 100644
--- a/crates/ra_hir/src/code_model_impl/krate.rs
+++ b/crates/ra_hir/src/code_model_impl/krate.rs
@@ -18,9 +18,7 @@ impl Crate {
18 .collect() 18 .collect()
19 } 19 }
20 pub(crate) fn root_module_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 20 pub(crate) fn root_module_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
21 let module_tree = db.module_tree(*self); 21 let module_id = db.crate_def_map(*self).root();
22 let module_id = module_tree.modules().next()?;
23
24 let module = Module { krate: *self, module_id }; 22 let module = Module { krate: *self, module_id };
25 Some(module) 23 Some(module)
26 } 24 }
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 437f96942..f7d15c55e 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -1,33 +1,61 @@
1use ra_syntax::{ast, SyntaxNode, TreeArc}; 1use ra_db::FileId;
2use ra_syntax::{ast, SyntaxNode, TreeArc, AstNode};
2 3
3use crate::{ 4use crate::{
4 Module, ModuleSource, Problem, 5 Module, ModuleSource, Problem, Name,
5 Name, 6 nameres::{CrateModuleId, ImportId},
6 module_tree::ModuleId,
7 nameres::lower::ImportId,
8 HirDatabase, PersistentHirDatabase, 7 HirDatabase, PersistentHirDatabase,
9 HirFileId 8 HirFileId, SourceItemId,
10}; 9};
11 10
11impl ModuleSource {
12 pub(crate) fn new(
13 db: &impl PersistentHirDatabase,
14 file_id: Option<FileId>,
15 decl_id: Option<SourceItemId>,
16 ) -> ModuleSource {
17 match (file_id, decl_id) {
18 (Some(file_id), _) => {
19 let source_file = db.parse(file_id);
20 ModuleSource::SourceFile(source_file)
21 }
22 (None, Some(item_id)) => {
23 let module = db.file_item(item_id);
24 let module = ast::Module::cast(&*module).unwrap();
25 assert!(module.item_list().is_some(), "expected inline module");
26 ModuleSource::Module(module.to_owned())
27 }
28 (None, None) => panic!(),
29 }
30 }
31}
32
12impl Module { 33impl Module {
13 fn with_module_id(&self, module_id: ModuleId) -> Module { 34 fn with_module_id(&self, module_id: CrateModuleId) -> Module {
14 Module { module_id, krate: self.krate } 35 Module { module_id, krate: self.krate }
15 } 36 }
16 37
17 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> { 38 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> {
18 let module_tree = db.module_tree(self.krate); 39 let def_map = db.crate_def_map(self.krate);
19 let link = self.module_id.parent_link(&module_tree)?; 40 let parent = def_map[self.module_id].parent?;
20 Some(link.name(&module_tree).clone()) 41 def_map[parent].children.iter().find_map(|(name, module_id)| {
42 if *module_id == self.module_id {
43 Some(name.clone())
44 } else {
45 None
46 }
47 })
21 } 48 }
22 49
23 pub(crate) fn definition_source_impl( 50 pub(crate) fn definition_source_impl(
24 &self, 51 &self,
25 db: &impl PersistentHirDatabase, 52 db: &impl PersistentHirDatabase,
26 ) -> (HirFileId, ModuleSource) { 53 ) -> (HirFileId, ModuleSource) {
27 let module_tree = db.module_tree(self.krate); 54 let def_map = db.crate_def_map(self.krate);
28 let file_id = self.module_id.file_id(&module_tree); 55 let decl_id = def_map[self.module_id].declaration;
29 let decl_id = self.module_id.decl_id(&module_tree); 56 let file_id = def_map[self.module_id].definition;
30 let module_source = ModuleSource::new(db, file_id, decl_id); 57 let module_source = ModuleSource::new(db, file_id, decl_id);
58 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id);
31 (file_id, module_source) 59 (file_id, module_source)
32 } 60 }
33 61
@@ -35,11 +63,11 @@ impl Module {
35 &self, 63 &self,
36 db: &impl HirDatabase, 64 db: &impl HirDatabase,
37 ) -> Option<(HirFileId, TreeArc<ast::Module>)> { 65 ) -> Option<(HirFileId, TreeArc<ast::Module>)> {
38 let module_tree = db.module_tree(self.krate); 66 let def_map = db.crate_def_map(self.krate);
39 let link = self.module_id.parent_link(&module_tree)?; 67 let decl = def_map[self.module_id].declaration?;
40 let file_id = link.owner(&module_tree).file_id(&module_tree); 68 let syntax_node = db.file_item(decl);
41 let src = link.source(&module_tree, db); 69 let ast = ast::Module::cast(&syntax_node).unwrap().to_owned();
42 Some((file_id, src)) 70 Some((decl.file_id, ast))
43 } 71 }
44 72
45 pub(crate) fn import_source_impl( 73 pub(crate) fn import_source_impl(
@@ -47,22 +75,21 @@ impl Module {
47 db: &impl HirDatabase, 75 db: &impl HirDatabase,
48 import: ImportId, 76 import: ImportId,
49 ) -> TreeArc<ast::PathSegment> { 77 ) -> TreeArc<ast::PathSegment> {
50 let (_, source_map) = db.lower_module_with_source_map(*self); 78 let (file_id, source) = self.definition_source(db);
51 let (_, source) = self.definition_source(db); 79 let (_, source_map) = db.raw_items_with_source_map(file_id.original_file(db));
52 source_map.get(&source, import) 80 source_map.get(&source, import)
53 } 81 }
54 82
55 pub(crate) fn crate_root_impl(&self, db: &impl PersistentHirDatabase) -> Module { 83 pub(crate) fn crate_root_impl(&self, db: &impl PersistentHirDatabase) -> Module {
56 let module_tree = db.module_tree(self.krate); 84 let def_map = db.crate_def_map(self.krate);
57 let module_id = self.module_id.crate_root(&module_tree); 85 self.with_module_id(def_map.root())
58 self.with_module_id(module_id)
59 } 86 }
60 87
61 /// Finds a child module with the specified name. 88 /// Finds a child module with the specified name.
62 pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> { 89 pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> {
63 let module_tree = db.module_tree(self.krate); 90 let def_map = db.crate_def_map(self.krate);
64 let child_id = self.module_id.child(&module_tree, name)?; 91 let child_id = def_map[self.module_id].children.get(name)?;
65 Some(self.with_module_id(child_id)) 92 Some(self.with_module_id(*child_id))
66 } 93 }
67 94
68 /// Iterates over all child modules. 95 /// Iterates over all child modules.
@@ -70,18 +97,18 @@ impl Module {
70 &self, 97 &self,
71 db: &impl PersistentHirDatabase, 98 db: &impl PersistentHirDatabase,
72 ) -> impl Iterator<Item = Module> { 99 ) -> impl Iterator<Item = Module> {
73 let module_tree = db.module_tree(self.krate); 100 let def_map = db.crate_def_map(self.krate);
74 let children = self 101 let children = def_map[self.module_id]
75 .module_id 102 .children
76 .children(&module_tree) 103 .iter()
77 .map(|(_, module_id)| self.with_module_id(module_id)) 104 .map(|(_, module_id)| self.with_module_id(*module_id))
78 .collect::<Vec<_>>(); 105 .collect::<Vec<_>>();
79 children.into_iter() 106 children.into_iter()
80 } 107 }
81 108
82 pub(crate) fn parent_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 109 pub(crate) fn parent_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
83 let module_tree = db.module_tree(self.krate); 110 let def_map = db.crate_def_map(self.krate);
84 let parent_id = self.module_id.parent(&module_tree)?; 111 let parent_id = def_map[self.module_id].parent?;
85 Some(self.with_module_id(parent_id)) 112 Some(self.with_module_id(parent_id))
86 } 113 }
87 114
@@ -89,7 +116,14 @@ impl Module {
89 &self, 116 &self,
90 db: &impl HirDatabase, 117 db: &impl HirDatabase,
91 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> { 118 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
92 let module_tree = db.module_tree(self.krate); 119 let def_map = db.crate_def_map(self.krate);
93 self.module_id.problems(&module_tree, db) 120 let (my_file_id, _) = self.definition_source(db);
121 // FIXME: not entirely corret filterint by module
122 def_map
123 .problems()
124 .iter()
125 .filter(|(source_item_id, _problem)| my_file_id == source_item_id.file_id)
126 .map(|(source_item_id, problem)| (db.file_item(*source_item_id), problem.clone()))
127 .collect()
94 } 128 }
95} 129}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 21d22aa7f..c7bad7e2b 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,23 +1,18 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SourceDatabase, salsa}; 4use ra_db::{SourceDatabase, salsa, FileId};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, HirFileId, 7 HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner,
8 SourceFileItems, SourceItemId, Crate, Module, HirInterner,
9 Function, FnSignature, ExprScopes, TypeAlias, 8 Function, FnSignature, ExprScopes, TypeAlias,
10 Struct, Enum, StructField, 9 Struct, Enum, StructField,
11 Const, ConstSignature, Static, 10 Const, ConstSignature, Static,
12 macros::MacroExpansion, 11 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap},
13 module_tree::ModuleTree, 12 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig},
14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
15 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
16 adt::{StructData, EnumData}, 13 adt::{StructData, EnumData},
17 impl_block::{ModuleImplBlocks, ImplSourceMap}, 14 impl_block::{ModuleImplBlocks, ImplSourceMap},
18 generics::{GenericParams, GenericDef}, 15 generics::{GenericParams, GenericDef},
19 ids::SourceFileItemId,
20 nameres::Namespace,
21 type_ref::TypeRef, 16 type_ref::TypeRef,
22}; 17};
23 18
@@ -26,9 +21,6 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
26 #[salsa::invoke(HirFileId::hir_parse)] 21 #[salsa::invoke(HirFileId::hir_parse)]
27 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; 22 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
28 23
29 #[salsa::invoke(crate::macros::expand_macro_invocation)]
30 fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;
31
32 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 24 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
33 fn struct_data(&self, s: Struct) -> Arc<StructData>; 25 fn struct_data(&self, s: Struct) -> Arc<StructData>;
34 26
@@ -41,27 +33,14 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
41 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] 33 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)]
42 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; 34 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;
43 35
44 #[salsa::invoke(crate::module_tree::Submodule::submodules_query)] 36 #[salsa::invoke(RawItems::raw_items_query)]
45 fn submodules( 37 fn raw_items(&self, file_id: FileId) -> Arc<RawItems>;
46 &self,
47 file_id: HirFileId,
48 delc_id: Option<SourceFileItemId>,
49 ) -> Arc<Vec<crate::module_tree::Submodule>>;
50 38
51 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_with_source_map_query)] 39 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
52 fn lower_module_with_source_map( 40 fn raw_items_with_source_map(&self, file_id: FileId) -> (Arc<RawItems>, Arc<ImportSourceMap>);
53 &self,
54 module: Module,
55 ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>);
56 41
57 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] 42 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
58 fn lower_module(&self, module: Module) -> Arc<LoweredModule>; 43 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
59
60 #[salsa::invoke(crate::nameres::ItemMap::item_map_query)]
61 fn item_map(&self, krate: Crate) -> Arc<ItemMap>;
62
63 #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)]
64 fn module_tree(&self, krate: Crate) -> Arc<ModuleTree>;
65 44
66 #[salsa::invoke(crate::impl_block::impls_in_module)] 45 #[salsa::invoke(crate::impl_block::impls_in_module)]
67 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; 46 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>;
@@ -105,6 +84,9 @@ pub trait HirDatabase: PersistentHirDatabase {
105 #[salsa::invoke(crate::ty::type_for_field)] 84 #[salsa::invoke(crate::ty::type_for_field)]
106 fn type_for_field(&self, field: StructField) -> Ty; 85 fn type_for_field(&self, field: StructField) -> Ty;
107 86
87 #[salsa::invoke(crate::ty::callable_item_sig)]
88 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
89
108 #[salsa::invoke(crate::expr::body_with_source_map_query)] 90 #[salsa::invoke(crate::expr::body_with_source_map_query)]
109 fn body_with_source_map( 91 fn body_with_source_map(
110 &self, 92 &self,
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 5b00330c6..9596488d3 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -83,30 +83,37 @@ impl HirFileId {
83 } 83 }
84 } 84 }
85 85
86 pub(crate) fn as_macro_call_id(self) -> Option<MacroCallId> {
87 match self.0 {
88 HirFileIdRepr::Macro(it) => Some(it),
89 _ => None,
90 }
91 }
92
93 pub(crate) fn hir_parse( 86 pub(crate) fn hir_parse(
94 db: &impl PersistentHirDatabase, 87 db: &impl PersistentHirDatabase,
95 file_id: HirFileId, 88 file_id: HirFileId,
96 ) -> TreeArc<SourceFile> { 89 ) -> TreeArc<SourceFile> {
97 match file_id.0 { 90 match file_id.0 {
98 HirFileIdRepr::File(file_id) => db.parse(file_id), 91 HirFileIdRepr::File(file_id) => db.parse(file_id),
99 HirFileIdRepr::Macro(m) => { 92 HirFileIdRepr::Macro(macro_call_id) => {
100 if let Some(exp) = db.expand_macro_invocation(m) {
101 return exp.file();
102 }
103 // returning an empty string looks fishy... 93 // returning an empty string looks fishy...
104 SourceFile::parse("") 94 parse_macro(db, macro_call_id).unwrap_or_else(|| SourceFile::parse(""))
105 } 95 }
106 } 96 }
107 } 97 }
108} 98}
109 99
100fn parse_macro(
101 db: &impl PersistentHirDatabase,
102 macro_call_id: MacroCallId,
103) -> Option<TreeArc<SourceFile>> {
104 let loc = macro_call_id.loc(db);
105 let syntax = db.file_item(loc.source_item_id);
106 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
107 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?;
108
109 let def_map = db.crate_def_map(loc.module.krate);
110 let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?;
111 let def_map = db.crate_def_map(krate);
112 let macro_rules = &def_map[macro_id];
113 let tt = macro_rules.expand(&macro_arg).ok()?;
114 Some(mbe::token_tree_to_ast_item_list(&tt))
115}
116
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111enum HirFileIdRepr { 118enum HirFileIdRepr {
112 File(FileId), 119 File(FileId),
@@ -200,8 +207,14 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
200 fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>; 207 fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>;
201 fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self { 208 fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self {
202 let items = ctx.db.file_items(ctx.file_id); 209 let items = ctx.db.file_items(ctx.file_id);
203 let raw = 210 let item_id = items.id_of(ctx.file_id, ast.syntax());
204 SourceItemId { file_id: ctx.file_id, item_id: items.id_of(ctx.file_id, ast.syntax()) }; 211 Self::from_source_item_id_unchecked(ctx, item_id)
212 }
213 fn from_source_item_id_unchecked(
214 ctx: LocationCtx<&impl PersistentHirDatabase>,
215 item_id: SourceFileItemId,
216 ) -> Self {
217 let raw = SourceItemId { file_id: ctx.file_id, item_id };
205 let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData }; 218 let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData };
206 219
207 Self::interner(ctx.db.as_ref()).loc2id(&loc) 220 Self::interner(ctx.db.as_ref()).loc2id(&loc)
@@ -290,6 +303,12 @@ impl AstItemDef<ast::TypeAliasDef> for TypeId {
290pub struct SourceFileItemId(RawId); 303pub struct SourceFileItemId(RawId);
291impl_arena_id!(SourceFileItemId); 304impl_arena_id!(SourceFileItemId);
292 305
306impl SourceFileItemId {
307 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
308 SourceItemId { file_id, item_id: self }
309 }
310}
311
293#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 312#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
294pub struct SourceItemId { 313pub struct SourceItemId {
295 pub(crate) file_id: HirFileId, 314 pub(crate) file_id: HirFileId,
@@ -309,9 +328,7 @@ impl SourceFileItems {
309 file_id: HirFileId, 328 file_id: HirFileId,
310 ) -> Arc<SourceFileItems> { 329 ) -> Arc<SourceFileItems> {
311 let source_file = db.hir_parse(file_id); 330 let source_file = db.hir_parse(file_id);
312 let mut res = SourceFileItems { file_id, arena: Arena::default() }; 331 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
313 res.init(&source_file);
314 Arc::new(res)
315 } 332 }
316 333
317 pub(crate) fn file_item_query( 334 pub(crate) fn file_item_query(
@@ -324,18 +341,23 @@ impl SourceFileItems {
324 .to_owned() 341 .to_owned()
325 } 342 }
326 343
327 fn init(&mut self, source_file: &SourceFile) { 344 pub(crate) fn from_source_file(
345 source_file: &SourceFile,
346 file_id: HirFileId,
347 ) -> SourceFileItems {
348 let mut res = SourceFileItems { file_id, arena: Arena::default() };
328 // By walking the tree in bread-first order we make sure that parents 349 // By walking the tree in bread-first order we make sure that parents
329 // get lower ids then children. That is, adding a new child does not 350 // get lower ids then children. That is, adding a new child does not
330 // change parent's id. This means that, say, adding a new function to a 351 // change parent's id. This means that, say, adding a new function to a
331 // trait does not change ids of top-level items, which helps caching. 352 // trait does not change ids of top-level items, which helps caching.
332 bfs(source_file.syntax(), |it| { 353 bfs(source_file.syntax(), |it| {
333 if let Some(module_item) = ast::ModuleItem::cast(it) { 354 if let Some(module_item) = ast::ModuleItem::cast(it) {
334 self.alloc(module_item.syntax()); 355 res.alloc(module_item.syntax());
335 } else if let Some(macro_call) = ast::MacroCall::cast(it) { 356 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
336 self.alloc(macro_call.syntax()); 357 res.alloc(macro_call.syntax());
337 } 358 }
338 }) 359 });
360 res
339 } 361 }
340 362
341 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { 363 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index eb2d4ed8d..8807a4b56 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -4,7 +4,8 @@ use rustc_hash::FxHashMap;
4use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 4use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
5use ra_syntax::{ 5use ra_syntax::{
6 AstPtr, SourceFile, TreeArc, 6 AstPtr, SourceFile, TreeArc,
7ast::{self, AstNode}}; 7 ast::{self, AstNode}
8};
8 9
9use crate::{ 10use crate::{
10 Const, TypeAlias, Function, HirFileId, 11 Const, TypeAlias, Function, HirFileId,
@@ -13,7 +14,7 @@ use crate::{
13 type_ref::TypeRef, 14 type_ref::TypeRef,
14 ids::LocationCtx, 15 ids::LocationCtx,
15 resolve::Resolver, 16 resolve::Resolver,
16 ty::Ty, generics::GenericParams 17 ty::Ty, generics::GenericParams,
17}; 18};
18 19
19use crate::code_model_api::{Module, ModuleSource}; 20use crate::code_model_api::{Module, ModuleSource};
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ac5f33079..75c977d32 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -24,9 +24,7 @@ mod path;
24pub mod source_binder; 24pub mod source_binder;
25 25
26mod ids; 26mod ids;
27mod macros;
28mod name; 27mod name;
29mod module_tree;
30mod nameres; 28mod nameres;
31mod adt; 29mod adt;
32mod type_alias; 30mod type_alias;
@@ -54,9 +52,8 @@ pub use self::{
54 path::{Path, PathKind}, 52 path::{Path, PathKind},
55 name::Name, 53 name::Name,
56 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, 54 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
57 macros::{MacroDef, MacroInput, MacroExpansion}, 55 nameres::{PerNs, Namespace},
58 nameres::{ItemMap, PerNs, Namespace}, 56 ty::{Ty, Substs, display::HirDisplay},
59 ty::{Ty, Substs},
60 impl_block::{ImplBlock, ImplItem}, 57 impl_block::{ImplBlock, ImplItem},
61 docs::{Docs, Documentation}, 58 docs::{Docs, Documentation},
62 adt::AdtDef, 59 adt::AdtDef,
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
deleted file mode 100644
index 45128c7df..000000000
--- a/crates/ra_hir/src/macros.rs
+++ /dev/null
@@ -1,135 +0,0 @@
1/// Machinery for macro expansion.
2///
3/// One of the more complicated things about macros is managing the source code
4/// that is produced after expansion. See `HirFileId` and `MacroCallId` for how
5/// do we do that.
6///
7/// When the file-management question is resolved, all that is left is a
8/// token-tree-to-token-tree transformation plus hygiene. We don't have either of
9/// those yet, so all macros are string based at the moment!
10use std::sync::Arc;
11
12use ra_syntax::{
13 TextRange, TextUnit, SourceFile, AstNode, SyntaxNode, TreeArc, SyntaxNodePtr,
14 ast,
15};
16
17use crate::{MacroCallId, PersistentHirDatabase};
18
19// Hard-coded defs for now :-(
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum MacroDef {
22 Vec,
23}
24
25impl MacroDef {
26 /// Expands macro call, returning the expansion and offset to be used to
27 /// convert ranges between expansion and original source.
28 pub fn ast_expand(macro_call: &ast::MacroCall) -> Option<(TextUnit, MacroExpansion)> {
29 let (def, input) = MacroDef::from_call(macro_call)?;
30 let exp = def.expand(input)?;
31 let off = macro_call.token_tree()?.syntax().range().start();
32 Some((off, exp))
33 }
34
35 fn from_call(macro_call: &ast::MacroCall) -> Option<(MacroDef, MacroInput)> {
36 let def = {
37 let path = macro_call.path()?;
38 let name_ref = path.segment()?.name_ref()?;
39 if name_ref.text() == "vec" {
40 MacroDef::Vec
41 } else {
42 return None;
43 }
44 };
45
46 let input = {
47 let arg = macro_call.token_tree()?.syntax();
48 MacroInput { text: arg.text().to_string() }
49 };
50 Some((def, input))
51 }
52
53 fn expand(self, input: MacroInput) -> Option<MacroExpansion> {
54 match self {
55 MacroDef::Vec => self.expand_vec(input),
56 }
57 }
58 fn expand_vec(self, input: MacroInput) -> Option<MacroExpansion> {
59 let text = format!(r"fn dummy() {{ {}; }}", input.text);
60 let file = SourceFile::parse(&text);
61 let array_expr = file.syntax().descendants().find_map(ast::ArrayExpr::cast)?;
62 let ptr = SyntaxNodePtr::new(array_expr.syntax());
63 let src_range = TextRange::offset_len(0.into(), TextUnit::of_str(&input.text));
64 let ranges_map = vec![(src_range, array_expr.syntax().range())];
65 let res = MacroExpansion { text, ranges_map, ptr };
66 Some(res)
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct MacroInput {
72 // Should be token trees
73 pub text: String,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct MacroExpansion {
78 /// The result of macro expansion. Should be token tree as well.
79 text: String,
80 /// Correspondence between ranges in the original source code and ranges in
81 /// the macro.
82 ranges_map: Vec<(TextRange, TextRange)>,
83 /// Implementation detail: internally, a macro is expanded to the whole file,
84 /// even if it is an expression. This `ptr` selects the actual expansion from
85 /// the expanded file.
86 ptr: SyntaxNodePtr,
87}
88
89impl MacroExpansion {
90 // FIXME: does not really make sense, macro expansion is not necessary a
91 // whole file. See `MacroExpansion::ptr` as well.
92 pub(crate) fn file(&self) -> TreeArc<SourceFile> {
93 SourceFile::parse(&self.text)
94 }
95
96 pub fn syntax(&self) -> TreeArc<SyntaxNode> {
97 self.ptr.to_node(&self.file()).to_owned()
98 }
99 /// Maps range in the source code to the range in the expanded code.
100 pub fn map_range_forward(&self, src_range: TextRange) -> Option<TextRange> {
101 for (s_range, t_range) in self.ranges_map.iter() {
102 if src_range.is_subrange(&s_range) {
103 let src_at_zero_range = src_range - src_range.start();
104 let src_range_offset = src_range.start() - s_range.start();
105 let src_range = src_at_zero_range + src_range_offset + t_range.start();
106 return Some(src_range);
107 }
108 }
109 None
110 }
111 /// Maps range in the expanded code to the range in the source code.
112 pub fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
113 for (s_range, t_range) in self.ranges_map.iter() {
114 if tgt_range.is_subrange(&t_range) {
115 let tgt_at_zero_range = tgt_range - tgt_range.start();
116 let tgt_range_offset = tgt_range.start() - t_range.start();
117 let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
118 return Some(src_range);
119 }
120 }
121 None
122 }
123}
124
125pub(crate) fn expand_macro_invocation(
126 db: &impl PersistentHirDatabase,
127 invoc: MacroCallId,
128) -> Option<Arc<MacroExpansion>> {
129 let loc = invoc.loc(db);
130 let syntax = db.file_item(loc.source_item_id);
131 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
132
133 let (def, input) = MacroDef::from_call(macro_call)?;
134 def.expand(input).map(Arc::new)
135}
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 6f3e5f09d..5b6400042 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -1,6 +1,7 @@
1test_utils::marks!( 1test_utils::marks!(
2 bogus_paths
2 name_res_works_for_broken_modules 3 name_res_works_for_broken_modules
3 item_map_enum_importing 4 can_import_enum_variant
4 type_var_cycles_resolve_completely 5 type_var_cycles_resolve_completely
5 type_var_cycles_resolve_as_possible 6 type_var_cycles_resolve_as_possible
6 type_var_resolves_to_int_var 7 type_var_resolves_to_int_var
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index 99c2115e1..e69de29bb 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -1,331 +0,0 @@
1use std::sync::Arc;
2
3use arrayvec::ArrayVec;
4use relative_path::RelativePathBuf;
5use ra_db::{FileId, SourceRoot};
6use ra_syntax::{
7 SyntaxNode, TreeArc,
8 algo::generate,
9 ast::{self, AstNode, NameOwner},
10};
11use ra_arena::{Arena, RawId, impl_arena_id};
12use test_utils::tested_by;
13
14use crate::{
15 Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource,
16 PersistentHirDatabase,
17 Crate,
18 ids::SourceFileItemId,
19};
20
21impl ModuleSource {
22 pub(crate) fn new(
23 db: &impl PersistentHirDatabase,
24 file_id: HirFileId,
25 decl_id: Option<SourceFileItemId>,
26 ) -> ModuleSource {
27 match decl_id {
28 Some(item_id) => {
29 let module = db.file_item(SourceItemId { file_id, item_id });
30 let module = ast::Module::cast(&*module).unwrap();
31 assert!(module.item_list().is_some(), "expected inline module");
32 ModuleSource::Module(module.to_owned())
33 }
34 None => {
35 let source_file = db.hir_parse(file_id);
36 ModuleSource::SourceFile(source_file)
37 }
38 }
39 }
40}
41
42#[derive(Clone, Hash, PartialEq, Eq, Debug)]
43pub struct Submodule {
44 name: Name,
45 is_declaration: bool,
46 decl_id: SourceFileItemId,
47}
48
49impl Submodule {
50 pub(crate) fn submodules_query(
51 db: &impl PersistentHirDatabase,
52 file_id: HirFileId,
53 decl_id: Option<SourceFileItemId>,
54 ) -> Arc<Vec<Submodule>> {
55 db.check_canceled();
56 let file_items = db.file_items(file_id);
57 let module_source = ModuleSource::new(db, file_id, decl_id);
58 let submodules = match module_source {
59 ModuleSource::SourceFile(source_file) => {
60 collect_submodules(file_id, &file_items, &*source_file)
61 }
62 ModuleSource::Module(module) => {
63 collect_submodules(file_id, &file_items, module.item_list().unwrap())
64 }
65 };
66
67 return Arc::new(submodules);
68
69 fn collect_submodules(
70 file_id: HirFileId,
71 file_items: &SourceFileItems,
72 root: &impl ast::ModuleItemOwner,
73 ) -> Vec<Submodule> {
74 root.items()
75 .filter_map(|item| match item.kind() {
76 ast::ModuleItemKind::Module(m) => Some(m),
77 _ => None,
78 })
79 .filter_map(|module| {
80 let name = module.name()?.as_name();
81 if !module.has_semi() && module.item_list().is_none() {
82 tested_by!(name_res_works_for_broken_modules);
83 return None;
84 }
85 let sub = Submodule {
86 name,
87 is_declaration: module.has_semi(),
88 decl_id: file_items.id_of(file_id, module.syntax()),
89 };
90 Some(sub)
91 })
92 .collect()
93 }
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
98pub struct ModuleId(RawId);
99impl_arena_id!(ModuleId);
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
102pub struct LinkId(RawId);
103impl_arena_id!(LinkId);
104
105/// Physically, rust source is organized as a set of files, but logically it is
106/// organized as a tree of modules. Usually, a single file corresponds to a
107/// single module, but it is not neccessarily always the case.
108///
109/// `ModuleTree` encapsulates the logic of transitioning from the fuzzy world of files
110/// (which can have multiple parents) to the precise world of modules (which
111/// always have one parent).
112#[derive(Default, Debug, PartialEq, Eq)]
113pub struct ModuleTree {
114 mods: Arena<ModuleId, ModuleData>,
115 links: Arena<LinkId, LinkData>,
116}
117
118#[derive(Debug, PartialEq, Eq)]
119pub struct ModuleData {
120 file_id: HirFileId,
121 /// Points to `ast::Module`, `None` for the whole file.
122 decl_id: Option<SourceFileItemId>,
123 parent: Option<LinkId>,
124 children: Vec<LinkId>,
125}
126
127#[derive(Hash, Debug, PartialEq, Eq)]
128struct LinkData {
129 source: SourceItemId,
130 owner: ModuleId,
131 name: Name,
132 points_to: Vec<ModuleId>,
133 problem: Option<Problem>,
134}
135
136impl ModuleTree {
137 pub(crate) fn module_tree_query(
138 db: &impl PersistentHirDatabase,
139 krate: Crate,
140 ) -> Arc<ModuleTree> {
141 db.check_canceled();
142 let mut res = ModuleTree::default();
143 res.init_crate(db, krate);
144 Arc::new(res)
145 }
146
147 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
148 self.mods.iter().map(|(id, _)| id)
149 }
150
151 pub(crate) fn find_module_by_source(
152 &self,
153 file_id: HirFileId,
154 decl_id: Option<SourceFileItemId>,
155 ) -> Option<ModuleId> {
156 let (res, _) =
157 self.mods.iter().find(|(_, m)| (m.file_id, m.decl_id) == (file_id, decl_id))?;
158 Some(res)
159 }
160
161 fn init_crate(&mut self, db: &impl PersistentHirDatabase, krate: Crate) {
162 let crate_graph = db.crate_graph();
163 let file_id = crate_graph.crate_root(krate.crate_id);
164 let source_root_id = db.file_source_root(file_id);
165
166 let source_root = db.source_root(source_root_id);
167 self.init_subtree(db, &source_root, None, file_id.into(), None);
168 }
169
170 fn init_subtree(
171 &mut self,
172 db: &impl PersistentHirDatabase,
173 source_root: &SourceRoot,
174 parent: Option<LinkId>,
175 file_id: HirFileId,
176 decl_id: Option<SourceFileItemId>,
177 ) -> ModuleId {
178 let is_root = parent.is_none();
179 let id = self.alloc_mod(ModuleData { file_id, decl_id, parent, children: Vec::new() });
180 for sub in db.submodules(file_id, decl_id).iter() {
181 let link = self.alloc_link(LinkData {
182 source: SourceItemId { file_id, item_id: sub.decl_id },
183 name: sub.name.clone(),
184 owner: id,
185 points_to: Vec::new(),
186 problem: None,
187 });
188
189 let (points_to, problem) = if sub.is_declaration {
190 let (points_to, problem) = resolve_submodule(db, file_id, &sub.name, is_root);
191 let points_to = points_to
192 .into_iter()
193 .map(|file_id| {
194 self.init_subtree(db, source_root, Some(link), file_id.into(), None)
195 })
196 .collect::<Vec<_>>();
197 (points_to, problem)
198 } else {
199 let points_to =
200 self.init_subtree(db, source_root, Some(link), file_id, Some(sub.decl_id));
201 (vec![points_to], None)
202 };
203
204 self.links[link].points_to = points_to;
205 self.links[link].problem = problem;
206 }
207 id
208 }
209
210 fn alloc_mod(&mut self, data: ModuleData) -> ModuleId {
211 self.mods.alloc(data)
212 }
213
214 fn alloc_link(&mut self, data: LinkData) -> LinkId {
215 let owner = data.owner;
216 let id = self.links.alloc(data);
217 self.mods[owner].children.push(id);
218 id
219 }
220}
221
222impl ModuleId {
223 pub(crate) fn file_id(self, tree: &ModuleTree) -> HirFileId {
224 tree.mods[self].file_id
225 }
226 pub(crate) fn decl_id(self, tree: &ModuleTree) -> Option<SourceFileItemId> {
227 tree.mods[self].decl_id
228 }
229 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
230 tree.mods[self].parent
231 }
232 pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
233 let link = self.parent_link(tree)?;
234 Some(tree.links[link].owner)
235 }
236 pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
237 generate(Some(self), move |it| it.parent(tree)).last().unwrap()
238 }
239 pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
240 let link = tree.mods[self]
241 .children
242 .iter()
243 .map(|&it| &tree.links[it])
244 .find(|it| it.name == *name)?;
245 Some(*link.points_to.first()?)
246 }
247 pub(crate) fn children<'a>(
248 self,
249 tree: &'a ModuleTree,
250 ) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
251 tree.mods[self].children.iter().filter_map(move |&it| {
252 let link = &tree.links[it];
253 let module = *link.points_to.first()?;
254 Some((link.name.clone(), module))
255 })
256 }
257 pub(crate) fn problems(
258 self,
259 tree: &ModuleTree,
260 db: &impl HirDatabase,
261 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
262 tree.mods[self]
263 .children
264 .iter()
265 .filter_map(|&link| {
266 let p = tree.links[link].problem.clone()?;
267 let s = link.source(tree, db);
268 let s = s.name().unwrap().syntax().to_owned();
269 Some((s, p))
270 })
271 .collect()
272 }
273}
274
275impl LinkId {
276 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
277 tree.links[self].owner
278 }
279 pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
280 &tree.links[self].name
281 }
282 pub(crate) fn source(
283 self,
284 tree: &ModuleTree,
285 db: &impl PersistentHirDatabase,
286 ) -> TreeArc<ast::Module> {
287 let syntax_node = db.file_item(tree.links[self].source);
288 ast::Module::cast(&syntax_node).unwrap().to_owned()
289 }
290}
291
292fn resolve_submodule(
293 db: &impl PersistentHirDatabase,
294 file_id: HirFileId,
295 name: &Name,
296 is_root: bool,
297) -> (Vec<FileId>, Option<Problem>) {
298 // FIXME: handle submodules of inline modules properly
299 let file_id = file_id.original_file(db);
300 let source_root_id = db.file_source_root(file_id);
301 let path = db.file_relative_path(file_id);
302 let root = RelativePathBuf::default();
303 let dir_path = path.parent().unwrap_or(&root);
304 let mod_name = path.file_stem().unwrap_or("unknown");
305 let is_dir_owner = is_root || mod_name == "mod";
306
307 let file_mod = dir_path.join(format!("{}.rs", name));
308 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
309 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
310 let mut candidates = ArrayVec::<[_; 2]>::new();
311 if is_dir_owner {
312 candidates.push(file_mod.clone());
313 candidates.push(dir_mod);
314 } else {
315 candidates.push(file_dir_mod.clone());
316 };
317 let sr = db.source_root(source_root_id);
318 let points_to = candidates
319 .into_iter()
320 .filter_map(|path| sr.files.get(&path))
321 .map(|&it| it)
322 .collect::<Vec<_>>();
323 let problem = if points_to.is_empty() {
324 Some(Problem::UnresolvedModule {
325 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
326 })
327 } else {
328 None
329 };
330 (points_to, problem)
331}
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 8d786d2ac..06bafa6f0 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -64,6 +64,7 @@ impl Name {
64 "str" => KnownName::Str, 64 "str" => KnownName::Str,
65 "Self" => KnownName::SelfType, 65 "Self" => KnownName::SelfType,
66 "self" => KnownName::SelfParam, 66 "self" => KnownName::SelfParam,
67 "macro_rules" => KnownName::MacroRules,
67 _ => return None, 68 _ => return None,
68 }; 69 };
69 Some(name) 70 Some(name)
@@ -122,4 +123,6 @@ pub(crate) enum KnownName {
122 123
123 SelfType, 124 SelfType,
124 SelfParam, 125 SelfParam,
126
127 MacroRules,
125} 128}
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 73919ee37..edd2f25f7 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -1,60 +1,148 @@
1//! Name resolution algorithm. The end result of the algorithm is an `ItemMap`: 1/// This module implements import-resolution/macro expansion algorithm.
2//! a map which maps each module to its scope: the set of items visible in the 2///
3//! module. That is, we only resolve imports here, name resolution of item 3/// The result of this module is `CrateDefMap`: a datastructure which contains:
4//! bodies will be done in a separate step. 4///
5//! 5/// * a tree of modules for the crate
6//! Like Rustc, we use an interactive per-crate algorithm: we start with scopes 6/// * for each module, a set of items visible in the module (directly declared
7//! containing only directly defined items, and then iteratively resolve 7/// or imported)
8//! imports. 8///
9//! 9/// Note that `CrateDefMap` contains fully macro expanded code.
10//! To make this work nicely in the IDE scenario, we place `InputModuleItems` 10///
11//! in between raw syntax and name resolution. `InputModuleItems` are computed 11/// Computing `CrateDefMap` can be partitioned into several logically
12//! using only the module's syntax, and it is all directly defined items plus 12/// independent "phases". The phases are mutually recursive though, there's no
13//! imports. The plan is to make `InputModuleItems` independent of local 13/// strict ordering.
14//! modifications (that is, typing inside a function should not change IMIs), 14///
15//! so that the results of name resolution can be preserved unless the module 15/// ## Collecting RawItems
16//! structure itself is modified. 16///
17pub(crate) mod lower; 17/// This happens in the `raw` module, which parses a single source file into a
18 18/// set of top-level items. Nested imports are desugared to flat imports in
19use std::{time, sync::Arc}; 19/// this phase. Macro calls are represented as a triple of (Path, Option<Name>,
20 20/// TokenTree).
21use rustc_hash::{FxHashMap, FxHashSet}; 21///
22 22/// ## Collecting Modules
23use ra_arena::map::ArenaMap; 23///
24use ra_db::Edition; 24/// This happens in the `collector` module. In this phase, we recursively walk
25/// tree of modules, collect raw items from submodules, populate module scopes
26/// with defined items (so, we assign item ids in this phase) and record the set
27/// of unresolved imports and macros.
28///
29/// While we walk tree of modules, we also record macro_rules definitions and
30/// expand calls to macro_rules defined macros.
31///
32/// ## Resolving Imports
33///
34/// We maintain a list of currently unresolved imports. On every iteration, we
35/// try to resolve some imports from this list. If the import is resolved, we
36/// record it, by adding an item to current module scope and, if necessary, by
37/// recursively populating glob imports.
38///
39/// ## Resolving Macros
40///
41/// macro_rules from the same crate use a global mutable namespace. We expand
42/// them immediately, when we collect modules.
43///
44/// Macros from other crates (including proc-macros) can be used with
45/// `foo::bar!` syntax. We handle them similarly to imports. There's a list of
46/// unexpanded macros. On every iteration, we try to resolve each macro call
47/// path and, upon success, we run macro expansion and "collect module" phase
48/// on the result
49
50mod per_ns;
51mod raw;
52mod collector;
53#[cfg(test)]
54mod tests;
55
56use std::sync::Arc;
57
58use rustc_hash::FxHashMap;
59use ra_arena::{Arena, RawId, impl_arena_id};
60use ra_db::{FileId, Edition};
25use test_utils::tested_by; 61use test_utils::tested_by;
26 62
27use crate::{ 63use crate::{
28 Module, ModuleDef, 64 ModuleDef, Name, Crate, Module, Problem,
29 Path, PathKind, PersistentHirDatabase, 65 PersistentHirDatabase, Path, PathKind, HirFileId,
30 Crate, Name, 66 ids::{SourceItemId, SourceFileItemId, MacroCallId},
31 module_tree::{ModuleId, ModuleTree},
32 nameres::lower::{ImportId, LoweredModule, ImportData},
33}; 67};
34 68
35/// `ItemMap` is the result of module name resolution. It contains, for each 69pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
36/// module, the set of visible items. 70
71pub use self::per_ns::{PerNs, Namespace};
72
73/// Contans all top-level defs from a macro-expanded crate
37#[derive(Debug, PartialEq, Eq)] 74#[derive(Debug, PartialEq, Eq)]
38pub struct ItemMap { 75pub struct CrateDefMap {
76 krate: Crate,
39 edition: Edition, 77 edition: Edition,
40 /// The prelude module for this crate. This either comes from an import 78 /// The prelude module for this crate. This either comes from an import
41 /// marked with the `prelude_import` attribute, or (in the normal case) from 79 /// marked with the `prelude_import` attribute, or (in the normal case) from
42 /// a dependency (`std` or `core`). 80 /// a dependency (`std` or `core`).
43 pub(crate) prelude: Option<Module>, 81 prelude: Option<Module>,
44 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, 82 extern_prelude: FxHashMap<Name, ModuleDef>,
45 per_module: ArenaMap<ModuleId, ModuleScope>, 83 root: CrateModuleId,
84 modules: Arena<CrateModuleId, ModuleData>,
85 macros: Arena<CrateMacroId, mbe::MacroRules>,
86 public_macros: FxHashMap<Name, CrateMacroId>,
87 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
88 problems: CrateDefMapProblems,
89}
90
91impl std::ops::Index<CrateModuleId> for CrateDefMap {
92 type Output = ModuleData;
93 fn index(&self, id: CrateModuleId) -> &ModuleData {
94 &self.modules[id]
95 }
96}
97
98impl std::ops::Index<CrateMacroId> for CrateDefMap {
99 type Output = mbe::MacroRules;
100 fn index(&self, id: CrateMacroId) -> &mbe::MacroRules {
101 &self.macros[id]
102 }
103}
104
105/// An ID of a macro, **local** to a specific crate
106#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
107pub(crate) struct CrateMacroId(RawId);
108impl_arena_id!(CrateMacroId);
109
110/// An ID of a module, **local** to a specific crate
111#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
112pub(crate) struct CrateModuleId(RawId);
113impl_arena_id!(CrateModuleId);
114
115#[derive(Default, Debug, PartialEq, Eq)]
116pub(crate) struct ModuleData {
117 pub(crate) parent: Option<CrateModuleId>,
118 pub(crate) children: FxHashMap<Name, CrateModuleId>,
119 pub(crate) scope: ModuleScope,
120 /// None for root
121 pub(crate) declaration: Option<SourceItemId>,
122 /// None for inline modules.
123 ///
124 /// Note that non-inline modules, by definition, live inside non-macro file.
125 pub(crate) definition: Option<FileId>,
126}
127
128#[derive(Default, Debug, PartialEq, Eq)]
129pub(crate) struct CrateDefMapProblems {
130 problems: Vec<(SourceItemId, Problem)>,
46} 131}
47 132
48impl std::ops::Index<ModuleId> for ItemMap { 133impl CrateDefMapProblems {
49 type Output = ModuleScope; 134 fn add(&mut self, source_item_id: SourceItemId, problem: Problem) {
50 fn index(&self, id: ModuleId) -> &ModuleScope { 135 self.problems.push((source_item_id, problem))
51 &self.per_module[id] 136 }
137
138 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a {
139 self.problems.iter().map(|(s, p)| (s, p))
52 } 140 }
53} 141}
54 142
55#[derive(Debug, Default, PartialEq, Eq, Clone)] 143#[derive(Debug, Default, PartialEq, Eq, Clone)]
56pub struct ModuleScope { 144pub struct ModuleScope {
57 pub(crate) items: FxHashMap<Name, Resolution>, 145 items: FxHashMap<Name, Resolution>,
58} 146}
59 147
60impl ModuleScope { 148impl ModuleScope {
@@ -66,8 +154,6 @@ impl ModuleScope {
66 } 154 }
67} 155}
68 156
69/// `Resolution` is basically `DefId` atm, but it should account for stuff like
70/// multiple namespaces, ambiguity and errors.
71#[derive(Debug, Clone, PartialEq, Eq, Default)] 157#[derive(Debug, Clone, PartialEq, Eq, Default)]
72pub struct Resolution { 158pub struct Resolution {
73 /// None for unresolved 159 /// None for unresolved
@@ -76,372 +162,6 @@ pub struct Resolution {
76 pub import: Option<ImportId>, 162 pub import: Option<ImportId>,
77} 163}
78 164
79#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub enum Namespace {
81 Types,
82 Values,
83}
84
85#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
86pub struct PerNs<T> {
87 pub types: Option<T>,
88 pub values: Option<T>,
89}
90
91impl<T> Default for PerNs<T> {
92 fn default() -> Self {
93 PerNs { types: None, values: None }
94 }
95}
96
97impl<T> PerNs<T> {
98 pub fn none() -> PerNs<T> {
99 PerNs { types: None, values: None }
100 }
101
102 pub fn values(t: T) -> PerNs<T> {
103 PerNs { types: None, values: Some(t) }
104 }
105
106 pub fn types(t: T) -> PerNs<T> {
107 PerNs { types: Some(t), values: None }
108 }
109
110 pub fn both(types: T, values: T) -> PerNs<T> {
111 PerNs { types: Some(types), values: Some(values) }
112 }
113
114 pub fn is_none(&self) -> bool {
115 self.types.is_none() && self.values.is_none()
116 }
117
118 pub fn is_both(&self) -> bool {
119 self.types.is_some() && self.values.is_some()
120 }
121
122 pub fn take(self, namespace: Namespace) -> Option<T> {
123 match namespace {
124 Namespace::Types => self.types,
125 Namespace::Values => self.values,
126 }
127 }
128
129 pub fn take_types(self) -> Option<T> {
130 self.take(Namespace::Types)
131 }
132
133 pub fn take_values(self) -> Option<T> {
134 self.take(Namespace::Values)
135 }
136
137 pub fn get(&self, namespace: Namespace) -> Option<&T> {
138 self.as_ref().take(namespace)
139 }
140
141 pub fn as_ref(&self) -> PerNs<&T> {
142 PerNs { types: self.types.as_ref(), values: self.values.as_ref() }
143 }
144
145 pub fn or(self, other: PerNs<T>) -> PerNs<T> {
146 PerNs { types: self.types.or(other.types), values: self.values.or(other.values) }
147 }
148
149 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
150 PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) }
151 }
152
153 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
154 PerNs { types: self.types.map(&f), values: self.values.map(&f) }
155 }
156}
157
158struct Resolver<'a, DB> {
159 db: &'a DB,
160 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
161 krate: Crate,
162 module_tree: Arc<ModuleTree>,
163 processed_imports: FxHashSet<(ModuleId, ImportId)>,
164 /// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import)
165 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>,
166 result: ItemMap,
167}
168
169impl<'a, DB> Resolver<'a, DB>
170where
171 DB: PersistentHirDatabase,
172{
173 fn new(
174 db: &'a DB,
175 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
176 krate: Crate,
177 ) -> Resolver<'a, DB> {
178 let module_tree = db.module_tree(krate);
179 Resolver {
180 db,
181 input,
182 krate,
183 module_tree,
184 processed_imports: FxHashSet::default(),
185 glob_imports: FxHashMap::default(),
186 result: ItemMap {
187 edition: krate.edition(db),
188 prelude: None,
189 extern_prelude: FxHashMap::default(),
190 per_module: ArenaMap::default(),
191 },
192 }
193 }
194
195 pub(crate) fn resolve(mut self) -> ItemMap {
196 self.populate_extern_prelude();
197 for (&module_id, items) in self.input.iter() {
198 self.populate_module(module_id, Arc::clone(items));
199 }
200
201 let mut iter = 0;
202 loop {
203 iter += 1;
204 if iter > 1000 {
205 panic!("failed to reach fixedpoint after 1000 iters")
206 }
207 let processed_imports_count = self.processed_imports.len();
208 for &module_id in self.input.keys() {
209 self.db.check_canceled();
210 self.resolve_imports(module_id);
211 }
212 if processed_imports_count == self.processed_imports.len() {
213 // no new imports resolved
214 break;
215 }
216 }
217 self.result
218 }
219
220 fn populate_extern_prelude(&mut self) {
221 for dep in self.krate.dependencies(self.db) {
222 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
223 if let Some(module) = dep.krate.root_module(self.db) {
224 self.result.extern_prelude.insert(dep.name.clone(), module.into());
225 }
226 // look for the prelude
227 if self.result.prelude.is_none() {
228 let item_map = self.db.item_map(dep.krate);
229 if item_map.prelude.is_some() {
230 self.result.prelude = item_map.prelude;
231 }
232 }
233 }
234 }
235
236 fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) {
237 let mut module_items = ModuleScope::default();
238 for (import_id, import_data) in input.imports.iter() {
239 if let Some(last_segment) = import_data.path.segments.iter().last() {
240 if !import_data.is_glob {
241 let name =
242 import_data.alias.clone().unwrap_or_else(|| last_segment.name.clone());
243 module_items
244 .items
245 .insert(name, Resolution { def: PerNs::none(), import: Some(import_id) });
246 }
247 }
248 }
249 // Populate explicitly declared items, except modules
250 for (name, &def) in input.declarations.iter() {
251 let resolution = Resolution { def, import: None };
252 module_items.items.insert(name.clone(), resolution);
253 }
254
255 // Populate modules
256 for (name, module_id) in module_id.children(&self.module_tree) {
257 let module = Module { module_id, krate: self.krate };
258 self.add_module_item(&mut module_items, name, PerNs::types(module.into()));
259 }
260
261 self.result.per_module.insert(module_id, module_items);
262 }
263
264 fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def: PerNs<ModuleDef>) {
265 let resolution = Resolution { def, import: None };
266 module_items.items.insert(name, resolution);
267 }
268
269 fn resolve_imports(&mut self, module_id: ModuleId) {
270 for (import_id, import_data) in self.input[&module_id].imports.iter() {
271 if self.processed_imports.contains(&(module_id, import_id)) {
272 // already done
273 continue;
274 }
275 if self.resolve_import(module_id, import_id, import_data) == ReachedFixedPoint::Yes {
276 log::debug!("import {:?} resolved (or definite error)", import_id);
277 self.processed_imports.insert((module_id, import_id));
278 }
279 }
280 }
281
282 fn resolve_import(
283 &mut self,
284 module_id: ModuleId,
285 import_id: ImportId,
286 import: &ImportData,
287 ) -> ReachedFixedPoint {
288 log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
289 let original_module = Module { krate: self.krate, module_id };
290
291 let (def, reached_fixedpoint) = if import.is_extern_crate {
292 let res = self.result.resolve_name_in_extern_prelude(
293 &import
294 .path
295 .as_ident()
296 .expect("extern crate should have been desugared to one-element path"),
297 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else {
300 let res = self.result.resolve_path_fp(
301 self.db,
302 ResolveMode::Import,
303 original_module,
304 &import.path,
305 );
306
307 (res.resolved_def, res.reached_fixedpoint)
308 };
309
310 if reached_fixedpoint != ReachedFixedPoint::Yes {
311 return reached_fixedpoint;
312 }
313
314 if import.is_glob {
315 log::debug!("glob import: {:?}", import);
316 match def.take_types() {
317 Some(ModuleDef::Module(m)) => {
318 if import.is_prelude {
319 tested_by!(std_prelude);
320 self.result.prelude = Some(m);
321 } else if m.krate != self.krate {
322 tested_by!(glob_across_crates);
323 // glob import from other crate => we can just import everything once
324 let item_map = self.db.item_map(m.krate);
325 let scope = &item_map[m.module_id];
326 let items = scope
327 .items
328 .iter()
329 .map(|(name, res)| (name.clone(), res.clone()))
330 .collect::<Vec<_>>();
331 self.update(module_id, Some(import_id), &items);
332 } else {
333 // glob import from same crate => we do an initial
334 // import, and then need to propagate any further
335 // additions
336 let scope = &self.result[m.module_id];
337 let items = scope
338 .items
339 .iter()
340 .map(|(name, res)| (name.clone(), res.clone()))
341 .collect::<Vec<_>>();
342 self.update(module_id, Some(import_id), &items);
343 // record the glob import in case we add further items
344 self.glob_imports
345 .entry(m.module_id)
346 .or_default()
347 .push((module_id, import_id));
348 }
349 }
350 Some(ModuleDef::Enum(e)) => {
351 tested_by!(glob_enum);
352 // glob import from enum => just import all the variants
353 let variants = e.variants(self.db);
354 let resolutions = variants
355 .into_iter()
356 .filter_map(|variant| {
357 let res = Resolution {
358 def: PerNs::both(variant.into(), variant.into()),
359 import: Some(import_id),
360 };
361 let name = variant.name(self.db)?;
362 Some((name, res))
363 })
364 .collect::<Vec<_>>();
365 self.update(module_id, Some(import_id), &resolutions);
366 }
367 Some(d) => {
368 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
369 }
370 None => {
371 log::debug!("glob import {:?} didn't resolve as type", import);
372 }
373 }
374 } else {
375 let last_segment = import.path.segments.last().unwrap();
376 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
377 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
378
379 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
380 if let Some(root_module) = self.krate.root_module(self.db) {
381 if import.is_extern_crate && module_id == root_module.module_id {
382 if let Some(def) = def.take_types() {
383 self.result.extern_prelude.insert(name.clone(), def);
384 }
385 }
386 }
387 let resolution = Resolution { def, import: Some(import_id) };
388 self.update(module_id, None, &[(name, resolution)]);
389 }
390 reached_fixedpoint
391 }
392
393 fn update(
394 &mut self,
395 module_id: ModuleId,
396 import: Option<ImportId>,
397 resolutions: &[(Name, Resolution)],
398 ) {
399 self.update_recursive(module_id, import, resolutions, 0)
400 }
401
402 fn update_recursive(
403 &mut self,
404 module_id: ModuleId,
405 import: Option<ImportId>,
406 resolutions: &[(Name, Resolution)],
407 depth: usize,
408 ) {
409 if depth > 100 {
410 // prevent stack overflows (but this shouldn't be possible)
411 panic!("infinite recursion in glob imports!");
412 }
413 let module_items = self.result.per_module.get_mut(module_id).unwrap();
414 let mut changed = false;
415 for (name, res) in resolutions {
416 let existing = module_items.items.entry(name.clone()).or_default();
417 if existing.def.types.is_none() && res.def.types.is_some() {
418 existing.def.types = res.def.types;
419 existing.import = import.or(res.import);
420 changed = true;
421 }
422 if existing.def.values.is_none() && res.def.values.is_some() {
423 existing.def.values = res.def.values;
424 existing.import = import.or(res.import);
425 changed = true;
426 }
427 }
428 if !changed {
429 return;
430 }
431 let glob_imports = self
432 .glob_imports
433 .get(&module_id)
434 .into_iter()
435 .flat_map(|v| v.iter())
436 .cloned()
437 .collect::<Vec<_>>();
438 for (glob_importing_module, glob_import) in glob_imports {
439 // We pass the glob import so that the tracked import in those modules is that glob import
440 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
441 }
442 }
443}
444
445#[derive(Debug, Clone)] 165#[derive(Debug, Clone)]
446struct ResolvePathResult { 166struct ResolvePathResult {
447 resolved_def: PerNs<ModuleDef>, 167 resolved_def: PerNs<ModuleDef>,
@@ -475,84 +195,85 @@ enum ReachedFixedPoint {
475 No, 195 No,
476} 196}
477 197
478impl ItemMap { 198impl CrateDefMap {
479 pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> { 199 pub(crate) fn crate_def_map_query(
480 let start = time::Instant::now(); 200 db: &impl PersistentHirDatabase,
481 let module_tree = db.module_tree(krate); 201 krate: Crate,
482 let input = module_tree 202 ) -> Arc<CrateDefMap> {
483 .modules() 203 let start = std::time::Instant::now();
484 .map(|module_id| (module_id, db.lower_module(Module { krate, module_id }))) 204 let def_map = {
485 .collect::<FxHashMap<_, _>>(); 205 let edition = krate.edition(db);
486 206 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
487 let resolver = Resolver::new(db, &input, krate); 207 let root = modules.alloc(ModuleData::default());
488 let res = resolver.resolve(); 208 CrateDefMap {
489 let elapsed = start.elapsed(); 209 krate,
490 log::info!("item_map: {:?}", elapsed); 210 edition,
491 Arc::new(res) 211 extern_prelude: FxHashMap::default(),
212 prelude: None,
213 root,
214 modules,
215 macros: Arena::default(),
216 public_macros: FxHashMap::default(),
217 macro_resolutions: FxHashMap::default(),
218 problems: CrateDefMapProblems::default(),
219 }
220 };
221 let def_map = collector::collect_defs(db, def_map);
222 log::info!("crate_def_map_query: {:?}", start.elapsed());
223 Arc::new(def_map)
492 } 224 }
493 225
494 pub(crate) fn resolve_path( 226 pub(crate) fn root(&self) -> CrateModuleId {
495 &self, 227 self.root
496 db: &impl PersistentHirDatabase,
497 original_module: Module,
498 path: &Path,
499 ) -> (PerNs<ModuleDef>, Option<usize>) {
500 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
501 (res.resolved_def, res.segment_index)
502 } 228 }
503 229
504 fn resolve_in_prelude( 230 pub(crate) fn problems(&self) -> &CrateDefMapProblems {
505 &self, 231 &self.problems
506 db: &impl PersistentHirDatabase,
507 original_module: Module,
508 name: &Name,
509 ) -> PerNs<ModuleDef> {
510 if let Some(prelude) = self.prelude {
511 let resolution = if prelude.krate == original_module.krate {
512 self[prelude.module_id].items.get(name).cloned()
513 } else {
514 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
515 };
516 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
517 } else {
518 PerNs::none()
519 }
520 } 232 }
521 233
522 pub(crate) fn resolve_name_in_module( 234 pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module {
523 &self, 235 Module { krate: self.krate, module_id }
524 db: &impl PersistentHirDatabase, 236 }
525 module: Module,
526 name: &Name,
527 ) -> PerNs<ModuleDef> {
528 // Resolve in:
529 // - current module / scope
530 // - extern prelude
531 // - std prelude
532 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
533 let from_extern_prelude =
534 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
535 let from_prelude = self.resolve_in_prelude(db, module, name);
536 237
537 from_scope.or(from_extern_prelude).or(from_prelude) 238 pub(crate) fn prelude(&self) -> Option<Module> {
239 self.prelude
538 } 240 }
539 241
540 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 242 pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> {
541 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 243 &self.extern_prelude
542 } 244 }
543 245
544 fn resolve_name_in_crate_root_or_extern_prelude( 246 pub(crate) fn resolve_macro(
545 &self, 247 &self,
546 db: &impl PersistentHirDatabase, 248 macro_call_id: MacroCallId,
547 module: Module, 249 ) -> Option<(Crate, CrateMacroId)> {
548 name: &Name, 250 self.macro_resolutions.get(&macro_call_id).map(|&it| it)
549 ) -> PerNs<ModuleDef> { 251 }
550 let crate_root = module.crate_root(db);
551 let from_crate_root =
552 self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
553 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
554 252
555 from_crate_root.or(from_extern_prelude) 253 pub(crate) fn find_module_by_source(
254 &self,
255 file_id: HirFileId,
256 decl_id: Option<SourceFileItemId>,
257 ) -> Option<CrateModuleId> {
258 let decl_id = decl_id.map(|it| it.with_file_id(file_id));
259 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
260 if decl_id.is_some() {
261 module_data.declaration == decl_id
262 } else {
263 module_data.definition.map(|it| it.into()) == Some(file_id)
264 }
265 })?;
266 Some(module_id)
267 }
268
269 pub(crate) fn resolve_path(
270 &self,
271 db: &impl PersistentHirDatabase,
272 original_module: CrateModuleId,
273 path: &Path,
274 ) -> (PerNs<ModuleDef>, Option<usize>) {
275 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
276 (res.resolved_def, res.segment_index)
556 } 277 }
557 278
558 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -561,13 +282,17 @@ impl ItemMap {
561 &self, 282 &self,
562 db: &impl PersistentHirDatabase, 283 db: &impl PersistentHirDatabase,
563 mode: ResolveMode, 284 mode: ResolveMode,
564 original_module: Module, 285 original_module: CrateModuleId,
565 path: &Path, 286 path: &Path,
566 ) -> ResolvePathResult { 287 ) -> ResolvePathResult {
567 let mut segments = path.segments.iter().enumerate(); 288 let mut segments = path.segments.iter().enumerate();
568 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 289 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
569 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 290 PathKind::Crate => {
570 PathKind::Self_ => PerNs::types(original_module.into()), 291 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
292 }
293 PathKind::Self_ => {
294 PerNs::types(Module { krate: self.krate, module_id: original_module }.into())
295 }
571 // plain import or absolute path in 2015: crate-relative with 296 // plain import or absolute path in 2015: crate-relative with
572 // fallback to extern prelude (with the simplification in 297 // fallback to extern prelude (with the simplification in
573 // rust-lang/rust#57745) 298 // rust-lang/rust#57745)
@@ -581,11 +306,7 @@ impl ItemMap {
581 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 306 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
582 }; 307 };
583 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 308 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
584 self.resolve_name_in_crate_root_or_extern_prelude( 309 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
585 db,
586 original_module,
587 &segment.name,
588 )
589 } 310 }
590 PathKind::Plain => { 311 PathKind::Plain => {
591 let segment = match segments.next() { 312 let segment = match segments.next() {
@@ -596,8 +317,8 @@ impl ItemMap {
596 self.resolve_name_in_module(db, original_module, &segment.name) 317 self.resolve_name_in_module(db, original_module, &segment.name)
597 } 318 }
598 PathKind::Super => { 319 PathKind::Super => {
599 if let Some(p) = original_module.parent(db) { 320 if let Some(p) = self.modules[original_module].parent {
600 PerNs::types(p.into()) 321 PerNs::types(Module { krate: self.krate, module_id: p }.into())
601 } else { 322 } else {
602 log::debug!("super path in root module"); 323 log::debug!("super path in root module");
603 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 324 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -634,14 +355,14 @@ impl ItemMap {
634 355
635 curr_per_ns = match curr { 356 curr_per_ns = match curr {
636 ModuleDef::Module(module) => { 357 ModuleDef::Module(module) => {
637 if module.krate != original_module.krate { 358 if module.krate != self.krate {
638 let path = Path { 359 let path = Path {
639 segments: path.segments[i..].iter().cloned().collect(), 360 segments: path.segments[i..].iter().cloned().collect(),
640 kind: PathKind::Self_, 361 kind: PathKind::Self_,
641 }; 362 };
642 log::debug!("resolving {:?} in other crate", path); 363 log::debug!("resolving {:?} in other crate", path);
643 let item_map = db.item_map(module.krate); 364 let defp_map = db.crate_def_map(module.krate);
644 let (def, s) = item_map.resolve_path(db, *module, &path); 365 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
645 return ResolvePathResult::with( 366 return ResolvePathResult::with(
646 def, 367 def,
647 ReachedFixedPoint::Yes, 368 ReachedFixedPoint::Yes,
@@ -649,7 +370,7 @@ impl ItemMap {
649 ); 370 );
650 } 371 }
651 372
652 match self[module.module_id].items.get(&segment.name) { 373 match self[module.module_id].scope.items.get(&segment.name) {
653 Some(res) if !res.def.is_none() => res.def, 374 Some(res) if !res.def.is_none() => res.def,
654 _ => { 375 _ => {
655 log::debug!("path segment {:?} not found", segment.name); 376 log::debug!("path segment {:?} not found", segment.name);
@@ -659,7 +380,7 @@ impl ItemMap {
659 } 380 }
660 ModuleDef::Enum(e) => { 381 ModuleDef::Enum(e) => {
661 // enum variant 382 // enum variant
662 tested_by!(item_map_enum_importing); 383 tested_by!(can_import_enum_variant);
663 match e.variant(db, &segment.name) { 384 match e.variant(db, &segment.name) {
664 Some(variant) => PerNs::both(variant.into(), variant.into()), 385 Some(variant) => PerNs::both(variant.into(), variant.into()),
665 None => { 386 None => {
@@ -690,7 +411,47 @@ impl ItemMap {
690 } 411 }
691 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 412 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
692 } 413 }
693}
694 414
695#[cfg(test)] 415 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
696mod tests; 416 let from_crate_root =
417 self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
418 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
419
420 from_crate_root.or(from_extern_prelude)
421 }
422
423 pub(crate) fn resolve_name_in_module(
424 &self,
425 db: &impl PersistentHirDatabase,
426 module: CrateModuleId,
427 name: &Name,
428 ) -> PerNs<ModuleDef> {
429 // Resolve in:
430 // - current module / scope
431 // - extern prelude
432 // - std prelude
433 let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
434 let from_extern_prelude =
435 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
436 let from_prelude = self.resolve_in_prelude(db, name);
437
438 from_scope.or(from_extern_prelude).or(from_prelude)
439 }
440
441 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
442 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
443 }
444
445 fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> {
446 if let Some(prelude) = self.prelude {
447 let resolution = if prelude.krate == self.krate {
448 self[prelude.module_id].scope.items.get(name).cloned()
449 } else {
450 db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned()
451 };
452 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
453 } else {
454 PerNs::none()
455 }
456 }
457}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
new file mode 100644
index 000000000..12ed49a0a
--- /dev/null
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -0,0 +1,564 @@
1use arrayvec::ArrayVec;
2use rustc_hash::FxHashMap;
3use relative_path::RelativePathBuf;
4use test_utils::tested_by;
5use ra_db::FileId;
6
7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 PersistentHirDatabase, HirFileId, Name, Path, Problem, Crate,
10 KnownName,
11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw},
12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
13};
14
15use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
16
17pub(super) fn collect_defs(
18 db: &impl PersistentHirDatabase,
19 mut def_map: CrateDefMap,
20) -> CrateDefMap {
21 // populate external prelude
22 for dep in def_map.krate.dependencies(db) {
23 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
24 if let Some(module) = dep.krate.root_module(db) {
25 def_map.extern_prelude.insert(dep.name.clone(), module.into());
26 }
27 // look for the prelude
28 if def_map.prelude.is_none() {
29 let map = db.crate_def_map(dep.krate);
30 if map.prelude.is_some() {
31 def_map.prelude = map.prelude;
32 }
33 }
34 }
35
36 let mut collector = DefCollector {
37 db,
38 def_map,
39 glob_imports: FxHashMap::default(),
40 unresolved_imports: Vec::new(),
41 unexpanded_macros: Vec::new(),
42 global_macro_scope: FxHashMap::default(),
43 };
44 collector.collect();
45 collector.finish()
46}
47
48/// Walks the tree of module recursively
49struct DefCollector<DB> {
50 db: DB,
51 def_map: CrateDefMap,
52 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
53 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
54 unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>,
55 global_macro_scope: FxHashMap<Name, CrateMacroId>,
56}
57
58impl<'a, DB> DefCollector<&'a DB>
59where
60 DB: PersistentHirDatabase,
61{
62 fn collect(&mut self) {
63 let crate_graph = self.db.crate_graph();
64 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
65 let raw_items = self.db.raw_items(file_id);
66 let module_id = self.def_map.root;
67 self.def_map.modules[module_id].definition = Some(file_id);
68 ModCollector {
69 def_collector: &mut *self,
70 module_id,
71 file_id: file_id.into(),
72 raw_items: &raw_items,
73 }
74 .collect(raw_items.items());
75
76 // main name resolution fixed-point loop.
77 let mut i = 0;
78 loop {
79 match (self.resolve_imports(), self.resolve_macros()) {
80 (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break,
81 _ => i += 1,
82 }
83 if i == 1000 {
84 log::error!("diverging name resolution");
85 break;
86 }
87 }
88
89 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
90 // show unresolved imports in completion, etc
91 for (module_id, import, import_data) in unresolved_imports {
92 self.record_resolved_import(module_id, PerNs::none(), import, &import_data)
93 }
94 }
95
96 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) {
97 if let Ok(rules) = mbe::MacroRules::parse(tt) {
98 let macro_id = self.def_map.macros.alloc(rules);
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 }
104 }
105
106 fn resolve_imports(&mut self) -> ReachedFixedPoint {
107 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
108 let mut resolved = Vec::new();
109 imports.retain(|(module_id, import, import_data)| {
110 let (def, fp) = self.resolve_import(*module_id, import_data);
111 if fp == ReachedFixedPoint::Yes {
112 resolved.push((*module_id, def, *import, import_data.clone()))
113 }
114 fp == ReachedFixedPoint::No
115 });
116 self.unresolved_imports = imports;
117 // Resolves imports, filling-in module scopes
118 let result =
119 if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
120 for (module_id, def, import, import_data) in resolved {
121 self.record_resolved_import(module_id, def, import, &import_data)
122 }
123 result
124 }
125
126 fn resolve_import(
127 &mut self,
128 module_id: CrateModuleId,
129 import: &raw::ImportData,
130 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
131 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
132 if import.is_extern_crate {
133 let res = self.def_map.resolve_name_in_extern_prelude(
134 &import
135 .path
136 .as_ident()
137 .expect("extern crate should have been desugared to one-element path"),
138 );
139 (res, ReachedFixedPoint::Yes)
140 } else {
141 let res =
142 self.def_map.resolve_path_fp(self.db, ResolveMode::Import, module_id, &import.path);
143
144 (res.resolved_def, res.reached_fixedpoint)
145 }
146 }
147
148 fn record_resolved_import(
149 &mut self,
150 module_id: CrateModuleId,
151 def: PerNs<ModuleDef>,
152 import_id: raw::ImportId,
153 import: &raw::ImportData,
154 ) {
155 if import.is_glob {
156 log::debug!("glob import: {:?}", import);
157 match def.take_types() {
158 Some(ModuleDef::Module(m)) => {
159 if import.is_prelude {
160 tested_by!(std_prelude);
161 self.def_map.prelude = Some(m);
162 } else if m.krate != self.def_map.krate {
163 tested_by!(glob_across_crates);
164 // glob import from other crate => we can just import everything once
165 let item_map = self.db.crate_def_map(m.krate);
166 let scope = &item_map[m.module_id].scope;
167 let items = scope
168 .items
169 .iter()
170 .map(|(name, res)| (name.clone(), res.clone()))
171 .collect::<Vec<_>>();
172 self.update(module_id, Some(import_id), &items);
173 } else {
174 // glob import from same crate => we do an initial
175 // import, and then need to propagate any further
176 // additions
177 let scope = &self.def_map[m.module_id].scope;
178 let items = scope
179 .items
180 .iter()
181 .map(|(name, res)| (name.clone(), res.clone()))
182 .collect::<Vec<_>>();
183 self.update(module_id, Some(import_id), &items);
184 // record the glob import in case we add further items
185 self.glob_imports
186 .entry(m.module_id)
187 .or_default()
188 .push((module_id, import_id));
189 }
190 }
191 Some(ModuleDef::Enum(e)) => {
192 tested_by!(glob_enum);
193 // glob import from enum => just import all the variants
194 let variants = e.variants(self.db);
195 let resolutions = variants
196 .into_iter()
197 .filter_map(|variant| {
198 let res = Resolution {
199 def: PerNs::both(variant.into(), variant.into()),
200 import: Some(import_id),
201 };
202 let name = variant.name(self.db)?;
203 Some((name, res))
204 })
205 .collect::<Vec<_>>();
206 self.update(module_id, Some(import_id), &resolutions);
207 }
208 Some(d) => {
209 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
210 }
211 None => {
212 log::debug!("glob import {:?} didn't resolve as type", import);
213 }
214 }
215 } else {
216 match import.path.segments.last() {
217 Some(last_segment) => {
218 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
219 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
220
221 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
222 if import.is_extern_crate && module_id == self.def_map.root {
223 if let Some(def) = def.take_types() {
224 self.def_map.extern_prelude.insert(name.clone(), def);
225 }
226 }
227 let resolution = Resolution { def, import: Some(import_id) };
228 self.update(module_id, Some(import_id), &[(name, resolution)]);
229 }
230 None => tested_by!(bogus_paths),
231 }
232 }
233 }
234
235 fn update(
236 &mut self,
237 module_id: CrateModuleId,
238 import: Option<raw::ImportId>,
239 resolutions: &[(Name, Resolution)],
240 ) {
241 self.update_recursive(module_id, import, resolutions, 0)
242 }
243
244 fn update_recursive(
245 &mut self,
246 module_id: CrateModuleId,
247 import: Option<raw::ImportId>,
248 resolutions: &[(Name, Resolution)],
249 depth: usize,
250 ) {
251 if depth > 100 {
252 // prevent stack overflows (but this shouldn't be possible)
253 panic!("infinite recursion in glob imports!");
254 }
255 let module_items = &mut self.def_map.modules[module_id].scope;
256 let mut changed = false;
257 for (name, res) in resolutions {
258 let existing = module_items.items.entry(name.clone()).or_default();
259 if existing.def.types.is_none() && res.def.types.is_some() {
260 existing.def.types = res.def.types;
261 existing.import = import.or(res.import);
262 changed = true;
263 }
264 if existing.def.values.is_none() && res.def.values.is_some() {
265 existing.def.values = res.def.values;
266 existing.import = import.or(res.import);
267 changed = true;
268 }
269 if existing.def.is_none()
270 && res.def.is_none()
271 && existing.import.is_none()
272 && res.import.is_some()
273 {
274 existing.import = res.import;
275 }
276 }
277 if !changed {
278 return;
279 }
280 let glob_imports = self
281 .glob_imports
282 .get(&module_id)
283 .into_iter()
284 .flat_map(|v| v.iter())
285 .cloned()
286 .collect::<Vec<_>>();
287 for (glob_importing_module, glob_import) in glob_imports {
288 // We pass the glob import so that the tracked import in those modules is that glob import
289 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
290 }
291 }
292
293 // XXX: this is just a pile of hacks now, because `PerNs` does not handle
294 // macro namespace.
295 fn resolve_macros(&mut self) -> ReachedFixedPoint {
296 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
297 let mut resolved = Vec::new();
298 let mut res = ReachedFixedPoint::Yes;
299 macros.retain(|(module_id, call_id, path, tt)| {
300 if path.segments.len() != 2 {
301 return true;
302 }
303 let crate_name = &path.segments[0].name;
304 let krate = match self.def_map.resolve_name_in_extern_prelude(crate_name).take_types() {
305 Some(ModuleDef::Module(m)) => m.krate(self.db),
306 _ => return true,
307 };
308 let krate = match krate {
309 Some(it) => it,
310 _ => return true,
311 };
312 res = ReachedFixedPoint::No;
313 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() {
315 resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone()));
316 }
317 false
318 });
319
320 for (module_id, macro_call_id, macro_def_id, arg) in resolved {
321 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg);
322 }
323 res
324 }
325
326 fn collect_macro_expansion(
327 &mut self,
328 module_id: CrateModuleId,
329 macro_call_id: MacroCallId,
330 macro_def_id: (Crate, CrateMacroId),
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(&macro_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 }
357
358 fn finish(self) -> CrateDefMap {
359 self.def_map
360 }
361}
362
363/// Walks a single module, populating defs, imports and macros
364struct ModCollector<'a, D> {
365 def_collector: D,
366 module_id: CrateModuleId,
367 file_id: HirFileId,
368 raw_items: &'a raw::RawItems,
369}
370
371impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>>
372where
373 DB: PersistentHirDatabase,
374{
375 fn collect(&mut self, items: &[raw::RawItem]) {
376 for item in items {
377 match *item {
378 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]),
379 raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push((
380 self.module_id,
381 import,
382 self.raw_items[import].clone(),
383 )),
384 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]),
385 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
386 }
387 }
388 }
389
390 fn collect_module(&mut self, module: &raw::ModuleData) {
391 match module {
392 // inline module, just recurse
393 raw::ModuleData::Definition { name, items, source_item_id } => {
394 let module_id = self.push_child_module(
395 name.clone(),
396 source_item_id.with_file_id(self.file_id),
397 None,
398 );
399 ModCollector {
400 def_collector: &mut *self.def_collector,
401 module_id,
402 file_id: self.file_id,
403 raw_items: self.raw_items,
404 }
405 .collect(&*items);
406 }
407 // out of line module, resovle, parse and recurse
408 raw::ModuleData::Declaration { name, source_item_id } => {
409 let source_item_id = source_item_id.with_file_id(self.file_id);
410 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
411 let (file_ids, problem) =
412 resolve_submodule(self.def_collector.db, self.file_id, name, is_root);
413
414 if let Some(problem) = problem {
415 self.def_collector.def_map.problems.add(source_item_id, problem)
416 }
417
418 if let Some(&file_id) = file_ids.first() {
419 let module_id =
420 self.push_child_module(name.clone(), source_item_id, Some(file_id));
421 let raw_items = self.def_collector.db.raw_items(file_id);
422 ModCollector {
423 def_collector: &mut *self.def_collector,
424 module_id,
425 file_id: file_id.into(),
426 raw_items: &raw_items,
427 }
428 .collect(raw_items.items())
429 }
430 }
431 }
432 }
433
434 fn push_child_module(
435 &mut self,
436 name: Name,
437 declaration: SourceItemId,
438 definition: Option<FileId>,
439 ) -> CrateModuleId {
440 let modules = &mut self.def_collector.def_map.modules;
441 let res = modules.alloc(ModuleData::default());
442 modules[res].parent = Some(self.module_id);
443 modules[res].declaration = Some(declaration);
444 modules[res].definition = definition;
445 modules[self.module_id].children.insert(name.clone(), res);
446 let resolution = Resolution {
447 def: PerNs::types(
448 Module { krate: self.def_collector.def_map.krate, module_id: res }.into(),
449 ),
450 import: None,
451 };
452 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
453 res
454 }
455
456 fn define_def(&mut self, def: &raw::DefData) {
457 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id };
458 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into());
459 macro_rules! id {
460 () => {
461 AstItemDef::from_source_item_id_unchecked(ctx, def.source_item_id)
462 };
463 }
464 let name = def.name.clone();
465 let def: PerNs<ModuleDef> = match def.kind {
466 raw::DefKind::Function => PerNs::values(Function { id: id!() }.into()),
467 raw::DefKind::Struct => {
468 let s = Struct { id: id!() }.into();
469 PerNs::both(s, s)
470 }
471 raw::DefKind::Enum => PerNs::types(Enum { id: id!() }.into()),
472 raw::DefKind::Const => PerNs::values(Const { id: id!() }.into()),
473 raw::DefKind::Static => PerNs::values(Static { id: id!() }.into()),
474 raw::DefKind::Trait => PerNs::types(Trait { id: id!() }.into()),
475 raw::DefKind::TypeAlias => PerNs::types(TypeAlias { id: id!() }.into()),
476 };
477 let resolution = Resolution { def, import: None };
478 self.def_collector.update(self.module_id, None, &[(name, resolution)])
479 }
480
481 fn collect_macro(&mut self, mac: &raw::MacroData) {
482 // Case 1: macro rules, define a macro in crate-global mutable scope
483 if is_macro_rules(&mac.path) {
484 if let Some(name) = &mac.name {
485 self.def_collector.define_macro(name.clone(), &mac.arg, mac.export)
486 }
487 return;
488 }
489
490 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id };
491 let macro_call_id = MacroCallLoc {
492 module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id },
493 source_item_id,
494 }
495 .id(self.def_collector.db);
496
497 // Case 2: try to expand macro_rules from this crate, triggering
498 // recursive item collection.
499 if let Some(&macro_id) =
500 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name))
501 {
502 self.def_collector.collect_macro_expansion(
503 self.module_id,
504 macro_call_id,
505 (self.def_collector.def_map.krate, macro_id),
506 mac.arg.clone(),
507 );
508 return;
509 }
510
511 // Case 3: path to a macro from another crate, expand during name resolution
512 self.def_collector.unexpanded_macros.push((
513 self.module_id,
514 macro_call_id,
515 mac.path.clone(),
516 mac.arg.clone(),
517 ))
518 }
519}
520
521fn is_macro_rules(path: &Path) -> bool {
522 path.as_ident().and_then(Name::as_known_name) == Some(KnownName::MacroRules)
523}
524
525fn resolve_submodule(
526 db: &impl PersistentHirDatabase,
527 file_id: HirFileId,
528 name: &Name,
529 is_root: bool,
530) -> (Vec<FileId>, Option<Problem>) {
531 // FIXME: handle submodules of inline modules properly
532 let file_id = file_id.original_file(db);
533 let source_root_id = db.file_source_root(file_id);
534 let path = db.file_relative_path(file_id);
535 let root = RelativePathBuf::default();
536 let dir_path = path.parent().unwrap_or(&root);
537 let mod_name = path.file_stem().unwrap_or("unknown");
538 let is_dir_owner = is_root || mod_name == "mod";
539
540 let file_mod = dir_path.join(format!("{}.rs", name));
541 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
542 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
543 let mut candidates = ArrayVec::<[_; 2]>::new();
544 if is_dir_owner {
545 candidates.push(file_mod.clone());
546 candidates.push(dir_mod);
547 } else {
548 candidates.push(file_dir_mod.clone());
549 };
550 let sr = db.source_root(source_root_id);
551 let points_to = candidates
552 .into_iter()
553 .filter_map(|path| sr.files.get(&path))
554 .map(|&it| it)
555 .collect::<Vec<_>>();
556 let problem = if points_to.is_empty() {
557 Some(Problem::UnresolvedModule {
558 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
559 })
560 } else {
561 None
562 };
563 (points_to, problem)
564}
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
deleted file mode 100644
index 56262ad6d..000000000
--- a/crates/ra_hir/src/nameres/lower.rs
+++ /dev/null
@@ -1,222 +0,0 @@
1use std::sync::Arc;
2
3use ra_syntax::{
4 AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner, NameOwner, AttrsOwner},
6};
7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap;
9
10use crate::{
11 SourceItemId, Path, ModuleSource, Name,
12 HirFileId, MacroCallLoc, AsName, PerNs, Function,
13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
14 ids::LocationCtx, PersistentHirDatabase,
15};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct ImportId(RawId);
19impl_arena_id!(ImportId);
20
21#[derive(Debug, PartialEq, Eq)]
22pub(super) struct ImportData {
23 pub(super) path: Path,
24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool,
26 pub(super) is_prelude: bool,
27 pub(super) is_extern_crate: bool,
28}
29
30/// A set of items and imports declared inside a module, without relation to
31/// other modules.
32///
33/// This sits in-between raw syntax and name resolution and allows us to avoid
34/// recomputing name res: if two instance of `InputModuleItems` are the same, we
35/// can avoid redoing name resolution.
36#[derive(Debug, Default, PartialEq, Eq)]
37pub struct LoweredModule {
38 pub(crate) declarations: FxHashMap<Name, PerNs<ModuleDef>>,
39 pub(super) imports: Arena<ImportId, ImportData>,
40}
41
42#[derive(Debug, Default, PartialEq, Eq)]
43pub struct ImportSourceMap {
44 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
45}
46
47impl ImportSourceMap {
48 fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
49 self.map.insert(import, AstPtr::new(segment))
50 }
51
52 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
53 let file = match source {
54 ModuleSource::SourceFile(file) => &*file,
55 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
56 };
57
58 self.map[import].to_node(file).to_owned()
59 }
60}
61
62impl LoweredModule {
63 pub(crate) fn lower_module_query(
64 db: &impl PersistentHirDatabase,
65 module: Module,
66 ) -> Arc<LoweredModule> {
67 db.lower_module_with_source_map(module).0
68 }
69
70 pub(crate) fn lower_module_with_source_map_query(
71 db: &impl PersistentHirDatabase,
72 module: Module,
73 ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>) {
74 let (file_id, source) = module.definition_source(db);
75 let file_id: HirFileId = file_id.into();
76 let mut source_map = ImportSourceMap::default();
77 let mut res = LoweredModule::default();
78 match source {
79 ModuleSource::SourceFile(it) => {
80 res.fill(&mut source_map, db, module, file_id, &mut it.items_with_macros())
81 }
82 ModuleSource::Module(it) => {
83 if let Some(item_list) = it.item_list() {
84 res.fill(
85 &mut source_map,
86 db,
87 module,
88 file_id,
89 &mut item_list.items_with_macros(),
90 )
91 }
92 }
93 };
94 (Arc::new(res), Arc::new(source_map))
95 }
96
97 fn fill(
98 &mut self,
99 source_map: &mut ImportSourceMap,
100 db: &impl PersistentHirDatabase,
101 module: Module,
102 file_id: HirFileId,
103 items: &mut Iterator<Item = ast::ItemOrMacro>,
104 ) {
105 let file_items = db.file_items(file_id);
106
107 for item in items {
108 match item {
109 ast::ItemOrMacro::Item(it) => {
110 self.add_def_id(source_map, db, module, file_id, it);
111 }
112 ast::ItemOrMacro::Macro(macro_call) => {
113 let item_id = file_items.id_of_unchecked(macro_call.syntax());
114 let loc =
115 MacroCallLoc { module, source_item_id: SourceItemId { file_id, item_id } };
116 let id = loc.id(db);
117 let file_id = HirFileId::from(id);
118 //FIXME: expand recursively
119 for item in db.hir_parse(file_id).items() {
120 self.add_def_id(source_map, db, module, file_id, item);
121 }
122 }
123 }
124 }
125 }
126
127 fn add_def_id(
128 &mut self,
129 source_map: &mut ImportSourceMap,
130 db: &impl PersistentHirDatabase,
131 module: Module,
132 file_id: HirFileId,
133 item: &ast::ModuleItem,
134 ) {
135 let ctx = LocationCtx::new(db, module, file_id);
136 match item.kind() {
137 ast::ModuleItemKind::StructDef(it) => {
138 if let Some(name) = it.name() {
139 let s = Struct { id: ctx.to_def(it) };
140 let s: ModuleDef = s.into();
141 self.declarations.insert(name.as_name(), PerNs::both(s, s));
142 }
143 }
144 ast::ModuleItemKind::EnumDef(it) => {
145 if let Some(name) = it.name() {
146 let e = Enum { id: ctx.to_def(it) };
147 let e: ModuleDef = e.into();
148 self.declarations.insert(name.as_name(), PerNs::types(e));
149 }
150 }
151 ast::ModuleItemKind::FnDef(it) => {
152 if let Some(name) = it.name() {
153 let func = Function { id: ctx.to_def(it) };
154 self.declarations.insert(name.as_name(), PerNs::values(func.into()));
155 }
156 }
157 ast::ModuleItemKind::TraitDef(it) => {
158 if let Some(name) = it.name() {
159 let t = Trait { id: ctx.to_def(it) };
160 self.declarations.insert(name.as_name(), PerNs::types(t.into()));
161 }
162 }
163 ast::ModuleItemKind::TypeAliasDef(it) => {
164 if let Some(name) = it.name() {
165 let t = TypeAlias { id: ctx.to_def(it) };
166 self.declarations.insert(name.as_name(), PerNs::types(t.into()));
167 }
168 }
169 ast::ModuleItemKind::ImplBlock(_) => {
170 // impls don't define items
171 }
172 ast::ModuleItemKind::UseItem(it) => {
173 self.add_use_item(source_map, it);
174 }
175 ast::ModuleItemKind::ExternCrateItem(it) => {
176 if let Some(name_ref) = it.name_ref() {
177 let path = Path::from_name_ref(name_ref);
178 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
179 self.imports.alloc(ImportData {
180 path,
181 alias,
182 is_glob: false,
183 is_prelude: false,
184 is_extern_crate: true,
185 });
186 }
187 }
188 ast::ModuleItemKind::ConstDef(it) => {
189 if let Some(name) = it.name() {
190 let c = Const { id: ctx.to_def(it) };
191 self.declarations.insert(name.as_name(), PerNs::values(c.into()));
192 }
193 }
194 ast::ModuleItemKind::StaticDef(it) => {
195 if let Some(name) = it.name() {
196 let s = Static { id: ctx.to_def(it) };
197 self.declarations.insert(name.as_name(), PerNs::values(s.into()));
198 }
199 }
200 ast::ModuleItemKind::Module(_) => {
201 // modules are handled separately directly by name res
202 }
203 };
204 }
205
206 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
207 let is_prelude =
208 item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
209 Path::expand_use_item(item, |path, segment, alias| {
210 let import = self.imports.alloc(ImportData {
211 path,
212 alias,
213 is_glob: segment.is_none(),
214 is_prelude,
215 is_extern_crate: false,
216 });
217 if let Some(segment) = segment {
218 source_map.insert(import, segment)
219 }
220 })
221 }
222}
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs
new file mode 100644
index 000000000..c40a3ff9d
--- /dev/null
+++ b/crates/ra_hir/src/nameres/per_ns.rs
@@ -0,0 +1,78 @@
1#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2pub enum Namespace {
3 Types,
4 Values,
5}
6
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub struct PerNs<T> {
9 pub types: Option<T>,
10 pub values: Option<T>,
11}
12
13impl<T> Default for PerNs<T> {
14 fn default() -> Self {
15 PerNs { types: None, values: None }
16 }
17}
18
19impl<T> PerNs<T> {
20 pub fn none() -> PerNs<T> {
21 PerNs { types: None, values: None }
22 }
23
24 pub fn values(t: T) -> PerNs<T> {
25 PerNs { types: None, values: Some(t) }
26 }
27
28 pub fn types(t: T) -> PerNs<T> {
29 PerNs { types: Some(t), values: None }
30 }
31
32 pub fn both(types: T, values: T) -> PerNs<T> {
33 PerNs { types: Some(types), values: Some(values) }
34 }
35
36 pub fn is_none(&self) -> bool {
37 self.types.is_none() && self.values.is_none()
38 }
39
40 pub fn is_both(&self) -> bool {
41 self.types.is_some() && self.values.is_some()
42 }
43
44 pub fn take(self, namespace: Namespace) -> Option<T> {
45 match namespace {
46 Namespace::Types => self.types,
47 Namespace::Values => self.values,
48 }
49 }
50
51 pub fn take_types(self) -> Option<T> {
52 self.take(Namespace::Types)
53 }
54
55 pub fn take_values(self) -> Option<T> {
56 self.take(Namespace::Values)
57 }
58
59 pub fn get(&self, namespace: Namespace) -> Option<&T> {
60 self.as_ref().take(namespace)
61 }
62
63 pub fn as_ref(&self) -> PerNs<&T> {
64 PerNs { types: self.types.as_ref(), values: self.values.as_ref() }
65 }
66
67 pub fn or(self, other: PerNs<T>) -> PerNs<T> {
68 PerNs { types: self.types.or(other.types), values: self.values.or(other.values) }
69 }
70
71 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
72 PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) }
73 }
74
75 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
76 PerNs { types: self.types.map(&f), values: self.values.map(&f) }
77 }
78}
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
new file mode 100644
index 000000000..3226bbf0d
--- /dev/null
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -0,0 +1,322 @@
1use std::{
2 sync::Arc,
3 ops::Index,
4};
5
6use test_utils::tested_by;
7use ra_db::FileId;
8use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
9use ra_syntax::{
10 AstNode, SourceFile, AstPtr, TreeArc,
11 ast::{self, NameOwner, AttrsOwner},
12};
13
14use crate::{
15 PersistentHirDatabase, Name, AsName, Path, HirFileId, ModuleSource,
16 ids::{SourceFileItemId, SourceFileItems},
17};
18
19#[derive(Debug, Default, PartialEq, Eq)]
20pub struct RawItems {
21 modules: Arena<Module, ModuleData>,
22 imports: Arena<ImportId, ImportData>,
23 defs: Arena<Def, DefData>,
24 macros: Arena<Macro, MacroData>,
25 /// items for top-level module
26 items: Vec<RawItem>,
27}
28
29#[derive(Debug, Default, PartialEq, Eq)]
30pub struct ImportSourceMap {
31 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
32}
33
34impl ImportSourceMap {
35 pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
36 self.map.insert(import, AstPtr::new(segment))
37 }
38
39 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
40 let file = match source {
41 ModuleSource::SourceFile(file) => &*file,
42 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
43 };
44
45 self.map[import].to_node(file).to_owned()
46 }
47}
48
49impl RawItems {
50 pub(crate) fn raw_items_query(
51 db: &impl PersistentHirDatabase,
52 file_id: FileId,
53 ) -> Arc<RawItems> {
54 db.raw_items_with_source_map(file_id).0
55 }
56
57 pub(crate) fn raw_items_with_source_map_query(
58 db: &impl PersistentHirDatabase,
59 file_id: FileId,
60 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
61 let mut collector = RawItemsCollector {
62 raw_items: RawItems::default(),
63 source_file_items: db.file_items(file_id.into()),
64 source_map: ImportSourceMap::default(),
65 };
66 let source_file = db.parse(file_id);
67 collector.process_module(None, &*source_file);
68 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
69 }
70
71 pub(crate) fn items(&self) -> &[RawItem] {
72 &self.items
73 }
74
75 // We can't use queries during name resolution for fear of cycles, so this
76 // is a query-less variant of the above function.
77 pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
78 let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
79 let mut collector = RawItemsCollector {
80 raw_items: RawItems::default(),
81 source_file_items: Arc::new(source_file_items),
82 source_map: ImportSourceMap::default(),
83 };
84 collector.process_module(None, &*source_file);
85 collector.raw_items
86 }
87}
88
89impl Index<Module> for RawItems {
90 type Output = ModuleData;
91 fn index(&self, idx: Module) -> &ModuleData {
92 &self.modules[idx]
93 }
94}
95
96impl Index<ImportId> for RawItems {
97 type Output = ImportData;
98 fn index(&self, idx: ImportId) -> &ImportData {
99 &self.imports[idx]
100 }
101}
102
103impl Index<Def> for RawItems {
104 type Output = DefData;
105 fn index(&self, idx: Def) -> &DefData {
106 &self.defs[idx]
107 }
108}
109
110impl Index<Macro> for RawItems {
111 type Output = MacroData;
112 fn index(&self, idx: Macro) -> &MacroData {
113 &self.macros[idx]
114 }
115}
116
117#[derive(Debug, PartialEq, Eq, Clone, Copy)]
118pub(crate) enum RawItem {
119 Module(Module),
120 Import(ImportId),
121 Def(Def),
122 Macro(Macro),
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126pub(crate) struct Module(RawId);
127impl_arena_id!(Module);
128
129#[derive(Debug, PartialEq, Eq)]
130pub(crate) enum ModuleData {
131 Declaration { name: Name, source_item_id: SourceFileItemId },
132 Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> },
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
136pub struct ImportId(RawId);
137impl_arena_id!(ImportId);
138
139#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct ImportData {
141 pub(crate) path: Path,
142 pub(crate) alias: Option<Name>,
143 pub(crate) is_glob: bool,
144 pub(crate) is_prelude: bool,
145 pub(crate) is_extern_crate: bool,
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
149pub(crate) struct Def(RawId);
150impl_arena_id!(Def);
151
152#[derive(Debug, PartialEq, Eq)]
153pub(crate) struct DefData {
154 pub(crate) source_item_id: SourceFileItemId,
155 pub(crate) name: Name,
156 pub(crate) kind: DefKind,
157}
158
159#[derive(Debug, PartialEq, Eq, Clone, Copy)]
160pub(crate) enum DefKind {
161 Function,
162 Struct,
163 Enum,
164 Const,
165 Static,
166 Trait,
167 TypeAlias,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub(crate) struct Macro(RawId);
172impl_arena_id!(Macro);
173
174#[derive(Debug, PartialEq, Eq)]
175pub(crate) struct MacroData {
176 pub(crate) source_item_id: SourceFileItemId,
177 pub(crate) path: Path,
178 pub(crate) name: Option<Name>,
179 pub(crate) arg: tt::Subtree,
180 pub(crate) export: bool,
181}
182
183struct RawItemsCollector {
184 raw_items: RawItems,
185 source_file_items: Arc<SourceFileItems>,
186 source_map: ImportSourceMap,
187}
188
189impl RawItemsCollector {
190 fn process_module(&mut self, current_module: Option<Module>, body: &impl ast::ModuleItemOwner) {
191 for item_or_macro in body.items_with_macros() {
192 match item_or_macro {
193 ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
194 ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
195 }
196 }
197 }
198
199 fn add_item(&mut self, current_module: Option<Module>, item: &ast::ModuleItem) {
200 let (kind, name) = match item.kind() {
201 ast::ModuleItemKind::Module(module) => {
202 self.add_module(current_module, module);
203 return;
204 }
205 ast::ModuleItemKind::UseItem(use_item) => {
206 self.add_use_item(current_module, use_item);
207 return;
208 }
209 ast::ModuleItemKind::ExternCrateItem(extern_crate) => {
210 self.add_extern_crate_item(current_module, extern_crate);
211 return;
212 }
213 ast::ModuleItemKind::ImplBlock(_) => {
214 // impls don't participate in name resolution
215 return;
216 }
217 ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()),
218 ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()),
219 ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()),
220 ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()),
221 ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()),
222 ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()),
223 ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()),
224 };
225 if let Some(name) = name {
226 let name = name.as_name();
227 let source_item_id = self.source_file_items.id_of_unchecked(item.syntax());
228 let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
229 self.push_item(current_module, RawItem::Def(def))
230 }
231 }
232
233 fn add_module(&mut self, current_module: Option<Module>, module: &ast::Module) {
234 let name = match module.name() {
235 Some(it) => it.as_name(),
236 None => return,
237 };
238 let source_item_id = self.source_file_items.id_of_unchecked(module.syntax());
239 if module.has_semi() {
240 let item =
241 self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
242 self.push_item(current_module, RawItem::Module(item));
243 return;
244 }
245
246 if let Some(item_list) = module.item_list() {
247 let item = self.raw_items.modules.alloc(ModuleData::Definition {
248 name,
249 source_item_id,
250 items: Vec::new(),
251 });
252 self.process_module(Some(item), item_list);
253 self.push_item(current_module, RawItem::Module(item));
254 return;
255 }
256 tested_by!(name_res_works_for_broken_modules);
257 }
258
259 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
260 let is_prelude = use_item.has_atom_attr("prelude_import");
261
262 Path::expand_use_item(use_item, |path, segment, alias| {
263 let import = self.raw_items.imports.alloc(ImportData {
264 path,
265 alias,
266 is_glob: segment.is_none(),
267 is_prelude,
268 is_extern_crate: false,
269 });
270 if let Some(segment) = segment {
271 self.source_map.insert(import, segment)
272 }
273 self.push_item(current_module, RawItem::Import(import))
274 })
275 }
276
277 fn add_extern_crate_item(
278 &mut self,
279 current_module: Option<Module>,
280 extern_crate: &ast::ExternCrateItem,
281 ) {
282 if let Some(name_ref) = extern_crate.name_ref() {
283 let path = Path::from_name_ref(name_ref);
284 let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
285 let import = self.raw_items.imports.alloc(ImportData {
286 path,
287 alias,
288 is_glob: false,
289 is_prelude: false,
290 is_extern_crate: true,
291 });
292 self.push_item(current_module, RawItem::Import(import))
293 }
294 }
295
296 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
297 let (path, arg) = match (
298 m.path().and_then(Path::from_ast),
299 m.token_tree().and_then(mbe::ast_to_token_tree),
300 ) {
301 (Some(path), Some((token_tree, _token_map))) => (path, token_tree),
302 _ => return,
303 };
304
305 let name = m.name().map(|it| it.as_name());
306 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
307 let export = m.has_atom_attr("macro_export");
308 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export });
309 self.push_item(current_module, RawItem::Macro(m));
310 }
311
312 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
313 match current_module {
314 Some(module) => match &mut self.raw_items.modules[module] {
315 ModuleData::Definition { items, .. } => items,
316 ModuleData::Declaration { .. } => unreachable!(),
317 },
318 None => &mut self.raw_items.items,
319 }
320 .push(item)
321 }
322}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 9b151bb0c..ac9b88520 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -1,34 +1,43 @@
1mod macros;
2mod globs;
3mod incremental;
4
1use std::sync::Arc; 5use std::sync::Arc;
2 6
3use ra_db::SourceDatabase; 7use ra_db::SourceDatabase;
4use test_utils::{assert_eq_text, covers}; 8use test_utils::covers;
5 9use insta::assert_snapshot_matches;
6use crate::{ 10
7 ItemMap, 11use crate::{Crate, mock::{MockDatabase, CrateGraphFixture}, nameres::Resolution};
8 PersistentHirDatabase, 12
9 mock::MockDatabase, 13use super::*;
10 module_tree::ModuleId, 14
11}; 15fn compute_crate_def_map(fixture: &str, graph: Option<CrateGraphFixture>) -> Arc<CrateDefMap> {
12use super::Resolution; 16 let mut db = MockDatabase::with_files(fixture);
13 17 if let Some(graph) = graph {
14fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) { 18 db.set_crate_graph_from_fixture(graph);
15 let (db, pos) = MockDatabase::with_position(fixture); 19 }
16 let module = crate::source_binder::module_from_position(&db, pos).unwrap(); 20 let crate_id = db.crate_graph().iter().next().unwrap();
17 let krate = module.krate(&db).unwrap(); 21 let krate = Crate { crate_id };
18 let module_id = module.module_id; 22 db.crate_def_map(krate)
19 (db.item_map(krate), module_id)
20} 23}
21 24
22fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { 25fn render_crate_def_map(map: &CrateDefMap) -> String {
23 let mut lines = map[module_id] 26 let mut buf = String::new();
24 .items 27 go(&mut buf, map, "\ncrate", map.root);
25 .iter() 28 return buf;
26 .map(|(name, res)| format!("{}: {}", name, dump_resolution(res))) 29
27 .collect::<Vec<_>>(); 30 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) {
28 lines.sort(); 31 *buf += path;
29 let actual = lines.join("\n"); 32 *buf += "\n";
30 let expected = expected.trim().lines().map(|it| it.trim()).collect::<Vec<_>>().join("\n"); 33 for (name, res) in map.modules[module].scope.items.iter() {
31 assert_eq_text!(&expected, &actual); 34 *buf += &format!("{}: {}\n", name, dump_resolution(res))
35 }
36 for (name, child) in map.modules[module].children.iter() {
37 let path = path.to_string() + &format!("::{}", name);
38 go(buf, map, &path, *child);
39 }
40 }
32 41
33 fn dump_resolution(resolution: &Resolution) -> &'static str { 42 fn dump_resolution(resolution: &Resolution) -> &'static str {
34 match (resolution.def.types.is_some(), resolution.def.values.is_some()) { 43 match (resolution.def.types.is_some(), resolution.def.values.is_some()) {
@@ -40,66 +49,112 @@ fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
40 } 49 }
41} 50}
42 51
52fn def_map(fixtute: &str) -> String {
53 let dm = compute_crate_def_map(fixtute, None);
54 render_crate_def_map(&dm)
55}
56
57fn def_map_with_crate_graph(fixtute: &str, graph: CrateGraphFixture) -> String {
58 let dm = compute_crate_def_map(fixtute, Some(graph));
59 render_crate_def_map(&dm)
60}
61
43#[test] 62#[test]
44fn item_map_smoke_test() { 63fn crate_def_map_smoke_test() {
45 let (item_map, module_id) = item_map( 64 let map = def_map(
46 " 65 "
47 //- /lib.rs 66 //- /lib.rs
48 mod foo; 67 mod foo;
49 68 struct S;
50 use crate::foo::bar::Baz; 69 use crate::foo::bar::E;
51 <|> 70 use self::E::V;
52 71
53 //- /foo/mod.rs 72 //- /foo/mod.rs
54 pub mod bar; 73 pub mod bar;
74 fn f() {}
55 75
56 //- /foo/bar.rs 76 //- /foo/bar.rs
57 pub struct Baz; 77 pub struct Baz;
58 ", 78 enum E { V }
79 ",
59 ); 80 );
60 check_module_item_map( 81 assert_snapshot_matches!(map, @r###"
61 &item_map, 82crate
62 module_id, 83V: t v
84E: t
85foo: t
86S: t v
87
88crate::foo
89bar: t
90f: v
91
92crate::foo::bar
93Baz: t v
94E: t
95"###
96 )
97}
98
99#[test]
100fn bogus_paths() {
101 covers!(bogus_paths);
102 let map = def_map(
63 " 103 "
64 Baz: t v 104 //- /lib.rs
65 foo: t 105 mod foo;
106 struct S;
107 use self;
108
109 //- /foo/mod.rs
110 use super;
111 use crate;
112
66 ", 113 ",
67 ); 114 );
115 assert_snapshot_matches!(map, @r###"
116crate
117foo: t
118S: t v
119
120crate::foo
121"###
122 )
68} 123}
69 124
70#[test] 125#[test]
71fn use_as() { 126fn use_as() {
72 let (item_map, module_id) = item_map( 127 let map = def_map(
73 " 128 "
74 //- /lib.rs 129 //- /lib.rs
75 mod foo; 130 mod foo;
76 131
77 use crate::foo::Baz as Foo; 132 use crate::foo::Baz as Foo;
78 <|>
79 133
80 //- /foo/mod.rs 134 //- /foo/mod.rs
81 pub struct Baz; 135 pub struct Baz;
82 ",
83 );
84 check_module_item_map(
85 &item_map,
86 module_id,
87 "
88 Foo: t v
89 foo: t
90 ", 136 ",
91 ); 137 );
138 assert_snapshot_matches!(map,
139 @r###"
140crate
141Foo: t v
142foo: t
143
144crate::foo
145Baz: t v
146"###
147 );
92} 148}
93 149
94#[test] 150#[test]
95fn use_trees() { 151fn use_trees() {
96 let (item_map, module_id) = item_map( 152 let map = def_map(
97 " 153 "
98 //- /lib.rs 154 //- /lib.rs
99 mod foo; 155 mod foo;
100 156
101 use crate::foo::bar::{Baz, Quux}; 157 use crate::foo::bar::{Baz, Quux};
102 <|>
103 158
104 //- /foo/mod.rs 159 //- /foo/mod.rs
105 pub mod bar; 160 pub mod bar;
@@ -107,28 +162,33 @@ fn use_trees() {
107 //- /foo/bar.rs 162 //- /foo/bar.rs
108 pub struct Baz; 163 pub struct Baz;
109 pub enum Quux {}; 164 pub enum Quux {};
110 ",
111 );
112 check_module_item_map(
113 &item_map,
114 module_id,
115 "
116 Baz: t v
117 Quux: t
118 foo: t
119 ", 165 ",
120 ); 166 );
167 assert_snapshot_matches!(map,
168 @r###"
169crate
170Quux: t
171Baz: t v
172foo: t
173
174crate::foo
175bar: t
176
177crate::foo::bar
178Quux: t
179Baz: t v
180"###
181 );
121} 182}
122 183
123#[test] 184#[test]
124fn re_exports() { 185fn re_exports() {
125 let (item_map, module_id) = item_map( 186 let map = def_map(
126 " 187 "
127 //- /lib.rs 188 //- /lib.rs
128 mod foo; 189 mod foo;
129 190
130 use self::foo::Baz; 191 use self::foo::Baz;
131 <|>
132 192
133 //- /foo/mod.rs 193 //- /foo/mod.rs
134 pub mod bar; 194 pub mod bar;
@@ -137,137 +197,73 @@ fn re_exports() {
137 197
138 //- /foo/bar.rs 198 //- /foo/bar.rs
139 pub struct Baz; 199 pub struct Baz;
140 ",
141 );
142 check_module_item_map(
143 &item_map,
144 module_id,
145 "
146 Baz: t v
147 foo: t
148 ", 200 ",
149 ); 201 );
150} 202 assert_snapshot_matches!(map,
203 @r###"
204crate
205Baz: t v
206foo: t
151 207
152#[test] 208crate::foo
153fn glob_1() { 209bar: t
154 let (item_map, module_id) = item_map( 210Baz: t v
155 "
156 //- /lib.rs
157 mod foo;
158 use foo::*;
159 <|>
160
161 //- /foo/mod.rs
162 pub mod bar;
163 pub use self::bar::Baz;
164 pub struct Foo;
165 211
166 //- /foo/bar.rs 212crate::foo::bar
167 pub struct Baz; 213Baz: t v
168 ", 214"###
169 );
170 check_module_item_map(
171 &item_map,
172 module_id,
173 "
174 Baz: t v
175 Foo: t v
176 bar: t
177 foo: t
178 ",
179 ); 215 );
180} 216}
181 217
182#[test] 218#[test]
183fn glob_2() { 219fn std_prelude() {
184 let (item_map, module_id) = item_map( 220 covers!(std_prelude);
185 " 221 let map = def_map_with_crate_graph(
186 //- /lib.rs
187 mod foo;
188 use foo::*;
189 <|>
190
191 //- /foo/mod.rs
192 pub mod bar;
193 pub use self::bar::*;
194 pub struct Foo;
195
196 //- /foo/bar.rs
197 pub struct Baz;
198 pub use super::*;
199 ",
200 );
201 check_module_item_map(
202 &item_map,
203 module_id,
204 " 222 "
205 Baz: t v 223 //- /main.rs
206 Foo: t v 224 use Foo::*;
207 bar: t
208 foo: t
209 ",
210 );
211}
212 225
213#[test]
214fn glob_enum() {
215 covers!(glob_enum);
216 let (item_map, module_id) = item_map(
217 "
218 //- /lib.rs 226 //- /lib.rs
219 enum Foo { 227 mod prelude;
220 Bar, Baz 228 #[prelude_import]
221 } 229 use prelude::*;
222 use self::Foo::*; 230
223 <|> 231 //- /prelude.rs
224 ", 232 pub enum Foo { Bar, Baz };
225 );
226 check_module_item_map(
227 &item_map,
228 module_id,
229 "
230 Bar: t v
231 Baz: t v
232 Foo: t
233 ", 233 ",
234 crate_graph! {
235 "main": ("/main.rs", ["test_crate"]),
236 "test_crate": ("/lib.rs", []),
237 },
234 ); 238 );
239 assert_snapshot_matches!(map, @r###"
240crate
241Bar: t v
242Baz: t v
243"###);
235} 244}
236 245
237#[test] 246#[test]
238fn glob_across_crates() { 247fn can_import_enum_variant() {
239 covers!(glob_across_crates); 248 covers!(can_import_enum_variant);
240 let mut db = MockDatabase::with_files( 249 let map = def_map(
241 " 250 "
242 //- /main.rs
243 use test_crate::*;
244
245 //- /lib.rs 251 //- /lib.rs
246 pub struct Baz; 252 enum E { V }
253 use self::E::V;
247 ", 254 ",
248 ); 255 );
249 db.set_crate_graph_from_fixture(crate_graph! { 256 assert_snapshot_matches!(map, @r###"
250 "main": ("/main.rs", ["test_crate"]), 257crate
251 "test_crate": ("/lib.rs", []), 258V: t v
252 }); 259E: t
253 let main_id = db.file_id_of("/main.rs"); 260"###
254
255 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
256 let krate = module.krate(&db).unwrap();
257 let item_map = db.item_map(krate);
258
259 check_module_item_map(
260 &item_map,
261 module.module_id,
262 "
263 Baz: t v
264 ",
265 ); 261 );
266} 262}
267 263
268#[test] 264#[test]
269fn edition_2015_imports() { 265fn edition_2015_imports() {
270 let mut db = MockDatabase::with_files( 266 let map = def_map_with_crate_graph(
271 " 267 "
272 //- /main.rs 268 //- /main.rs
273 mod foo; 269 mod foo;
@@ -282,31 +278,32 @@ fn edition_2015_imports() {
282 278
283 //- /lib.rs 279 //- /lib.rs
284 struct FromLib; 280 struct FromLib;
285 ",
286 );
287 db.set_crate_graph_from_fixture(crate_graph! {
288 "main": ("/main.rs", "2015", ["other_crate"]),
289 "other_crate": ("/lib.rs", "2018", []),
290 });
291 let foo_id = db.file_id_of("/foo.rs");
292
293 let module = crate::source_binder::module_from_file_id(&db, foo_id).unwrap();
294 let krate = module.krate(&db).unwrap();
295 let item_map = db.item_map(krate);
296
297 check_module_item_map(
298 &item_map,
299 module.module_id,
300 "
301 Bar: t v
302 FromLib: t v
303 ", 281 ",
282 crate_graph! {
283 "main": ("/main.rs", "2015", ["other_crate"]),
284 "other_crate": ("/lib.rs", "2018", []),
285 },
286 );
287
288 assert_snapshot_matches!(map,
289 @r###"
290crate
291bar: t
292foo: t
293
294crate::bar
295Bar: t v
296
297crate::foo
298FromLib: t v
299Bar: t v
300"###
304 ); 301 );
305} 302}
306 303
307#[test] 304#[test]
308fn module_resolution_works_for_non_standard_filenames() { 305fn module_resolution_works_for_non_standard_filenames() {
309 let mut db = MockDatabase::with_files( 306 let map = def_map_with_crate_graph(
310 " 307 "
311 //- /my_library.rs 308 //- /my_library.rs
312 mod foo; 309 mod foo;
@@ -315,73 +312,32 @@ fn module_resolution_works_for_non_standard_filenames() {
315 //- /foo/mod.rs 312 //- /foo/mod.rs
316 pub struct Bar; 313 pub struct Bar;
317 ", 314 ",
315 crate_graph! {
316 "my_library": ("/my_library.rs", []),
317 },
318 ); 318 );
319 db.set_crate_graph_from_fixture(crate_graph! {
320 "my_library": ("/my_library.rs", []),
321 });
322 let file_id = db.file_id_of("/my_library.rs");
323
324 let module = crate::source_binder::module_from_file_id(&db, file_id).unwrap();
325 let krate = module.krate(&db).unwrap();
326 let module_id = module.module_id;
327 let item_map = db.item_map(krate);
328 check_module_item_map(
329 &item_map,
330 module_id,
331 "
332 Bar: t v
333 foo: t
334 ",
335 );
336}
337 319
338#[test] 320 assert_snapshot_matches!(map,
339fn std_prelude() { 321 @r###"
340 covers!(std_prelude); 322crate
341 let mut db = MockDatabase::with_files( 323Bar: t v
342 " 324foo: t
343 //- /main.rs
344 use Foo::*;
345
346 //- /lib.rs
347 mod prelude;
348 #[prelude_import]
349 use prelude::*;
350 325
351 //- /prelude.rs 326crate::foo
352 pub enum Foo { Bar, Baz }; 327Bar: t v
353 ", 328"###
354 );
355 db.set_crate_graph_from_fixture(crate_graph! {
356 "main": ("/main.rs", ["test_crate"]),
357 "test_crate": ("/lib.rs", []),
358 });
359 let main_id = db.file_id_of("/main.rs");
360
361 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
362 let krate = module.krate(&db).unwrap();
363 let item_map = db.item_map(krate);
364
365 check_module_item_map(
366 &item_map,
367 module.module_id,
368 "
369 Bar: t v
370 Baz: t v
371 ",
372 ); 329 );
373} 330}
374 331
375#[test] 332#[test]
376fn name_res_works_for_broken_modules() { 333fn name_res_works_for_broken_modules() {
377 covers!(name_res_works_for_broken_modules); 334 covers!(name_res_works_for_broken_modules);
378 let (item_map, module_id) = item_map( 335 let map = def_map(
379 " 336 "
380 //- /lib.rs 337 //- /lib.rs
381 mod foo // no `;`, no body 338 mod foo // no `;`, no body
382 339
383 use self::foo::Baz; 340 use self::foo::Baz;
384 <|>
385 341
386 //- /foo/mod.rs 342 //- /foo/mod.rs
387 pub mod bar; 343 pub mod bar;
@@ -390,65 +346,47 @@ fn name_res_works_for_broken_modules() {
390 346
391 //- /foo/bar.rs 347 //- /foo/bar.rs
392 pub struct Baz; 348 pub struct Baz;
393 ",
394 );
395 check_module_item_map(
396 &item_map,
397 module_id,
398 "
399 Baz: _
400 ", 349 ",
401 ); 350 );
402} 351 assert_snapshot_matches!(map,
403 352 @r###"
404#[test] 353crate
405fn item_map_using_self() { 354Baz: _
406 let (item_map, module_id) = item_map( 355"###
407 "
408 //- /lib.rs
409 mod foo;
410 use crate::foo::bar::Baz::{self};
411 <|>
412 //- /foo/mod.rs
413 pub mod bar;
414 //- /foo/bar.rs
415 pub struct Baz;
416 ",
417 );
418 check_module_item_map(
419 &item_map,
420 module_id,
421 "
422 Baz: t v
423 foo: t
424 ",
425 ); 356 );
426} 357}
427 358
428#[test] 359#[test]
429fn item_map_enum_importing() { 360fn item_map_using_self() {
430 covers!(item_map_enum_importing); 361 let map = def_map(
431 let (item_map, module_id) = item_map(
432 " 362 "
433 //- /lib.rs 363 //- /lib.rs
434 enum E { V } 364 mod foo;
435 use self::E::V; 365 use crate::foo::bar::Baz::{self};
436 <|> 366 //- /foo/mod.rs
367 pub mod bar;
368 //- /foo/bar.rs
369 pub struct Baz;
437 ", 370 ",
438 ); 371 );
439 check_module_item_map( 372 assert_snapshot_matches!(map,
440 &item_map, 373 @r###"
441 module_id, 374crate
442 " 375Baz: t v
443 E: t 376foo: t
444 V: t v 377
445 ", 378crate::foo
379bar: t
380
381crate::foo::bar
382Baz: t v
383"###
446 ); 384 );
447} 385}
448 386
449#[test] 387#[test]
450fn item_map_across_crates() { 388fn item_map_across_crates() {
451 let mut db = MockDatabase::with_files( 389 let map = def_map_with_crate_graph(
452 " 390 "
453 //- /main.rs 391 //- /main.rs
454 use test_crate::Baz; 392 use test_crate::Baz;
@@ -456,29 +394,23 @@ fn item_map_across_crates() {
456 //- /lib.rs 394 //- /lib.rs
457 pub struct Baz; 395 pub struct Baz;
458 ", 396 ",
397 crate_graph! {
398 "main": ("/main.rs", ["test_crate"]),
399 "test_crate": ("/lib.rs", []),
400 },
459 ); 401 );
460 db.set_crate_graph_from_fixture(crate_graph! { 402
461 "main": ("/main.rs", ["test_crate"]), 403 assert_snapshot_matches!(map,
462 "test_crate": ("/lib.rs", []), 404 @r###"
463 }); 405crate
464 let main_id = db.file_id_of("/main.rs"); 406Baz: t v
465 407"###
466 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
467 let krate = module.krate(&db).unwrap();
468 let item_map = db.item_map(krate);
469
470 check_module_item_map(
471 &item_map,
472 module.module_id,
473 "
474 Baz: t v
475 ",
476 ); 408 );
477} 409}
478 410
479#[test] 411#[test]
480fn extern_crate_rename() { 412fn extern_crate_rename() {
481 let mut db = MockDatabase::with_files( 413 let map = def_map_with_crate_graph(
482 " 414 "
483 //- /main.rs 415 //- /main.rs
484 extern crate alloc as alloc_crate; 416 extern crate alloc as alloc_crate;
@@ -492,29 +424,23 @@ fn extern_crate_rename() {
492 //- /lib.rs 424 //- /lib.rs
493 struct Arc; 425 struct Arc;
494 ", 426 ",
427 crate_graph! {
428 "main": ("/main.rs", ["alloc"]),
429 "alloc": ("/lib.rs", []),
430 },
495 ); 431 );
496 db.set_crate_graph_from_fixture(crate_graph! { 432
497 "main": ("/main.rs", ["alloc"]), 433 assert_snapshot_matches!(map,
498 "alloc": ("/lib.rs", []), 434 @r###"
499 }); 435crate
500 let sync_id = db.file_id_of("/sync.rs"); 436Arc: t v
501 437"###
502 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
503 let krate = module.krate(&db).unwrap();
504 let item_map = db.item_map(krate);
505
506 check_module_item_map(
507 &item_map,
508 module.module_id,
509 "
510 Arc: t v
511 ",
512 ); 438 );
513} 439}
514 440
515#[test] 441#[test]
516fn extern_crate_rename_2015_edition() { 442fn extern_crate_rename_2015_edition() {
517 let mut db = MockDatabase::with_files( 443 let map = def_map_with_crate_graph(
518 " 444 "
519 //- /main.rs 445 //- /main.rs
520 extern crate alloc as alloc_crate; 446 extern crate alloc as alloc_crate;
@@ -528,29 +454,23 @@ fn extern_crate_rename_2015_edition() {
528 //- /lib.rs 454 //- /lib.rs
529 struct Arc; 455 struct Arc;
530 ", 456 ",
457 crate_graph! {
458 "main": ("/main.rs", "2015", ["alloc"]),
459 "alloc": ("/lib.rs", []),
460 },
531 ); 461 );
532 db.set_crate_graph_from_fixture(crate_graph! { 462
533 "main": ("/main.rs", "2015", ["alloc"]), 463 assert_snapshot_matches!(map,
534 "alloc": ("/lib.rs", []), 464 @r###"
535 }); 465crate
536 let sync_id = db.file_id_of("/sync.rs"); 466Arc: t v
537 467"###
538 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
539 let krate = module.krate(&db).unwrap();
540 let item_map = db.item_map(krate);
541
542 check_module_item_map(
543 &item_map,
544 module.module_id,
545 "
546 Arc: t v
547 ",
548 ); 468 );
549} 469}
550 470
551#[test] 471#[test]
552fn import_across_source_roots() { 472fn import_across_source_roots() {
553 let mut db = MockDatabase::with_files( 473 let map = def_map_with_crate_graph(
554 " 474 "
555 //- /lib.rs 475 //- /lib.rs
556 pub mod a { 476 pub mod a {
@@ -564,29 +484,23 @@ fn import_across_source_roots() {
564 //- /main/main.rs 484 //- /main/main.rs
565 use test_crate::a::b::C; 485 use test_crate::a::b::C;
566 ", 486 ",
487 crate_graph! {
488 "main": ("/main/main.rs", ["test_crate"]),
489 "test_crate": ("/lib.rs", []),
490 },
567 ); 491 );
568 db.set_crate_graph_from_fixture(crate_graph! { 492
569 "main": ("/main/main.rs", ["test_crate"]), 493 assert_snapshot_matches!(map,
570 "test_crate": ("/lib.rs", []), 494 @r###"
571 }); 495crate
572 let main_id = db.file_id_of("/main/main.rs"); 496C: t v
573 497"###
574 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
575 let krate = module.krate(&db).unwrap();
576 let item_map = db.item_map(krate);
577
578 check_module_item_map(
579 &item_map,
580 module.module_id,
581 "
582 C: t v
583 ",
584 ); 498 );
585} 499}
586 500
587#[test] 501#[test]
588fn reexport_across_crates() { 502fn reexport_across_crates() {
589 let mut db = MockDatabase::with_files( 503 let map = def_map_with_crate_graph(
590 " 504 "
591 //- /main.rs 505 //- /main.rs
592 use test_crate::Baz; 506 use test_crate::Baz;
@@ -599,29 +513,23 @@ fn reexport_across_crates() {
599 //- /foo.rs 513 //- /foo.rs
600 pub struct Baz; 514 pub struct Baz;
601 ", 515 ",
516 crate_graph! {
517 "main": ("/main.rs", ["test_crate"]),
518 "test_crate": ("/lib.rs", []),
519 },
602 ); 520 );
603 db.set_crate_graph_from_fixture(crate_graph! { 521
604 "main": ("/main.rs", ["test_crate"]), 522 assert_snapshot_matches!(map,
605 "test_crate": ("/lib.rs", []), 523 @r###"
606 }); 524crate
607 let main_id = db.file_id_of("/main.rs"); 525Baz: t v
608 526"###
609 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
610 let krate = module.krate(&db).unwrap();
611 let item_map = db.item_map(krate);
612
613 check_module_item_map(
614 &item_map,
615 module.module_id,
616 "
617 Baz: t v
618 ",
619 ); 527 );
620} 528}
621 529
622#[test] 530#[test]
623fn values_dont_shadow_extern_crates() { 531fn values_dont_shadow_extern_crates() {
624 let mut db = MockDatabase::with_files( 532 let map = def_map_with_crate_graph(
625 " 533 "
626 //- /main.rs 534 //- /main.rs
627 fn foo() {} 535 fn foo() {}
@@ -630,139 +538,17 @@ fn values_dont_shadow_extern_crates() {
630 //- /foo/lib.rs 538 //- /foo/lib.rs
631 pub struct Bar; 539 pub struct Bar;
632 ", 540 ",
541 crate_graph! {
542 "main": ("/main.rs", ["foo"]),
543 "foo": ("/foo/lib.rs", []),
544 },
633 ); 545 );
634 db.set_crate_graph_from_fixture(crate_graph! {
635 "main": ("/main.rs", ["foo"]),
636 "foo": ("/foo/lib.rs", []),
637 });
638 let main_id = db.file_id_of("/main.rs");
639
640 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
641 let krate = module.krate(&db).unwrap();
642 let item_map = db.item_map(krate);
643
644 check_module_item_map(
645 &item_map,
646 module.module_id,
647 "
648 Bar: t v
649 foo: v
650 ",
651 );
652}
653
654fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
655 let (mut db, pos) = MockDatabase::with_position(initial);
656 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
657 let krate = module.krate(&db).unwrap();
658 {
659 let events = db.log_executed(|| {
660 db.item_map(krate);
661 });
662 assert!(format!("{:?}", events).contains("item_map"))
663 }
664 db.set_file_text(pos.file_id, Arc::new(file_change.to_string()));
665
666 {
667 let events = db.log_executed(|| {
668 db.item_map(krate);
669 });
670 assert!(!format!("{:?}", events).contains("item_map"), "{:#?}", events)
671 }
672}
673
674#[test]
675fn typing_inside_a_function_should_not_invalidate_item_map() {
676 check_item_map_is_not_recomputed(
677 "
678 //- /lib.rs
679 mod foo;<|>
680
681 use crate::foo::bar::Baz;
682
683 fn foo() -> i32 {
684 1 + 1
685 }
686 //- /foo/mod.rs
687 pub mod bar;
688
689 //- /foo/bar.rs
690 pub struct Baz;
691 ",
692 "
693 mod foo;
694
695 use crate::foo::bar::Baz;
696
697 fn foo() -> i32 { 92 }
698 ",
699 );
700}
701
702#[test]
703fn adding_inner_items_should_not_invalidate_item_map() {
704 check_item_map_is_not_recomputed(
705 "
706 //- /lib.rs
707 struct S { a: i32}
708 enum E { A }
709 trait T {
710 fn a() {}
711 }
712 mod foo;<|>
713 impl S {
714 fn a() {}
715 }
716 use crate::foo::bar::Baz;
717 //- /foo/mod.rs
718 pub mod bar;
719
720 //- /foo/bar.rs
721 pub struct Baz;
722 ",
723 "
724 struct S { a: i32, b: () }
725 enum E { A, B }
726 trait T {
727 fn a() {}
728 fn b() {}
729 }
730 mod foo;<|>
731 impl S {
732 fn a() {}
733 fn b() {}
734 }
735 use crate::foo::bar::Baz;
736 ",
737 );
738}
739 546
740#[test] 547 assert_snapshot_matches!(map,
741fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() { 548 @r###"
742 check_item_map_is_not_recomputed( 549crate
743 " 550Bar: t v
744 //- /lib.rs 551foo: v
745 mod foo; 552"###
746
747 use crate::foo::bar::Baz;
748
749 //- /foo/mod.rs
750 pub mod bar;
751
752 //- /foo/bar.rs
753 <|>
754 salsa::query_group! {
755 trait Baz {
756 fn foo() -> i32 { 1 + 1 }
757 }
758 }
759 ",
760 "
761 salsa::query_group! {
762 trait Baz {
763 fn foo() -> i32 { 92 }
764 }
765 }
766 ",
767 ); 553 );
768} 554}
diff --git a/crates/ra_hir/src/nameres/tests/globs.rs b/crates/ra_hir/src/nameres/tests/globs.rs
new file mode 100644
index 000000000..6e50c7ff6
--- /dev/null
+++ b/crates/ra_hir/src/nameres/tests/globs.rs
@@ -0,0 +1,118 @@
1use super::*;
2
3#[test]
4fn glob_1() {
5 let map = def_map(
6 "
7 //- /lib.rs
8 mod foo;
9 use foo::*;
10
11 //- /foo/mod.rs
12 pub mod bar;
13 pub use self::bar::Baz;
14 pub struct Foo;
15
16 //- /foo/bar.rs
17 pub struct Baz;
18 ",
19 );
20 assert_snapshot_matches!(map, @r###"
21crate
22bar: t
23Foo: t v
24Baz: t v
25foo: t
26
27crate::foo
28bar: t
29Foo: t v
30Baz: t v
31
32crate::foo::bar
33Baz: t v
34"###
35 );
36}
37
38#[test]
39fn glob_2() {
40 let map = def_map(
41 "
42 //- /lib.rs
43 mod foo;
44 use foo::*;
45
46 //- /foo/mod.rs
47 pub mod bar;
48 pub use self::bar::*;
49 pub struct Foo;
50
51 //- /foo/bar.rs
52 pub struct Baz;
53 pub use super::*;
54 ",
55 );
56 assert_snapshot_matches!(map, @r###"
57crate
58bar: t
59Foo: t v
60Baz: t v
61foo: t
62
63crate::foo
64bar: t
65Foo: t v
66Baz: t v
67
68crate::foo::bar
69bar: t
70Foo: t v
71Baz: t v
72"###
73 );
74}
75
76#[test]
77fn glob_across_crates() {
78 covers!(glob_across_crates);
79 let map = def_map_with_crate_graph(
80 "
81 //- /main.rs
82 use test_crate::*;
83
84 //- /lib.rs
85 pub struct Baz;
86 ",
87 crate_graph! {
88 "main": ("/main.rs", ["test_crate"]),
89 "test_crate": ("/lib.rs", []),
90 },
91 );
92 assert_snapshot_matches!(map, @r###"
93crate
94Baz: t v
95"###
96 );
97}
98
99#[test]
100fn glob_enum() {
101 covers!(glob_enum);
102 let map = def_map(
103 "
104 //- /lib.rs
105 enum Foo {
106 Bar, Baz
107 }
108 use self::Foo::*;
109 ",
110 );
111 assert_snapshot_matches!(map, @r###"
112crate
113Foo: t
114Bar: t v
115Baz: t v
116"###
117 );
118}
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
new file mode 100644
index 000000000..698781923
--- /dev/null
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -0,0 +1,123 @@
1use super::*;
2
3use std::sync::Arc;
4
5use ra_db::SourceDatabase;
6
7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
8 let (mut db, pos) = MockDatabase::with_position(initial);
9 let crate_id = db.crate_graph().iter().next().unwrap();
10 let krate = Crate { crate_id };
11 {
12 let events = db.log_executed(|| {
13 db.crate_def_map(krate);
14 });
15 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
16 }
17 db.set_file_text(pos.file_id, Arc::new(file_change.to_string()));
18
19 {
20 let events = db.log_executed(|| {
21 db.crate_def_map(krate);
22 });
23 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
24 }
25}
26
27#[test]
28fn typing_inside_a_function_should_not_invalidate_def_map() {
29 check_def_map_is_not_recomputed(
30 "
31 //- /lib.rs
32 mod foo;<|>
33
34 use crate::foo::bar::Baz;
35
36 fn foo() -> i32 {
37 1 + 1
38 }
39 //- /foo/mod.rs
40 pub mod bar;
41
42 //- /foo/bar.rs
43 pub struct Baz;
44 ",
45 "
46 mod foo;
47
48 use crate::foo::bar::Baz;
49
50 fn foo() -> i32 { 92 }
51 ",
52 );
53}
54
55#[test]
56fn adding_inner_items_should_not_invalidate_def_map() {
57 check_def_map_is_not_recomputed(
58 "
59 //- /lib.rs
60 struct S { a: i32}
61 enum E { A }
62 trait T {
63 fn a() {}
64 }
65 mod foo;<|>
66 impl S {
67 fn a() {}
68 }
69 use crate::foo::bar::Baz;
70 //- /foo/mod.rs
71 pub mod bar;
72
73 //- /foo/bar.rs
74 pub struct Baz;
75 ",
76 "
77 struct S { a: i32, b: () }
78 enum E { A, B }
79 trait T {
80 fn a() {}
81 fn b() {}
82 }
83 mod foo;<|>
84 impl S {
85 fn a() {}
86 fn b() {}
87 }
88 use crate::foo::bar::Baz;
89 ",
90 );
91}
92
93// It would be awesome to make this work, but it's unclear how
94#[test]
95#[ignore]
96fn typing_inside_a_function_inside_a_macro_should_not_invalidate_def_map() {
97 check_def_map_is_not_recomputed(
98 "
99 //- /lib.rs
100 mod foo;
101
102 use crate::foo::bar::Baz;
103
104 //- /foo/mod.rs
105 pub mod bar;
106
107 //- /foo/bar.rs
108 <|>
109 salsa::query_group! {
110 trait Baz {
111 fn foo() -> i32 { 1 + 1 }
112 }
113 }
114 ",
115 "
116 salsa::query_group! {
117 trait Baz {
118 fn foo() -> i32 { 92 }
119 }
120 }
121 ",
122 );
123}
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
new file mode 100644
index 000000000..8781b026b
--- /dev/null
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -0,0 +1,94 @@
1use super::*;
2
3#[test]
4fn macro_rules_are_globally_visible() {
5 let map = def_map(
6 "
7 //- /lib.rs
8 macro_rules! structs {
9 ($($i:ident),*) => {
10 $(struct $i { field: u32 } )*
11 }
12 }
13 structs!(Foo);
14 mod nested;
15
16 //- /nested.rs
17 structs!(Bar, Baz);
18 ",
19 );
20 assert_snapshot_matches!(map, @r###"
21crate
22nested: t
23Foo: t v
24
25crate::nested
26Bar: t v
27Baz: t v
28"###);
29}
30
31#[test]
32fn macro_rules_can_define_modules() {
33 let map = def_map(
34 "
35 //- /lib.rs
36 macro_rules! m {
37 ($name:ident) => { mod $name; }
38 }
39 m!(n1);
40
41 //- /n1.rs
42 m!(n2)
43 //- /n1/n2.rs
44 struct X;
45 ",
46 );
47 assert_snapshot_matches!(map, @r###"
48crate
49n1: t
50
51crate::n1
52n2: t
53
54crate::n1::n2
55X: t v
56"###);
57}
58
59#[test]
60fn macro_rules_from_other_crates_are_visible() {
61 let map = def_map_with_crate_graph(
62 "
63 //- /main.rs
64 foo::structs!(Foo, Bar)
65 mod bar;
66
67 //- /bar.rs
68 use crate::*;
69
70 //- /lib.rs
71 #[macro_export]
72 macro_rules! structs {
73 ($($i:ident),*) => {
74 $(struct $i { field: u32 } )*
75 }
76 }
77 ",
78 crate_graph! {
79 "main": ("/main.rs", ["foo"]),
80 "foo": ("/lib.rs", []),
81 },
82 );
83 assert_snapshot_matches!(map, @r###"
84crate
85bar: t
86Foo: t v
87Bar: t v
88
89crate::bar
90bar: t
91Foo: t v
92Bar: t v
93"###);
94}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 57e7d0b9a..59af4ec60 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -4,10 +4,10 @@ use std::sync::Arc;
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
5 5
6use crate::{ 6use crate::{
7 ModuleDef, Module, 7 ModuleDef,
8 db::HirDatabase, 8 db::HirDatabase,
9 name::{Name, KnownName}, 9 name::{Name, KnownName},
10 nameres::{PerNs, ItemMap}, 10 nameres::{PerNs, CrateDefMap, CrateModuleId},
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,
@@ -22,8 +22,8 @@ pub struct Resolver {
22// TODO how to store these best 22// TODO how to store these best
23#[derive(Debug, Clone)] 23#[derive(Debug, Clone)]
24pub(crate) struct ModuleItemMap { 24pub(crate) struct ModuleItemMap {
25 item_map: Arc<ItemMap>, 25 crate_def_map: Arc<CrateDefMap>,
26 module: Module, 26 module_id: CrateModuleId,
27} 27}
28 28
29#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
@@ -175,9 +175,9 @@ impl Resolver {
175 names 175 names
176 } 176 }
177 177
178 fn module(&self) -> Option<(&ItemMap, Module)> { 178 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
179 self.scopes.iter().rev().find_map(|scope| match scope { 179 self.scopes.iter().rev().find_map(|scope| match scope {
180 Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())), 180 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
181 181
182 _ => None, 182 _ => None,
183 }) 183 })
@@ -206,8 +206,12 @@ impl Resolver {
206 self.push_scope(Scope::ImplBlockScope(impl_block)) 206 self.push_scope(Scope::ImplBlockScope(impl_block))
207 } 207 }
208 208
209 pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver { 209 pub(crate) fn push_module_scope(
210 self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module })) 210 self,
211 crate_def_map: Arc<CrateDefMap>,
212 module_id: CrateModuleId,
213 ) -> Resolver {
214 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
211 } 215 }
212 216
213 pub(crate) fn push_expr_scope( 217 pub(crate) fn push_expr_scope(
@@ -224,9 +228,11 @@ impl Scope {
224 match self { 228 match self {
225 Scope::ModuleScope(m) => { 229 Scope::ModuleScope(m) => {
226 if let Some(KnownName::SelfParam) = name.as_known_name() { 230 if let Some(KnownName::SelfParam) = name.as_known_name() {
227 PerNs::types(Resolution::Def(m.module.into())) 231 PerNs::types(Resolution::Def(m.crate_def_map.mk_module(m.module_id).into()))
228 } else { 232 } else {
229 m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def) 233 m.crate_def_map
234 .resolve_name_in_module(db, m.module_id, name)
235 .map(Resolution::Def)
230 } 236 }
231 } 237 }
232 Scope::GenericParams(gp) => match gp.find_by_name(name) { 238 Scope::GenericParams(gp) => match gp.find_by_name(name) {
@@ -261,15 +267,15 @@ impl Scope {
261 // def: m.module.into(), 267 // def: m.module.into(),
262 // }), 268 // }),
263 // ); 269 // );
264 m.item_map[m.module.module_id].entries().for_each(|(name, res)| { 270 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| {
265 f(name.clone(), res.def.map(Resolution::Def)); 271 f(name.clone(), res.def.map(Resolution::Def));
266 }); 272 });
267 m.item_map.extern_prelude.iter().for_each(|(name, def)| { 273 m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
268 f(name.clone(), PerNs::types(Resolution::Def(*def))); 274 f(name.clone(), PerNs::types(Resolution::Def(*def)));
269 }); 275 });
270 if let Some(prelude) = m.item_map.prelude { 276 if let Some(prelude) = m.crate_def_map.prelude() {
271 let prelude_item_map = db.item_map(prelude.krate); 277 let prelude_def_map = db.crate_def_map(prelude.krate);
272 prelude_item_map[prelude.module_id].entries().for_each(|(name, res)| { 278 prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
273 f(name.clone(), res.def.map(Resolution::Def)); 279 f(name.clone(), res.def.map(Resolution::Def));
274 }); 280 });
275 } 281 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 4a9921a85..902110913 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,13 +7,13 @@
7/// purely for "IDE needs". 7/// purely for "IDE needs".
8use ra_db::{FileId, FilePosition}; 8use ra_db::{FileId, FilePosition};
9use ra_syntax::{ 9use ra_syntax::{
10 SmolStr, TextRange, SyntaxNode, 10 SyntaxNode,
11 ast::{self, AstNode, NameOwner}, 11 ast::{self, AstNode, NameOwner},
12 algo::{find_node_at_offset, find_leaf_at_offset}, 12 algo::{find_node_at_offset, find_leaf_at_offset},
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Function, ModuleDef, Struct, Enum, 16 HirDatabase, Function, Struct, Enum,
17 AsName, Module, HirFileId, Crate, Trait, Resolver, 17 AsName, Module, HirFileId, Crate, Trait, Resolver,
18 ids::{LocationCtx, SourceFileItemId}, 18 ids::{LocationCtx, SourceFileItemId},
19 expr 19 expr
@@ -80,8 +80,8 @@ fn module_from_source(
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(
82 |krate| { 82 |krate| {
83 let module_tree = db.module_tree(krate); 83 let def_map = db.crate_def_map(krate);
84 let module_id = module_tree.find_module_by_source(file_id, decl_id)?; 84 let module_id = def_map.find_module_by_source(file_id, decl_id)?;
85 Some(Module { krate, module_id }) 85 Some(Module { krate, module_id })
86 }, 86 },
87 ) 87 )
@@ -152,44 +152,6 @@ pub fn trait_from_module(
152 Trait { id: ctx.to_def(trait_def) } 152 Trait { id: ctx.to_def(trait_def) }
153} 153}
154 154
155pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> {
156 let module = match module_from_file_id(db, file_id) {
157 Some(it) => it,
158 None => return Vec::new(),
159 };
160 let items = db.lower_module(module);
161 let mut res = Vec::new();
162
163 for macro_call_id in items
164 .declarations
165 .iter()
166 .filter_map(|(_, it)| it.clone().take_types())
167 .filter_map(|it| match it {
168 ModuleDef::Trait(it) => Some(it),
169 _ => None,
170 })
171 .filter_map(|it| it.source(db).0.as_macro_call_id())
172 {
173 if let Some(exp) = db.expand_macro_invocation(macro_call_id) {
174 let loc = macro_call_id.loc(db);
175 let syntax = db.file_item(loc.source_item_id);
176 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
177 let off = macro_call.token_tree().unwrap().syntax().range().start();
178 let file = exp.file();
179 for trait_def in file.syntax().descendants().filter_map(ast::TraitDef::cast) {
180 if let Some(name) = trait_def.name() {
181 let dst_range = name.syntax().range();
182 if let Some(src_range) = exp.map_range_back(dst_range) {
183 res.push((name.text().clone(), src_range + off))
184 }
185 }
186 }
187 }
188 }
189
190 res
191}
192
193pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { 155pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver {
194 let file_id = position.file_id; 156 let file_id = position.file_id;
195 let file = db.parse(file_id); 157 let file = db.parse(file_id);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index bad811a56..2ea3b341f 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -9,16 +9,16 @@ pub(crate) mod method_resolution;
9mod op; 9mod op;
10mod lower; 10mod lower;
11mod infer; 11mod infer;
12pub(crate) mod display;
12 13
13use std::sync::Arc; 14use std::sync::Arc;
14use std::{fmt, mem}; 15use std::{fmt, mem};
15 16
16use join_to_string::join; 17use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase};
17 18
18use crate::{Name, AdtDef, type_ref::Mutability}; 19pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig};
19
20pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field};
21pub(crate) use infer::{infer, InferenceResult, InferTy}; 20pub(crate) use infer::{infer, InferenceResult, InferTy};
21use display::{HirDisplay, HirFormatter};
22 22
23/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). 23/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
24/// 24///
@@ -42,8 +42,6 @@ pub enum Ty {
42 Adt { 42 Adt {
43 /// The definition of the struct/enum. 43 /// The definition of the struct/enum.
44 def_id: AdtDef, 44 def_id: AdtDef,
45 /// The name, for displaying.
46 name: Name,
47 /// Substitutions for the generic parameters of the type. 45 /// Substitutions for the generic parameters of the type.
48 substs: Substs, 46 substs: Substs,
49 }, 47 },
@@ -79,10 +77,6 @@ pub enum Ty {
79 FnDef { 77 FnDef {
80 /// The definition of the function / constructor. 78 /// The definition of the function / constructor.
81 def: CallableDef, 79 def: CallableDef,
82 /// For display
83 name: Name,
84 /// Parameters and return type
85 sig: Arc<FnSig>,
86 /// Substitutions for the generic parameters of the type 80 /// Substitutions for the generic parameters of the type
87 substs: Substs, 81 substs: Substs,
88 }, 82 },
@@ -95,7 +89,7 @@ pub enum Ty {
95 /// fn foo() -> i32 { 1 } 89 /// fn foo() -> i32 { 1 }
96 /// let bar: fn() -> i32 = foo; 90 /// let bar: fn() -> i32 = foo;
97 /// ``` 91 /// ```
98 FnPtr(Arc<FnSig>), 92 FnPtr(FnSig),
99 93
100 /// The never type `!`. 94 /// The never type `!`.
101 Never, 95 Never,
@@ -132,13 +126,44 @@ impl Substs {
132 pub fn empty() -> Substs { 126 pub fn empty() -> Substs {
133 Substs(Arc::new([])) 127 Substs(Arc::new([]))
134 } 128 }
129
130 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
131 // Without an Arc::make_mut_slice, we can't avoid the clone here:
132 let mut v: Vec<_> = self.0.iter().cloned().collect();
133 for t in &mut v {
134 t.walk_mut(f);
135 }
136 self.0 = v.into();
137 }
135} 138}
136 139
137/// A function signature. 140/// A function signature.
138#[derive(Clone, PartialEq, Eq, Debug)] 141#[derive(Clone, PartialEq, Eq, Debug)]
139pub struct FnSig { 142pub struct FnSig {
140 input: Vec<Ty>, 143 params_and_return: Arc<[Ty]>,
141 output: Ty, 144}
145
146impl FnSig {
147 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig {
148 params.push(ret);
149 FnSig { params_and_return: params.into() }
150 }
151 pub fn params(&self) -> &[Ty] {
152 &self.params_and_return[0..self.params_and_return.len() - 1]
153 }
154
155 pub fn ret(&self) -> &Ty {
156 &self.params_and_return[self.params_and_return.len() - 1]
157 }
158
159 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
160 // Without an Arc::make_mut_slice, we can't avoid the clone here:
161 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
162 for t in &mut v {
163 t.walk_mut(f);
164 }
165 self.params_and_return = v.into();
166 }
142} 167}
143 168
144impl Ty { 169impl Ty {
@@ -157,16 +182,12 @@ impl Ty {
157 } 182 }
158 } 183 }
159 Ty::FnPtr(sig) => { 184 Ty::FnPtr(sig) => {
160 for input in &sig.input { 185 for input in sig.params() {
161 input.walk(f); 186 input.walk(f);
162 } 187 }
163 sig.output.walk(f); 188 sig.ret().walk(f);
164 } 189 }
165 Ty::FnDef { substs, sig, .. } => { 190 Ty::FnDef { substs, .. } => {
166 for input in &sig.input {
167 input.walk(f);
168 }
169 sig.output.walk(f);
170 for t in substs.0.iter() { 191 for t in substs.0.iter() {
171 t.walk(f); 192 t.walk(f);
172 } 193 }
@@ -203,32 +224,13 @@ impl Ty {
203 *ts = v.into(); 224 *ts = v.into();
204 } 225 }
205 Ty::FnPtr(sig) => { 226 Ty::FnPtr(sig) => {
206 let sig_mut = Arc::make_mut(sig); 227 sig.walk_mut(f);
207 for input in &mut sig_mut.input {
208 input.walk_mut(f);
209 }
210 sig_mut.output.walk_mut(f);
211 } 228 }
212 Ty::FnDef { substs, sig, .. } => { 229 Ty::FnDef { substs, .. } => {
213 let sig_mut = Arc::make_mut(sig); 230 substs.walk_mut(f);
214 for input in &mut sig_mut.input {
215 input.walk_mut(f);
216 }
217 sig_mut.output.walk_mut(f);
218 // Without an Arc::make_mut_slice, we can't avoid the clone here:
219 let mut v: Vec<_> = substs.0.iter().cloned().collect();
220 for t in &mut v {
221 t.walk_mut(f);
222 }
223 substs.0 = v.into();
224 } 231 }
225 Ty::Adt { substs, .. } => { 232 Ty::Adt { substs, .. } => {
226 // Without an Arc::make_mut_slice, we can't avoid the clone here: 233 substs.walk_mut(f);
227 let mut v: Vec<_> = substs.0.iter().cloned().collect();
228 for t in &mut v {
229 t.walk_mut(f);
230 }
231 substs.0 = v.into();
232 } 234 }
233 Ty::Bool 235 Ty::Bool
234 | Ty::Char 236 | Ty::Char
@@ -265,8 +267,8 @@ impl Ty {
265 /// `Option<u32>` afterwards.) 267 /// `Option<u32>` afterwards.)
266 pub fn apply_substs(self, substs: Substs) -> Ty { 268 pub fn apply_substs(self, substs: Substs) -> Ty {
267 match self { 269 match self {
268 Ty::Adt { def_id, name, .. } => Ty::Adt { def_id, name, substs }, 270 Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs },
269 Ty::FnDef { def, name, sig, .. } => Ty::FnDef { def, name, sig, substs }, 271 Ty::FnDef { def, .. } => Ty::FnDef { def, substs },
270 _ => self, 272 _ => self,
271 } 273 }
272 } 274 }
@@ -297,50 +299,81 @@ impl Ty {
297 } 299 }
298} 300}
299 301
300impl fmt::Display for Ty { 302impl HirDisplay for &Ty {
301 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 303 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
304 HirDisplay::hir_fmt(*self, f)
305 }
306}
307
308impl HirDisplay for Ty {
309 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
302 match self { 310 match self {
303 Ty::Bool => write!(f, "bool"), 311 Ty::Bool => write!(f, "bool")?,
304 Ty::Char => write!(f, "char"), 312 Ty::Char => write!(f, "char")?,
305 Ty::Int(t) => write!(f, "{}", t.ty_to_string()), 313 Ty::Int(t) => write!(f, "{}", t)?,
306 Ty::Float(t) => write!(f, "{}", t.ty_to_string()), 314 Ty::Float(t) => write!(f, "{}", t)?,
307 Ty::Str => write!(f, "str"), 315 Ty::Str => write!(f, "str")?,
308 Ty::Slice(t) | Ty::Array(t) => write!(f, "[{}]", t), 316 Ty::Slice(t) | Ty::Array(t) => {
309 Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t), 317 write!(f, "[{}]", t.display(f.db))?;
310 Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t), 318 }
311 Ty::Never => write!(f, "!"), 319 Ty::RawPtr(t, m) => {
320 write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
321 }
322 Ty::Ref(t, m) => {
323 write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?;
324 }
325 Ty::Never => write!(f, "!")?,
312 Ty::Tuple(ts) => { 326 Ty::Tuple(ts) => {
313 if ts.len() == 1 { 327 if ts.len() == 1 {
314 write!(f, "({},)", ts[0]) 328 write!(f, "({},)", ts[0].display(f.db))?;
315 } else { 329 } else {
316 join(ts.iter()).surround_with("(", ")").separator(", ").to_fmt(f) 330 write!(f, "(")?;
331 f.write_joined(&**ts, ", ")?;
332 write!(f, ")")?;
317 } 333 }
318 } 334 }
319 Ty::FnPtr(sig) => { 335 Ty::FnPtr(sig) => {
320 join(sig.input.iter()).surround_with("fn(", ")").separator(", ").to_fmt(f)?; 336 write!(f, "fn(")?;
321 write!(f, " -> {}", sig.output) 337 f.write_joined(sig.params(), ", ")?;
338 write!(f, ") -> {}", sig.ret().display(f.db))?;
322 } 339 }
323 Ty::FnDef { def, name, substs, sig, .. } => { 340 Ty::FnDef { def, substs, .. } => {
341 let sig = f.db.callable_item_signature(*def);
342 let name = match def {
343 CallableDef::Function(ff) => ff.name(f.db),
344 CallableDef::Struct(s) => s.name(f.db).unwrap_or_else(Name::missing),
345 CallableDef::EnumVariant(e) => e.name(f.db).unwrap_or_else(Name::missing),
346 };
324 match def { 347 match def {
325 CallableDef::Function(_) => write!(f, "fn {}", name)?, 348 CallableDef::Function(_) => write!(f, "fn {}", name)?,
326 CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?, 349 CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?,
327 } 350 }
328 if substs.0.len() > 0 { 351 if substs.0.len() > 0 {
329 join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?; 352 write!(f, "<")?;
353 f.write_joined(&*substs.0, ", ")?;
354 write!(f, ">")?;
330 } 355 }
331 join(sig.input.iter()).surround_with("(", ")").separator(", ").to_fmt(f)?; 356 write!(f, "(")?;
332 write!(f, " -> {}", sig.output) 357 f.write_joined(sig.params(), ", ")?;
358 write!(f, ") -> {}", sig.ret().display(f.db))?;
333 } 359 }
334 Ty::Adt { name, substs, .. } => { 360 Ty::Adt { def_id, substs, .. } => {
361 let name = match def_id {
362 AdtDef::Struct(s) => s.name(f.db),
363 AdtDef::Enum(e) => e.name(f.db),
364 }
365 .unwrap_or_else(Name::missing);
335 write!(f, "{}", name)?; 366 write!(f, "{}", name)?;
336 if substs.0.len() > 0 { 367 if substs.0.len() > 0 {
337 join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?; 368 write!(f, "<")?;
369 f.write_joined(&*substs.0, ", ")?;
370 write!(f, ">")?;
338 } 371 }
339 Ok(())
340 } 372 }
341 Ty::Param { name, .. } => write!(f, "{}", name), 373 Ty::Param { name, .. } => write!(f, "{}", name)?,
342 Ty::Unknown => write!(f, "{{unknown}}"), 374 Ty::Unknown => write!(f, "{{unknown}}")?,
343 Ty::Infer(..) => write!(f, "_"), 375 Ty::Infer(..) => write!(f, "_")?,
344 } 376 }
377 Ok(())
345 } 378 }
346} 379}
diff --git a/crates/ra_hir/src/ty/display.rs b/crates/ra_hir/src/ty/display.rs
new file mode 100644
index 000000000..63ec9d7e1
--- /dev/null
+++ b/crates/ra_hir/src/ty/display.rs
@@ -0,0 +1,56 @@
1use std::fmt;
2
3use crate::db::HirDatabase;
4
5pub struct HirFormatter<'a, 'b, DB> {
6 pub db: &'a DB,
7 fmt: &'a mut fmt::Formatter<'b>,
8}
9
10pub trait HirDisplay {
11 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result;
12 fn display<'a, DB>(&'a self, db: &'a DB) -> HirDisplayWrapper<'a, DB, Self>
13 where
14 Self: Sized,
15 {
16 HirDisplayWrapper(db, self)
17 }
18}
19
20impl<'a, 'b, DB> HirFormatter<'a, 'b, DB>
21where
22 DB: HirDatabase,
23{
24 pub fn write_joined<T: HirDisplay>(
25 &mut self,
26 iter: impl IntoIterator<Item = T>,
27 sep: &str,
28 ) -> fmt::Result {
29 let mut first = true;
30 for e in iter {
31 if !first {
32 write!(self, "{}", sep)?;
33 }
34 first = false;
35 e.hir_fmt(self)?;
36 }
37 Ok(())
38 }
39
40 /// This allows using the `write!` macro directly with a `HirFormatter`.
41 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
42 fmt::write(self.fmt, args)
43 }
44}
45
46pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T);
47
48impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T>
49where
50 DB: HirDatabase,
51 T: HirDisplay,
52{
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 self.1.hir_fmt(&mut HirFormatter { db: self.0, fmt: f })
55 }
56}
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 0a698988c..735cdecb9 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -789,11 +789,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
789 Expr::Call { callee, args } => { 789 Expr::Call { callee, args } => {
790 let callee_ty = self.infer_expr(*callee, &Expectation::none()); 790 let callee_ty = self.infer_expr(*callee, &Expectation::none());
791 let (param_tys, ret_ty) = match &callee_ty { 791 let (param_tys, ret_ty) = match &callee_ty {
792 Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()), 792 Ty::FnPtr(sig) => (sig.params().to_vec(), sig.ret().clone()),
793 Ty::FnDef { substs, sig, .. } => { 793 Ty::FnDef { substs, def, .. } => {
794 let ret_ty = sig.output.clone().subst(&substs); 794 let sig = self.db.callable_item_signature(*def);
795 let ret_ty = sig.ret().clone().subst(&substs);
795 let param_tys = 796 let param_tys =
796 sig.input.iter().map(|ty| ty.clone().subst(&substs)).collect(); 797 sig.params().iter().map(|ty| ty.clone().subst(&substs)).collect();
797 (param_tys, ret_ty) 798 (param_tys, ret_ty)
798 } 799 }
799 _ => { 800 _ => {
@@ -827,19 +828,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
827 let method_ty = self.insert_type_vars(method_ty); 828 let method_ty = self.insert_type_vars(method_ty);
828 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { 829 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
829 Ty::FnPtr(sig) => { 830 Ty::FnPtr(sig) => {
830 if !sig.input.is_empty() { 831 if !sig.params().is_empty() {
831 (sig.input[0].clone(), sig.input[1..].to_vec(), sig.output.clone()) 832 (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
832 } else { 833 } else {
833 (Ty::Unknown, Vec::new(), sig.output.clone()) 834 (Ty::Unknown, Vec::new(), sig.ret().clone())
834 } 835 }
835 } 836 }
836 Ty::FnDef { substs, sig, .. } => { 837 Ty::FnDef { substs, def, .. } => {
837 let ret_ty = sig.output.clone().subst(&substs); 838 let sig = self.db.callable_item_signature(*def);
838 839 let ret_ty = sig.ret().clone().subst(&substs);
839 if !sig.input.is_empty() { 840
840 let mut arg_iter = sig.input.iter().map(|ty| ty.clone().subst(&substs)); 841 if !sig.params().is_empty() {
841 let receiver_ty = arg_iter.next().unwrap(); 842 let mut params_iter =
842 (receiver_ty, arg_iter.collect(), ret_ty) 843 sig.params().iter().map(|ty| ty.clone().subst(&substs));
844 let receiver_ty = params_iter.next().unwrap();
845 (receiver_ty, params_iter.collect(), ret_ty)
843 } else { 846 } else {
844 (Ty::Unknown, Vec::new(), ret_ty) 847 (Ty::Unknown, Vec::new(), ret_ty)
845 } 848 }
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index f4e055feb..278f592d3 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -9,7 +9,7 @@
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use crate::{ 11use crate::{
12 Function, Struct, StructField, Enum, EnumVariant, Path, Name, 12 Function, Struct, StructField, Enum, EnumVariant, Path,
13 ModuleDef, TypeAlias, 13 ModuleDef, TypeAlias,
14 Const, Static, 14 Const, Static,
15 HirDatabase, 15 HirDatabase,
@@ -51,12 +51,10 @@ impl Ty {
51 } 51 }
52 TypeRef::Placeholder => Ty::Unknown, 52 TypeRef::Placeholder => Ty::Unknown,
53 TypeRef::Fn(params) => { 53 TypeRef::Fn(params) => {
54 let mut inner_tys = 54 let inner_tys =
55 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); 55 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
56 let return_ty = 56 let sig = FnSig { params_and_return: inner_tys.into() };
57 inner_tys.pop().expect("TypeRef::Fn should always have at least return type"); 57 Ty::FnPtr(sig)
58 let sig = FnSig { input: inner_tys, output: return_ty };
59 Ty::FnPtr(Arc::new(sig))
60 } 58 }
61 TypeRef::Error => Ty::Unknown, 59 TypeRef::Error => Ty::Unknown,
62 } 60 }
@@ -214,6 +212,15 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
214 } 212 }
215} 213}
216 214
215/// Build the signature of a callable item (function, struct or enum variant).
216pub(crate) fn callable_item_sig(db: &impl HirDatabase, def: CallableDef) -> FnSig {
217 match def {
218 CallableDef::Function(f) => fn_sig_for_fn(db, f),
219 CallableDef::Struct(s) => fn_sig_for_struct_constructor(db, s),
220 CallableDef::EnumVariant(e) => fn_sig_for_enum_variant_constructor(db, e),
221 }
222}
223
217/// Build the type of a specific field of a struct or enum variant. 224/// Build the type of a specific field of a struct or enum variant.
218pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { 225pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
219 let parent_def = field.parent_def(db); 226 let parent_def = field.parent_def(db);
@@ -226,19 +233,21 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
226 Ty::from_hir(db, &resolver, type_ref) 233 Ty::from_hir(db, &resolver, type_ref)
227} 234}
228 235
236fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
237 let signature = def.signature(db);
238 let resolver = def.resolver(db);
239 let params =
240 signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
241 let ret = Ty::from_hir(db, &resolver, signature.ret_type());
242 FnSig::from_params_and_return(params, ret)
243}
244
229/// Build the declared type of a function. This should not need to look at the 245/// Build the declared type of a function. This should not need to look at the
230/// function body. 246/// function body.
231fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { 247fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
232 let signature = def.signature(db);
233 let resolver = def.resolver(db);
234 let generics = def.generic_params(db); 248 let generics = def.generic_params(db);
235 let name = def.name(db);
236 let input =
237 signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
238 let output = Ty::from_hir(db, &resolver, signature.ret_type());
239 let sig = Arc::new(FnSig { input, output });
240 let substs = make_substs(&generics); 249 let substs = make_substs(&generics);
241 Ty::FnDef { def: def.into(), sig, name, substs } 250 Ty::FnDef { def: def.into(), substs }
242} 251}
243 252
244/// Build the declared type of a const. 253/// Build the declared type of a const.
@@ -257,44 +266,58 @@ fn type_for_static(db: &impl HirDatabase, def: Static) -> Ty {
257 Ty::from_hir(db, &resolver, signature.type_ref()) 266 Ty::from_hir(db, &resolver, signature.type_ref())
258} 267}
259 268
260/// Build the type of a tuple struct constructor. 269fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
261fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
262 let var_data = def.variant_data(db); 270 let var_data = def.variant_data(db);
263 let fields = match var_data.fields() { 271 let fields = match var_data.fields() {
264 Some(fields) => fields, 272 Some(fields) => fields,
265 None => return type_for_struct(db, def), // Unit struct 273 None => panic!("fn_sig_for_struct_constructor called on unit struct"),
266 }; 274 };
267 let resolver = def.resolver(db); 275 let resolver = def.resolver(db);
268 let generics = def.generic_params(db); 276 let params = fields
269 let name = def.name(db).unwrap_or_else(Name::missing);
270 let input = fields
271 .iter() 277 .iter()
272 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 278 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
273 .collect::<Vec<_>>(); 279 .collect::<Vec<_>>();
274 let output = type_for_struct(db, def); 280 let ret = type_for_struct(db, def);
275 let sig = Arc::new(FnSig { input, output }); 281 FnSig::from_params_and_return(params, ret)
282}
283
284/// Build the type of a tuple struct constructor.
285fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
286 let var_data = def.variant_data(db);
287 if var_data.fields().is_none() {
288 return type_for_struct(db, def); // Unit struct
289 }
290 let generics = def.generic_params(db);
276 let substs = make_substs(&generics); 291 let substs = make_substs(&generics);
277 Ty::FnDef { def: def.into(), sig, name, substs } 292 Ty::FnDef { def: def.into(), substs }
278} 293}
279 294
280/// Build the type of a tuple enum variant constructor. 295fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> FnSig {
281fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
282 let var_data = def.variant_data(db); 296 let var_data = def.variant_data(db);
283 let fields = match var_data.fields() { 297 let fields = match var_data.fields() {
284 Some(fields) => fields, 298 Some(fields) => fields,
285 None => return type_for_enum(db, def.parent_enum(db)), // Unit variant 299 None => panic!("fn_sig_for_enum_variant_constructor called for unit variant"),
286 }; 300 };
287 let resolver = def.parent_enum(db).resolver(db); 301 let resolver = def.parent_enum(db).resolver(db);
288 let generics = def.parent_enum(db).generic_params(db); 302 let params = fields
289 let name = def.name(db).unwrap_or_else(Name::missing);
290 let input = fields
291 .iter() 303 .iter()
292 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 304 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
293 .collect::<Vec<_>>(); 305 .collect::<Vec<_>>();
306 let generics = def.parent_enum(db).generic_params(db);
307 let substs = make_substs(&generics);
308 let ret = type_for_enum(db, def.parent_enum(db)).subst(&substs);
309 FnSig::from_params_and_return(params, ret)
310}
311
312/// Build the type of a tuple enum variant constructor.
313fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
314 let var_data = def.variant_data(db);
315 if var_data.fields().is_none() {
316 return type_for_enum(db, def.parent_enum(db)); // Unit variant
317 }
318 let generics = def.parent_enum(db).generic_params(db);
294 let substs = make_substs(&generics); 319 let substs = make_substs(&generics);
295 let output = type_for_enum(db, def.parent_enum(db)).subst(&substs); 320 Ty::FnDef { def: def.into(), substs }
296 let sig = Arc::new(FnSig { input, output });
297 Ty::FnDef { def: def.into(), sig, name, substs }
298} 321}
299 322
300fn make_substs(generics: &GenericParams) -> Substs { 323fn make_substs(generics: &GenericParams) -> Substs {
@@ -310,20 +333,12 @@ fn make_substs(generics: &GenericParams) -> Substs {
310 333
311fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { 334fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
312 let generics = s.generic_params(db); 335 let generics = s.generic_params(db);
313 Ty::Adt { 336 Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
314 def_id: s.into(),
315 name: s.name(db).unwrap_or_else(Name::missing),
316 substs: make_substs(&generics),
317 }
318} 337}
319 338
320fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { 339fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
321 let generics = s.generic_params(db); 340 let generics = s.generic_params(db);
322 Ty::Adt { 341 Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
323 def_id: s.into(),
324 name: s.name(db).unwrap_or_else(Name::missing),
325 substs: make_substs(&generics),
326 }
327} 342}
328 343
329fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty { 344fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 94b757af2..804824868 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,10 +7,12 @@ use std::sync::Arc;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait, 10 HirDatabase, Module, Crate, Name, Function, Trait,
11 ids::TraitId, 11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 12 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{AdtDef, Ty}, 13 ty::{AdtDef, Ty},
14 nameres::CrateModuleId,
15
14}; 16};
15 17
16/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
@@ -33,10 +35,10 @@ impl TyFingerprint {
33 35
34#[derive(Debug, PartialEq, Eq)] 36#[derive(Debug, PartialEq, Eq)]
35pub struct CrateImplBlocks { 37pub struct CrateImplBlocks {
36 /// To make sense of the ModuleIds, we need the source root. 38 /// To make sense of the CrateModuleIds, we need the source root.
37 krate: Crate, 39 krate: Crate,
38 impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>, 40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
39 impls_by_trait: FxHashMap<TraitId, Vec<(ModuleId, ImplId)>>, 41 impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>,
40} 42}
41 43
42impl CrateImplBlocks { 44impl CrateImplBlocks {
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 5741ca90d..30aeac48e 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -10,14 +10,6 @@ pub enum UncertainIntTy {
10} 10}
11 11
12impl UncertainIntTy { 12impl UncertainIntTy {
13 pub fn ty_to_string(&self) -> &'static str {
14 match *self {
15 UncertainIntTy::Unknown => "{integer}",
16 UncertainIntTy::Signed(ty) => ty.ty_to_string(),
17 UncertainIntTy::Unsigned(ty) => ty.ty_to_string(),
18 }
19 }
20
21 pub fn from_name(name: &Name) -> Option<UncertainIntTy> { 13 pub fn from_name(name: &Name) -> Option<UncertainIntTy> {
22 if let Some(ty) = IntTy::from_name(name) { 14 if let Some(ty) = IntTy::from_name(name) {
23 Some(UncertainIntTy::Signed(ty)) 15 Some(UncertainIntTy::Signed(ty))
@@ -29,6 +21,16 @@ impl UncertainIntTy {
29 } 21 }
30} 22}
31 23
24impl fmt::Display for UncertainIntTy {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26 match *self {
27 UncertainIntTy::Unknown => write!(f, "{{integer}}"),
28 UncertainIntTy::Signed(ty) => write!(f, "{}", ty),
29 UncertainIntTy::Unsigned(ty) => write!(f, "{}", ty),
30 }
31 }
32}
33
32#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] 34#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
33pub enum UncertainFloatTy { 35pub enum UncertainFloatTy {
34 Unknown, 36 Unknown,
@@ -36,13 +38,6 @@ pub enum UncertainFloatTy {
36} 38}
37 39
38impl UncertainFloatTy { 40impl UncertainFloatTy {
39 pub fn ty_to_string(&self) -> &'static str {
40 match *self {
41 UncertainFloatTy::Unknown => "{float}",
42 UncertainFloatTy::Known(ty) => ty.ty_to_string(),
43 }
44 }
45
46 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> { 41 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> {
47 if let Some(ty) = FloatTy::from_name(name) { 42 if let Some(ty) = FloatTy::from_name(name) {
48 Some(UncertainFloatTy::Known(ty)) 43 Some(UncertainFloatTy::Known(ty))
@@ -52,6 +47,15 @@ impl UncertainFloatTy {
52 } 47 }
53} 48}
54 49
50impl fmt::Display for UncertainFloatTy {
51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52 match *self {
53 UncertainFloatTy::Unknown => write!(f, "{{float}}"),
54 UncertainFloatTy::Known(ty) => write!(f, "{}", ty),
55 }
56 }
57}
58
55#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] 59#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
56pub enum IntTy { 60pub enum IntTy {
57 Isize, 61 Isize,
@@ -70,22 +74,19 @@ impl fmt::Debug for IntTy {
70 74
71impl fmt::Display for IntTy { 75impl fmt::Display for IntTy {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 write!(f, "{}", self.ty_to_string()) 77 let s = match *self {
74 }
75}
76
77impl IntTy {
78 pub fn ty_to_string(&self) -> &'static str {
79 match *self {
80 IntTy::Isize => "isize", 78 IntTy::Isize => "isize",
81 IntTy::I8 => "i8", 79 IntTy::I8 => "i8",
82 IntTy::I16 => "i16", 80 IntTy::I16 => "i16",
83 IntTy::I32 => "i32", 81 IntTy::I32 => "i32",
84 IntTy::I64 => "i64", 82 IntTy::I64 => "i64",
85 IntTy::I128 => "i128", 83 IntTy::I128 => "i128",
86 } 84 };
85 write!(f, "{}", s)
87 } 86 }
87}
88 88
89impl IntTy {
89 pub fn from_name(name: &Name) -> Option<IntTy> { 90 pub fn from_name(name: &Name) -> Option<IntTy> {
90 match name.as_known_name()? { 91 match name.as_known_name()? {
91 KnownName::Isize => Some(IntTy::Isize), 92 KnownName::Isize => Some(IntTy::Isize),
@@ -109,18 +110,21 @@ pub enum UintTy {
109 U128, 110 U128,
110} 111}
111 112
112impl UintTy { 113impl fmt::Display for UintTy {
113 pub fn ty_to_string(&self) -> &'static str { 114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 match *self { 115 let s = match *self {
115 UintTy::Usize => "usize", 116 UintTy::Usize => "usize",
116 UintTy::U8 => "u8", 117 UintTy::U8 => "u8",
117 UintTy::U16 => "u16", 118 UintTy::U16 => "u16",
118 UintTy::U32 => "u32", 119 UintTy::U32 => "u32",
119 UintTy::U64 => "u64", 120 UintTy::U64 => "u64",
120 UintTy::U128 => "u128", 121 UintTy::U128 => "u128",
121 } 122 };
123 write!(f, "{}", s)
122 } 124 }
125}
123 126
127impl UintTy {
124 pub fn from_name(name: &Name) -> Option<UintTy> { 128 pub fn from_name(name: &Name) -> Option<UintTy> {
125 match name.as_known_name()? { 129 match name.as_known_name()? {
126 KnownName::Usize => Some(UintTy::Usize), 130 KnownName::Usize => Some(UintTy::Usize),
@@ -140,12 +144,6 @@ impl fmt::Debug for UintTy {
140 } 144 }
141} 145}
142 146
143impl fmt::Display for UintTy {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 write!(f, "{}", self.ty_to_string())
146 }
147}
148
149#[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] 147#[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
150pub enum FloatTy { 148pub enum FloatTy {
151 F32, 149 F32,
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 0f8551a9d..0f2172ddf 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -10,6 +10,7 @@ use test_utils::covers;
10use crate::{ 10use crate::{
11 source_binder, 11 source_binder,
12 mock::MockDatabase, 12 mock::MockDatabase,
13 ty::display::HirDisplay,
13}; 14};
14 15
15// These tests compare the inference results for all expressions in a file 16// These tests compare the inference results for all expressions in a file
@@ -2196,7 +2197,7 @@ fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
2196 let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap(); 2197 let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap();
2197 let expr = body_source_map.node_expr(node).unwrap(); 2198 let expr = body_source_map.node_expr(node).unwrap();
2198 let ty = &inference_result[expr]; 2199 let ty = &inference_result[expr];
2199 ty.to_string() 2200 ty.display(db).to_string()
2200} 2201}
2201 2202
2202fn infer(content: &str) -> String { 2203fn infer(content: &str) -> String {
@@ -2232,7 +2233,7 @@ fn infer(content: &str) -> String {
2232 "{} '{}': {}\n", 2233 "{} '{}': {}\n",
2233 syntax_ptr.range(), 2234 syntax_ptr.range(),
2234 ellipsize(node.text().to_string().replace("\n", " "), 15), 2235 ellipsize(node.text().to_string().replace("\n", " "), 15),
2235 ty 2236 ty.display(&db)
2236 ) 2237 )
2237 .unwrap(); 2238 .unwrap();
2238 } 2239 }