aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/completion/complete_scope.rs14
-rw-r--r--crates/ra_analysis/src/db.rs3
-rw-r--r--crates/ra_analysis/src/goto_defenition.rs6
-rw-r--r--crates/ra_analysis/src/imp.rs34
-rw-r--r--crates/ra_analysis/src/lib.rs2
-rw-r--r--crates/ra_analysis/src/runnables.rs9
-rw-r--r--crates/ra_analysis/tests/test/main.rs3
-rw-r--r--crates/ra_db/src/syntax_ptr.rs2
-rw-r--r--crates/ra_editor/src/assists/split_import.rs14
-rw-r--r--crates/ra_hir/src/code_model_api.rs110
-rw-r--r--crates/ra_hir/src/code_model_impl.rs2
-rw-r--r--crates/ra_hir/src/code_model_impl/krate.rs47
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs154
-rw-r--r--crates/ra_hir/src/db.rs29
-rw-r--r--crates/ra_hir/src/expr.rs745
-rw-r--r--crates/ra_hir/src/function.rs79
-rw-r--r--crates/ra_hir/src/function/scope.rs368
-rw-r--r--crates/ra_hir/src/ids.rs10
-rw-r--r--crates/ra_hir/src/impl_block.rs32
-rw-r--r--crates/ra_hir/src/krate.rs48
-rw-r--r--crates/ra_hir/src/lib.rs20
-rw-r--r--crates/ra_hir/src/mock.rs3
-rw-r--r--crates/ra_hir/src/module.rs376
-rw-r--r--crates/ra_hir/src/module/imp.rs190
-rw-r--r--crates/ra_hir/src/module_tree.rs368
-rw-r--r--crates/ra_hir/src/name.rs14
-rw-r--r--crates/ra_hir/src/nameres.rs (renamed from crates/ra_hir/src/module/nameres.rs)16
-rw-r--r--crates/ra_hir/src/nameres/tests.rs (renamed from crates/ra_hir/src/module/nameres/tests.rs)4
-rw-r--r--crates/ra_hir/src/path.rs14
-rw-r--r--crates/ra_hir/src/query_definitions.rs77
-rw-r--r--crates/ra_hir/src/source_binder.rs80
-rw-r--r--crates/ra_hir/src/ty.rs19
-rw-r--r--crates/ra_hir/src/ty/tests.rs44
-rw-r--r--crates/ra_hir/src/type_ref.rs4
-rw-r--r--crates/ra_syntax/src/ast/generated.rs35
-rw-r--r--crates/ra_syntax/src/grammar.ron14
36 files changed, 1970 insertions, 1019 deletions
diff --git a/crates/ra_analysis/src/completion/complete_scope.rs b/crates/ra_analysis/src/completion/complete_scope.rs
index 4dead3689..ee9052d3d 100644
--- a/crates/ra_analysis/src/completion/complete_scope.rs
+++ b/crates/ra_analysis/src/completion/complete_scope.rs
@@ -15,19 +15,22 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
15 None => return Ok(()), 15 None => return Ok(()),
16 }; 16 };
17 if let Some(function) = &ctx.function { 17 if let Some(function) = &ctx.function {
18 let scopes = function.scopes(ctx.db); 18 let scopes = function.scopes(ctx.db)?;
19 complete_fn(acc, &scopes, ctx.offset); 19 complete_fn(acc, &scopes, ctx.offset);
20 } 20 }
21 21
22 let module_scope = module.scope(ctx.db)?; 22 let module_scope = module.scope(ctx.db)?;
23 let (file_id, _) = module.defenition_source(ctx.db)?;
23 module_scope 24 module_scope
24 .entries() 25 .entries()
25 .filter(|(_name, res)| { 26 .filter(|(_name, res)| {
26 // Don't expose this item 27 // Don't expose this item
28 // FIXME: this penetrates through all kinds of abstractions,
29 // we need to figura out the way to do it less ugly.
27 match res.import { 30 match res.import {
28 None => true, 31 None => true,
29 Some(import) => { 32 Some(import) => {
30 let range = import.range(ctx.db, module.file_id()); 33 let range = import.range(ctx.db, file_id);
31 !range.is_subrange(&ctx.leaf.range()) 34 !range.is_subrange(&ctx.leaf.range())
32 } 35 }
33 } 36 }
@@ -40,20 +43,17 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
40 Ok(()) 43 Ok(())
41} 44}
42 45
43fn complete_fn(acc: &mut Completions, scopes: &hir::FnScopes, offset: TextUnit) { 46fn complete_fn(acc: &mut Completions, scopes: &hir::ScopesWithSyntaxMapping, offset: TextUnit) {
44 let mut shadowed = FxHashSet::default(); 47 let mut shadowed = FxHashSet::default();
45 scopes 48 scopes
46 .scope_chain_for_offset(offset) 49 .scope_chain_for_offset(offset)
47 .flat_map(|scope| scopes.entries(scope).iter()) 50 .flat_map(|scope| scopes.scopes.entries(scope).iter())
48 .filter(|entry| shadowed.insert(entry.name())) 51 .filter(|entry| shadowed.insert(entry.name()))
49 .for_each(|entry| { 52 .for_each(|entry| {
50 CompletionItem::new(CompletionKind::Reference, entry.name().to_string()) 53 CompletionItem::new(CompletionKind::Reference, entry.name().to_string())
51 .kind(CompletionItemKind::Binding) 54 .kind(CompletionItemKind::Binding)
52 .add_to(acc) 55 .add_to(acc)
53 }); 56 });
54 if scopes.self_param.is_some() {
55 CompletionItem::new(CompletionKind::Reference, "self").add_to(acc);
56 }
57} 57}
58 58
59#[cfg(test)] 59#[cfg(test)]
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index 5422a400b..1709be5cf 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -106,6 +106,9 @@ salsa::database_storage! {
106 fn struct_data() for hir::db::StructDataQuery; 106 fn struct_data() for hir::db::StructDataQuery;
107 fn enum_data() for hir::db::EnumDataQuery; 107 fn enum_data() for hir::db::EnumDataQuery;
108 fn impls_in_module() for hir::db::ImplsInModuleQuery; 108 fn impls_in_module() for hir::db::ImplsInModuleQuery;
109 fn body_hir() for hir::db::BodyHirQuery;
110 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery;
111 fn fn_signature() for hir::db::FnSignatureQuery;
109 } 112 }
110 } 113 }
111} 114}
diff --git a/crates/ra_analysis/src/goto_defenition.rs b/crates/ra_analysis/src/goto_defenition.rs
index e37421f8d..aa0616e3b 100644
--- a/crates/ra_analysis/src/goto_defenition.rs
+++ b/crates/ra_analysis/src/goto_defenition.rs
@@ -28,7 +28,7 @@ pub(crate) fn reference_defenition(
28 if let Some(fn_descr) = 28 if let Some(fn_descr) =
29 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())? 29 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
30 { 30 {
31 let scope = fn_descr.scopes(db); 31 let scope = fn_descr.scopes(db)?;
32 // First try to resolve the symbol locally 32 // First try to resolve the symbol locally
33 if let Some(entry) = scope.resolve_local_name(name_ref) { 33 if let Some(entry) = scope.resolve_local_name(name_ref) {
34 let nav = NavigationTarget { 34 let nav = NavigationTarget {
@@ -60,8 +60,8 @@ fn name_defenition(
60 if let Some(child_module) = 60 if let Some(child_module) =
61 hir::source_binder::module_from_declaration(db, file_id, module)? 61 hir::source_binder::module_from_declaration(db, file_id, module)?
62 { 62 {
63 let file_id = child_module.file_id(); 63 let (file_id, _) = child_module.defenition_source(db)?;
64 let name = match child_module.name() { 64 let name = match child_module.name(db)? {
65 Some(name) => name.to_string().into(), 65 Some(name) => name.to_string().into(),
66 None => "".into(), 66 None => "".into(),
67 }; 67 };
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 6ab3c5476..07a966290 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -105,39 +105,35 @@ impl db::RootDatabase {
105 &self, 105 &self,
106 position: FilePosition, 106 position: FilePosition,
107 ) -> Cancelable<Vec<NavigationTarget>> { 107 ) -> Cancelable<Vec<NavigationTarget>> {
108 let descr = match source_binder::module_from_position(self, position)? { 108 let module = match source_binder::module_from_position(self, position)? {
109 None => return Ok(Vec::new()), 109 None => return Ok(Vec::new()),
110 Some(it) => it, 110 Some(it) => it,
111 }; 111 };
112 let (file_id, decl) = match descr.parent_link_source(self) { 112 let (file_id, ast_module) = match module.declaration_source(self)? {
113 None => return Ok(Vec::new()), 113 None => return Ok(Vec::new()),
114 Some(it) => it, 114 Some(it) => it,
115 }; 115 };
116 let decl = decl.borrowed(); 116 let ast_module = ast_module.borrowed();
117 let decl_name = decl.name().unwrap(); 117 let name = ast_module.name().unwrap();
118 Ok(vec![NavigationTarget { 118 Ok(vec![NavigationTarget {
119 file_id, 119 file_id,
120 name: decl_name.text(), 120 name: name.text(),
121 range: decl_name.syntax().range(), 121 range: name.syntax().range(),
122 kind: MODULE, 122 kind: MODULE,
123 ptr: None, 123 ptr: None,
124 }]) 124 }])
125 } 125 }
126 /// Returns `Vec` for the same reason as `parent_module` 126 /// Returns `Vec` for the same reason as `parent_module`
127 pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 127 pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
128 let descr = match source_binder::module_from_file_id(self, file_id)? { 128 let module = match source_binder::module_from_file_id(self, file_id)? {
129 Some(it) => it,
129 None => return Ok(Vec::new()), 130 None => return Ok(Vec::new()),
131 };
132 let krate = match module.krate(self)? {
130 Some(it) => it, 133 Some(it) => it,
134 None => return Ok(Vec::new()),
131 }; 135 };
132 let root = descr.crate_root(); 136 Ok(vec![krate.crate_id()])
133 let file_id = root.file_id();
134
135 let crate_graph = self.crate_graph();
136 let crate_id = crate_graph.crate_id_for_crate_root(file_id);
137 Ok(crate_id.into_iter().collect())
138 }
139 pub(crate) fn crate_root(&self, crate_id: CrateId) -> FileId {
140 self.crate_graph().crate_root(crate_id)
141 } 137 }
142 pub(crate) fn find_all_refs( 138 pub(crate) fn find_all_refs(
143 &self, 139 &self,
@@ -157,7 +153,7 @@ impl db::RootDatabase {
157 .collect::<Vec<_>>(); 153 .collect::<Vec<_>>();
158 ret.extend( 154 ret.extend(
159 descr 155 descr
160 .scopes(self) 156 .scopes(self)?
161 .find_all_refs(binding) 157 .find_all_refs(binding)
162 .into_iter() 158 .into_iter()
163 .map(|ref_desc| (position.file_id, ref_desc.range)), 159 .map(|ref_desc| (position.file_id, ref_desc.range)),
@@ -185,7 +181,7 @@ impl db::RootDatabase {
185 position.file_id, 181 position.file_id,
186 name_ref.syntax(), 182 name_ref.syntax(),
187 )?); 183 )?);
188 let scope = descr.scopes(db); 184 let scope = descr.scopes(db)?;
189 let resolved = ctry!(scope.resolve_local_name(name_ref)); 185 let resolved = ctry!(scope.resolve_local_name(name_ref));
190 let resolved = resolved.ptr().resolve(source_file); 186 let resolved = resolved.ptr().resolve(source_file);
191 let binding = ctry!(find_node_at_offset::<ast::BindPat>( 187 let binding = ctry!(find_node_at_offset::<ast::BindPat>(
@@ -209,7 +205,7 @@ impl db::RootDatabase {
209 }) 205 })
210 .collect::<Vec<_>>(); 206 .collect::<Vec<_>>();
211 if let Some(m) = source_binder::module_from_file_id(self, file_id)? { 207 if let Some(m) = source_binder::module_from_file_id(self, file_id)? {
212 for (name_node, problem) in m.problems(self) { 208 for (name_node, problem) in m.problems(self)? {
213 let source_root = self.file_source_root(file_id); 209 let source_root = self.file_source_root(file_id);
214 let diag = match problem { 210 let diag = match problem {
215 Problem::UnresolvedModule { candidate } => { 211 Problem::UnresolvedModule { candidate } => {
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 390c31c3f..77f77e9a8 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -397,7 +397,7 @@ impl Analysis {
397 } 397 }
398 /// Returns the root file of the given crate. 398 /// Returns the root file of the given crate.
399 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { 399 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
400 Ok(self.db.crate_root(crate_id)) 400 Ok(self.db.crate_graph().crate_root(crate_id))
401 } 401 }
402 /// Returns the set of possible targets to run for the current file. 402 /// Returns the set of possible targets to run for the current file.
403 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { 403 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
diff --git a/crates/ra_analysis/src/runnables.rs b/crates/ra_analysis/src/runnables.rs
index 474267605..216209098 100644
--- a/crates/ra_analysis/src/runnables.rs
+++ b/crates/ra_analysis/src/runnables.rs
@@ -72,12 +72,15 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
72 let range = module.syntax().range(); 72 let range = module.syntax().range();
73 let module = 73 let module =
74 hir::source_binder::module_from_child_node(db, file_id, module.syntax()).ok()??; 74 hir::source_binder::module_from_child_node(db, file_id, module.syntax()).ok()??;
75
76 // FIXME: thread cancellation instead of `.ok`ing
75 let path = module 77 let path = module
76 .path_to_root() 78 .path_to_root(db)
79 .ok()?
77 .into_iter() 80 .into_iter()
78 .rev() 81 .rev()
79 .into_iter() 82 .filter_map(|it| it.name(db).ok())
80 .filter_map(|it| it.name().map(Clone::clone)) 83 .filter_map(|it| it)
81 .join("::"); 84 .join("::");
82 Some(Runnable { 85 Some(Runnable {
83 range, 86 range,
diff --git a/crates/ra_analysis/tests/test/main.rs b/crates/ra_analysis/tests/test/main.rs
index 26da7c10c..1f70af12a 100644
--- a/crates/ra_analysis/tests/test/main.rs
+++ b/crates/ra_analysis/tests/test/main.rs
@@ -31,6 +31,7 @@ fn test_unresolved_module_diagnostic() {
31 ); 31 );
32} 32}
33 33
34// FIXME: move this test to hir
34#[test] 35#[test]
35fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 36fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
36 let (analysis, file_id) = single_file("mod foo {}"); 37 let (analysis, file_id) = single_file("mod foo {}");
@@ -69,7 +70,7 @@ fn test_resolve_parent_module_for_inline() {
69 ); 70 );
70 let symbols = analysis.parent_module(pos).unwrap(); 71 let symbols = analysis.parent_module(pos).unwrap();
71 assert_eq_dbg( 72 assert_eq_dbg(
72 r#"[NavigationTarget { file_id: FileId(1), name: "bar", kind: MODULE, range: [18; 21), ptr: None }]"#, 73 r#"[NavigationTarget { file_id: FileId(1), name: "baz", kind: MODULE, range: [36; 39), ptr: None }]"#,
73 &symbols, 74 &symbols,
74 ); 75 );
75} 76}
diff --git a/crates/ra_db/src/syntax_ptr.rs b/crates/ra_db/src/syntax_ptr.rs
index 744cb2352..5bfcedf2b 100644
--- a/crates/ra_db/src/syntax_ptr.rs
+++ b/crates/ra_db/src/syntax_ptr.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange}; 1use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange};
2 2
3/// A pionter to a syntax node inside a file. 3/// A pointer to a syntax node inside a file.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct LocalSyntaxPtr { 5pub struct LocalSyntaxPtr {
6 range: TextRange, 6 range: TextRange,
diff --git a/crates/ra_editor/src/assists/split_import.rs b/crates/ra_editor/src/assists/split_import.rs
index 75f9e8dfb..e4015f07d 100644
--- a/crates/ra_editor/src/assists/split_import.rs
+++ b/crates/ra_editor/src/assists/split_import.rs
@@ -19,7 +19,10 @@ pub fn split_import(ctx: AssistCtx) -> Option<Assist> {
19 } 19 }
20 20
21 let l_curly = colon_colon.range().end(); 21 let l_curly = colon_colon.range().end();
22 let r_curly = top_path.syntax().range().end(); 22 let r_curly = match top_path.syntax().parent().and_then(ast::UseTree::cast) {
23 Some(tree) => tree.syntax().range().end(),
24 None => top_path.syntax().range().end(),
25 };
23 26
24 ctx.build("split import", |edit| { 27 ctx.build("split import", |edit| {
25 edit.insert(l_curly, "{"); 28 edit.insert(l_curly, "{");
@@ -41,4 +44,13 @@ mod tests {
41 "use crate::{<|>db::RootDatabase};", 44 "use crate::{<|>db::RootDatabase};",
42 ) 45 )
43 } 46 }
47
48 #[test]
49 fn split_import_works_with_trees() {
50 check_assist(
51 split_import,
52 "use algo:<|>:visitor::{Visitor, visit}",
53 "use algo::{<|>visitor::{Visitor, visit}}",
54 )
55 }
44} 56}
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
new file mode 100644
index 000000000..09b532f74
--- /dev/null
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -0,0 +1,110 @@
1use relative_path::RelativePathBuf;
2use ra_db::{CrateId, Cancelable, FileId};
3use ra_syntax::{ast, SyntaxNode};
4
5use crate::{Name, db::HirDatabase, DefId, Path, PerNs, nameres::ModuleScope};
6
7/// hir::Crate describes a single crate. It's the main inteface with which
8/// crate's dependencies interact. Mostly, it should be just a proxy for the
9/// root module.
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Crate {
12 pub(crate) crate_id: CrateId,
13}
14
15#[derive(Debug)]
16pub struct CrateDependency {
17 pub krate: Crate,
18 pub name: Name,
19}
20
21impl Crate {
22 pub fn crate_id(&self) -> CrateId {
23 self.crate_id
24 }
25 pub fn dependencies(&self, db: &impl HirDatabase) -> Cancelable<Vec<CrateDependency>> {
26 Ok(self.dependencies_impl(db))
27 }
28 pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
29 self.root_module_impl(db)
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct Module {
35 pub(crate) def_id: DefId,
36}
37
38pub enum ModuleSource {
39 SourceFile(ast::SourceFileNode),
40 Module(ast::ModuleNode),
41}
42
43#[derive(Clone, Debug, Hash, PartialEq, Eq)]
44pub enum Problem {
45 UnresolvedModule {
46 candidate: RelativePathBuf,
47 },
48 NotDirOwner {
49 move_to: RelativePathBuf,
50 candidate: RelativePathBuf,
51 },
52}
53
54impl Module {
55 /// Name of this module.
56 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
57 self.name_impl(db)
58 }
59
60 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
61 pub fn defenition_source(&self, db: &impl HirDatabase) -> Cancelable<(FileId, ModuleSource)> {
62 self.defenition_source_impl(db)
63 }
64 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
65 /// `None` for the crate root.
66 pub fn declaration_source(
67 &self,
68 db: &impl HirDatabase,
69 ) -> Cancelable<Option<(FileId, ast::ModuleNode)>> {
70 self.declaration_source_impl(db)
71 }
72
73 /// Returns the crate this module is part of.
74 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
75 self.krate_impl(db)
76 }
77 /// Topmost parent of this module. Every module has a `crate_root`, but some
78 /// might miss `krate`. This can happen if a module's file is not included
79 /// into any module tree of any target from Cargo.toml.
80 pub fn crate_root(&self, db: &impl HirDatabase) -> Cancelable<Module> {
81 self.crate_root_impl(db)
82 }
83 /// Finds a child module with the specified name.
84 pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
85 self.child_impl(db, name)
86 }
87 /// Finds a parent module.
88 pub fn parent(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
89 self.parent_impl(db)
90 }
91 pub fn path_to_root(&self, db: &impl HirDatabase) -> Cancelable<Vec<Module>> {
92 let mut res = vec![self.clone()];
93 let mut curr = self.clone();
94 while let Some(next) = curr.parent(db)? {
95 res.push(next.clone());
96 curr = next
97 }
98 Ok(res)
99 }
100 /// Returns a `ModuleScope`: a set of items, visible in this module.
101 pub fn scope(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
102 self.scope_impl(db)
103 }
104 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
105 self.resolve_path_impl(db, path)
106 }
107 pub fn problems(&self, db: &impl HirDatabase) -> Cancelable<Vec<(SyntaxNode, Problem)>> {
108 self.problems_impl(db)
109 }
110}
diff --git a/crates/ra_hir/src/code_model_impl.rs b/crates/ra_hir/src/code_model_impl.rs
new file mode 100644
index 000000000..157b0c616
--- /dev/null
+++ b/crates/ra_hir/src/code_model_impl.rs
@@ -0,0 +1,2 @@
1mod krate; // `crate` is invalid ident :(
2mod module;
diff --git a/crates/ra_hir/src/code_model_impl/krate.rs b/crates/ra_hir/src/code_model_impl/krate.rs
new file mode 100644
index 000000000..3275eafed
--- /dev/null
+++ b/crates/ra_hir/src/code_model_impl/krate.rs
@@ -0,0 +1,47 @@
1use ra_db::{CrateId, Cancelable};
2
3use crate::{
4 HirFileId, Crate, CrateDependency, AsName, DefLoc, DefKind, Module, SourceItemId,
5 db::HirDatabase,
6};
7
8impl Crate {
9 pub(crate) fn new(crate_id: CrateId) -> Crate {
10 Crate { crate_id }
11 }
12 pub(crate) fn dependencies_impl(&self, db: &impl HirDatabase) -> Vec<CrateDependency> {
13 let crate_graph = db.crate_graph();
14 crate_graph
15 .dependencies(self.crate_id)
16 .map(|dep| {
17 let krate = Crate::new(dep.crate_id());
18 let name = dep.as_name();
19 CrateDependency { krate, name }
20 })
21 .collect()
22 }
23 pub(crate) fn root_module_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
24 let crate_graph = db.crate_graph();
25 let file_id = crate_graph.crate_root(self.crate_id);
26 let source_root_id = db.file_source_root(file_id);
27 let file_id = HirFileId::from(file_id);
28 let module_tree = db.module_tree(source_root_id)?;
29 // FIXME: teach module tree about crate roots instead of guessing
30 let source = SourceItemId {
31 file_id,
32 item_id: None,
33 };
34 let module_id = ctry!(module_tree.find_module_by_source(source));
35
36 let def_loc = DefLoc {
37 kind: DefKind::Module,
38 source_root_id,
39 module_id,
40 source_item_id: module_id.source(&module_tree),
41 };
42 let def_id = def_loc.id(db);
43
44 let module = Module::new(def_id);
45 Ok(Some(module))
46 }
47}
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
new file mode 100644
index 000000000..eb35779f1
--- /dev/null
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -0,0 +1,154 @@
1use ra_db::{Cancelable, SourceRootId, FileId};
2use ra_syntax::{ast, SyntaxNode, AstNode};
3
4use crate::{
5 Module, ModuleSource, Problem,
6 Crate, DefId, DefLoc, DefKind, Name, Path, PathKind, PerNs, Def, ModuleId,
7 nameres::ModuleScope,
8 db::HirDatabase,
9};
10
11impl Module {
12 pub(crate) fn new(def_id: DefId) -> Self {
13 crate::code_model_api::Module { def_id }
14 }
15 pub(crate) fn from_module_id(
16 db: &impl HirDatabase,
17 source_root_id: SourceRootId,
18 module_id: ModuleId,
19 ) -> Cancelable<Self> {
20 let module_tree = db.module_tree(source_root_id)?;
21 let def_loc = DefLoc {
22 kind: DefKind::Module,
23 source_root_id,
24 module_id,
25 source_item_id: module_id.source(&module_tree),
26 };
27 let def_id = def_loc.id(db);
28 let module = Module::new(def_id);
29 Ok(module)
30 }
31
32 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
33 let loc = self.def_id.loc(db);
34 let module_tree = db.module_tree(loc.source_root_id)?;
35 let link = ctry!(loc.module_id.parent_link(&module_tree));
36 Ok(Some(link.name(&module_tree).clone()))
37 }
38
39 pub fn defenition_source_impl(
40 &self,
41 db: &impl HirDatabase,
42 ) -> Cancelable<(FileId, ModuleSource)> {
43 let loc = self.def_id.loc(db);
44 let file_id = loc.source_item_id.file_id.as_original_file();
45 let syntax_node = db.file_item(loc.source_item_id);
46 let syntax_node = syntax_node.borrowed();
47 let module_source = if let Some(source_file) = ast::SourceFile::cast(syntax_node) {
48 ModuleSource::SourceFile(source_file.owned())
49 } else {
50 let module = ast::Module::cast(syntax_node).unwrap();
51 ModuleSource::Module(module.owned())
52 };
53 Ok((file_id, module_source))
54 }
55
56 pub fn declaration_source_impl(
57 &self,
58 db: &impl HirDatabase,
59 ) -> Cancelable<Option<(FileId, ast::ModuleNode)>> {
60 let loc = self.def_id.loc(db);
61 let module_tree = db.module_tree(loc.source_root_id)?;
62 let link = ctry!(loc.module_id.parent_link(&module_tree));
63 let file_id = link
64 .owner(&module_tree)
65 .source(&module_tree)
66 .file_id
67 .as_original_file();
68 let src = link.source(&module_tree, db);
69 Ok(Some((file_id, src)))
70 }
71
72 pub(crate) fn krate_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
73 let root = self.crate_root(db)?;
74 let loc = root.def_id.loc(db);
75 let file_id = loc.source_item_id.file_id.as_original_file();
76
77 let crate_graph = db.crate_graph();
78 let crate_id = ctry!(crate_graph.crate_id_for_crate_root(file_id));
79 Ok(Some(Crate::new(crate_id)))
80 }
81
82 pub(crate) fn crate_root_impl(&self, db: &impl HirDatabase) -> Cancelable<Module> {
83 let loc = self.def_id.loc(db);
84 let module_tree = db.module_tree(loc.source_root_id)?;
85 let module_id = loc.module_id.crate_root(&module_tree);
86 Module::from_module_id(db, loc.source_root_id, module_id)
87 }
88 /// Finds a child module with the specified name.
89 pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
90 let loc = self.def_id.loc(db);
91 let module_tree = db.module_tree(loc.source_root_id)?;
92 let child_id = ctry!(loc.module_id.child(&module_tree, name));
93 Module::from_module_id(db, loc.source_root_id, child_id).map(Some)
94 }
95 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
96 let loc = self.def_id.loc(db);
97 let module_tree = db.module_tree(loc.source_root_id)?;
98 let parent_id = ctry!(loc.module_id.parent(&module_tree));
99 Module::from_module_id(db, loc.source_root_id, parent_id).map(Some)
100 }
101 /// Returns a `ModuleScope`: a set of items, visible in this module.
102 pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
103 let loc = self.def_id.loc(db);
104 let item_map = db.item_map(loc.source_root_id)?;
105 let res = item_map.per_module[&loc.module_id].clone();
106 Ok(res)
107 }
108 pub fn resolve_path_impl(
109 &self,
110 db: &impl HirDatabase,
111 path: &Path,
112 ) -> Cancelable<PerNs<DefId>> {
113 let mut curr_per_ns = PerNs::types(
114 match path.kind {
115 PathKind::Crate => self.crate_root(db)?,
116 PathKind::Self_ | PathKind::Plain => self.clone(),
117 PathKind::Super => {
118 if let Some(p) = self.parent(db)? {
119 p
120 } else {
121 return Ok(PerNs::none());
122 }
123 }
124 }
125 .def_id,
126 );
127
128 let segments = &path.segments;
129 for name in segments.iter() {
130 let curr = if let Some(r) = curr_per_ns.as_ref().take_types() {
131 r
132 } else {
133 return Ok(PerNs::none());
134 };
135 let module = match curr.resolve(db)? {
136 Def::Module(it) => it,
137 // TODO here would be the place to handle enum variants...
138 _ => return Ok(PerNs::none()),
139 };
140 let scope = module.scope(db)?;
141 curr_per_ns = if let Some(r) = scope.get(&name) {
142 r.def_id
143 } else {
144 return Ok(PerNs::none());
145 };
146 }
147 Ok(curr_per_ns)
148 }
149 pub fn problems_impl(&self, db: &impl HirDatabase) -> Cancelable<Vec<(SyntaxNode, Problem)>> {
150 let loc = self.def_id.loc(db);
151 let module_tree = db.module_tree(loc.source_root_id)?;
152 Ok(loc.module_id.problems(&module_tree, db))
153 }
154}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 58296fc6f..033f9d25f 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -7,10 +7,10 @@ use crate::{
7 DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, 7 DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId,
8 SourceFileItems, SourceItemId, 8 SourceFileItems, SourceItemId,
9 query_definitions, 9 query_definitions,
10 FnScopes, 10 FnSignature, FnScopes,
11 macros::MacroExpansion, 11 macros::MacroExpansion,
12 module::{ModuleId, ModuleTree, ModuleSource, 12 module_tree::{ModuleId, ModuleTree},
13 nameres::{ItemMap, InputModuleItems}}, 13 nameres::{ItemMap, InputModuleItems},
14 ty::{InferenceResult, Ty}, 14 ty::{InferenceResult, Ty},
15 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData},
16 impl_block::ModuleImplBlocks, 16 impl_block::ModuleImplBlocks,
@@ -31,7 +31,7 @@ pub trait HirDatabase: SyntaxDatabase
31 use fn crate::macros::expand_macro_invocation; 31 use fn crate::macros::expand_macro_invocation;
32 } 32 }
33 33
34 fn fn_scopes(def_id: DefId) -> Arc<FnScopes> { 34 fn fn_scopes(def_id: DefId) -> Cancelable<Arc<FnScopes>> {
35 type FnScopesQuery; 35 type FnScopesQuery;
36 use fn query_definitions::fn_scopes; 36 use fn query_definitions::fn_scopes;
37 } 37 }
@@ -71,9 +71,9 @@ pub trait HirDatabase: SyntaxDatabase
71 use fn query_definitions::file_item; 71 use fn query_definitions::file_item;
72 } 72 }
73 73
74 fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<crate::module::imp::Submodule>>> { 74 fn submodules(source: SourceItemId) -> Cancelable<Arc<Vec<crate::module_tree::Submodule>>> {
75 type SubmodulesQuery; 75 type SubmodulesQuery;
76 use fn query_definitions::submodules; 76 use fn crate::module_tree::Submodule::submodules_query;
77 } 77 }
78 78
79 fn input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> { 79 fn input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> {
@@ -86,13 +86,28 @@ pub trait HirDatabase: SyntaxDatabase
86 } 86 }
87 fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { 87 fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
88 type ModuleTreeQuery; 88 type ModuleTreeQuery;
89 use fn crate::module::imp::module_tree; 89 use fn crate::module_tree::ModuleTree::module_tree_query;
90 } 90 }
91 91
92 fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> { 92 fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> {
93 type ImplsInModuleQuery; 93 type ImplsInModuleQuery;
94 use fn crate::impl_block::impls_in_module; 94 use fn crate::impl_block::impls_in_module;
95 } 95 }
96
97 fn body_hir(def_id: DefId) -> Cancelable<Arc<crate::expr::Body>> {
98 type BodyHirQuery;
99 use fn crate::expr::body_hir;
100 }
101
102 fn body_syntax_mapping(def_id: DefId) -> Cancelable<Arc<crate::expr::BodySyntaxMapping>> {
103 type BodySyntaxMappingQuery;
104 use fn crate::expr::body_syntax_mapping;
105 }
106
107 fn fn_signature(def_id: DefId) -> Arc<FnSignature> {
108 type FnSignatureQuery;
109 use fn crate::function::fn_signature;
110 }
96} 111}
97 112
98} 113}
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
new file mode 100644
index 000000000..6866fc2ac
--- /dev/null
+++ b/crates/ra_hir/src/expr.rs
@@ -0,0 +1,745 @@
1use std::ops::Index;
2use std::sync::Arc;
3
4use rustc_hash::FxHashMap;
5
6use ra_arena::{Arena, RawId, impl_arena_id};
7use ra_db::{LocalSyntaxPtr, Cancelable};
8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner};
9
10use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct ExprId(RawId);
14impl_arena_id!(ExprId);
15
16/// The body of an item (function, const etc.).
17#[derive(Debug, Eq, PartialEq)]
18pub struct Body {
19 exprs: Arena<ExprId, Expr>,
20 pats: Arena<PatId, Pat>,
21 /// The patterns for the function's arguments. While the argument types are
22 /// part of the function signature, the patterns are not (they don't change
23 /// the external type of the function).
24 ///
25 /// If this `Body` is for the body of a constant, this will just be
26 /// empty.
27 args: Vec<PatId>,
28 /// The `ExprId` of the actual body expression.
29 body_expr: ExprId,
30}
31
32/// An item body together with the mapping from syntax nodes to HIR expression
33/// IDs. This is needed to go from e.g. a position in a file to the HIR
34/// expression containing it; but for type inference etc., we want to operate on
35/// a structure that is agnostic to the actual positions of expressions in the
36/// file, so that we don't recompute the type inference whenever some whitespace
37/// is typed.
38#[derive(Debug, Eq, PartialEq)]
39pub struct BodySyntaxMapping {
40 body: Arc<Body>,
41 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>,
42 expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>,
43 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
44 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>,
45}
46
47impl Body {
48 pub fn args(&self) -> &[PatId] {
49 &self.args
50 }
51
52 pub fn body_expr(&self) -> ExprId {
53 self.body_expr
54 }
55}
56
57impl Index<ExprId> for Body {
58 type Output = Expr;
59
60 fn index(&self, expr: ExprId) -> &Expr {
61 &self.exprs[expr]
62 }
63}
64
65impl Index<PatId> for Body {
66 type Output = Pat;
67
68 fn index(&self, pat: PatId) -> &Pat {
69 &self.pats[pat]
70 }
71}
72
73impl BodySyntaxMapping {
74 pub fn expr_syntax(&self, expr: ExprId) -> Option<LocalSyntaxPtr> {
75 self.expr_syntax_mapping_back.get(&expr).cloned()
76 }
77 pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> {
78 self.expr_syntax_mapping.get(&ptr).cloned()
79 }
80 pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> {
81 self.pat_syntax_mapping_back.get(&pat).cloned()
82 }
83 pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> {
84 self.pat_syntax_mapping.get(&ptr).cloned()
85 }
86
87 pub fn body(&self) -> &Arc<Body> {
88 &self.body
89 }
90}
91
92#[derive(Debug, Clone, Eq, PartialEq)]
93pub enum Expr {
94 /// This is produced if syntax tree does not have a required expression piece.
95 Missing,
96 Path(Path),
97 If {
98 condition: ExprId,
99 then_branch: ExprId,
100 else_branch: Option<ExprId>,
101 },
102 Block {
103 statements: Vec<Statement>,
104 tail: Option<ExprId>,
105 },
106 Loop {
107 body: ExprId,
108 },
109 While {
110 condition: ExprId,
111 body: ExprId,
112 },
113 For {
114 iterable: ExprId,
115 pat: PatId,
116 body: ExprId,
117 },
118 Call {
119 callee: ExprId,
120 args: Vec<ExprId>,
121 },
122 MethodCall {
123 receiver: ExprId,
124 method_name: Name,
125 args: Vec<ExprId>,
126 },
127 Match {
128 expr: ExprId,
129 arms: Vec<MatchArm>,
130 },
131 Continue,
132 Break {
133 expr: Option<ExprId>,
134 },
135 Return {
136 expr: Option<ExprId>,
137 },
138 StructLit {
139 path: Option<Path>,
140 fields: Vec<StructLitField>,
141 spread: Option<ExprId>,
142 },
143 Field {
144 expr: ExprId,
145 name: Name,
146 },
147 Try {
148 expr: ExprId,
149 },
150 Cast {
151 expr: ExprId,
152 type_ref: TypeRef,
153 },
154 Ref {
155 expr: ExprId,
156 mutability: Mutability,
157 },
158 UnaryOp {
159 expr: ExprId,
160 op: Option<UnaryOp>,
161 },
162 Lambda {
163 args: Vec<PatId>,
164 arg_types: Vec<Option<TypeRef>>,
165 body: ExprId,
166 },
167}
168
169pub type UnaryOp = ast::PrefixOp;
170
171#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct MatchArm {
173 pub pats: Vec<PatId>,
174 // guard: Option<ExprId>, // TODO
175 pub expr: ExprId,
176}
177
178#[derive(Debug, Clone, Eq, PartialEq)]
179pub struct StructLitField {
180 pub name: Name,
181 pub expr: ExprId,
182}
183
184#[derive(Debug, Clone, Eq, PartialEq)]
185pub enum Statement {
186 Let {
187 pat: PatId,
188 type_ref: Option<TypeRef>,
189 initializer: Option<ExprId>,
190 },
191 Expr(ExprId),
192}
193
194impl Expr {
195 pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
196 match self {
197 Expr::Missing => {}
198 Expr::Path(_) => {}
199 Expr::If {
200 condition,
201 then_branch,
202 else_branch,
203 } => {
204 f(*condition);
205 f(*then_branch);
206 if let Some(else_branch) = else_branch {
207 f(*else_branch);
208 }
209 }
210 Expr::Block { statements, tail } => {
211 for stmt in statements {
212 match stmt {
213 Statement::Let { initializer, .. } => {
214 if let Some(expr) = initializer {
215 f(*expr);
216 }
217 }
218 Statement::Expr(e) => f(*e),
219 }
220 }
221 if let Some(expr) = tail {
222 f(*expr);
223 }
224 }
225 Expr::Loop { body } => f(*body),
226 Expr::While { condition, body } => {
227 f(*condition);
228 f(*body);
229 }
230 Expr::For { iterable, body, .. } => {
231 f(*iterable);
232 f(*body);
233 }
234 Expr::Call { callee, args } => {
235 f(*callee);
236 for arg in args {
237 f(*arg);
238 }
239 }
240 Expr::MethodCall { receiver, args, .. } => {
241 f(*receiver);
242 for arg in args {
243 f(*arg);
244 }
245 }
246 Expr::Match { expr, arms } => {
247 f(*expr);
248 for arm in arms {
249 f(arm.expr);
250 }
251 }
252 Expr::Continue => {}
253 Expr::Break { expr } | Expr::Return { expr } => {
254 if let Some(expr) = expr {
255 f(*expr);
256 }
257 }
258 Expr::StructLit { fields, spread, .. } => {
259 for field in fields {
260 f(field.expr);
261 }
262 if let Some(expr) = spread {
263 f(*expr);
264 }
265 }
266 Expr::Lambda { body, .. } => {
267 f(*body);
268 }
269 Expr::Field { expr, .. }
270 | Expr::Try { expr }
271 | Expr::Cast { expr, .. }
272 | Expr::Ref { expr, .. }
273 | Expr::UnaryOp { expr, .. } => {
274 f(*expr);
275 }
276 }
277 }
278}
279
280#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
281pub struct PatId(RawId);
282impl_arena_id!(PatId);
283
284#[derive(Debug, Clone, Eq, PartialEq)]
285pub enum Pat {
286 Missing,
287 Bind {
288 name: Name,
289 },
290 TupleStruct {
291 path: Option<Path>,
292 args: Vec<PatId>,
293 },
294}
295
296impl Pat {
297 pub fn walk_child_pats(&self, f: impl FnMut(PatId)) {
298 match self {
299 Pat::Missing | Pat::Bind { .. } => {}
300 Pat::TupleStruct { args, .. } => {
301 args.iter().map(|pat| *pat).for_each(f);
302 }
303 }
304 }
305}
306
307// Queries
308
309pub(crate) fn body_hir(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<Body>> {
310 Ok(Arc::clone(&body_syntax_mapping(db, def_id)?.body))
311}
312
313struct ExprCollector {
314 exprs: Arena<ExprId, Expr>,
315 pats: Arena<PatId, Pat>,
316 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>,
317 expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>,
318 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
319 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>,
320}
321
322impl ExprCollector {
323 fn new() -> Self {
324 ExprCollector {
325 exprs: Arena::default(),
326 pats: Arena::default(),
327 expr_syntax_mapping: FxHashMap::default(),
328 expr_syntax_mapping_back: FxHashMap::default(),
329 pat_syntax_mapping: FxHashMap::default(),
330 pat_syntax_mapping_back: FxHashMap::default(),
331 }
332 }
333
334 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId {
335 let id = self.exprs.alloc(expr);
336 self.expr_syntax_mapping.insert(syntax_ptr, id);
337 self.expr_syntax_mapping_back.insert(id, syntax_ptr);
338 id
339 }
340
341 fn alloc_pat(&mut self, pat: Pat, syntax_ptr: LocalSyntaxPtr) -> PatId {
342 let id = self.pats.alloc(pat);
343 self.pat_syntax_mapping.insert(syntax_ptr, id);
344 self.pat_syntax_mapping_back.insert(id, syntax_ptr);
345 id
346 }
347
348 fn empty_block(&mut self) -> ExprId {
349 let block = Expr::Block {
350 statements: Vec::new(),
351 tail: None,
352 };
353 self.exprs.alloc(block)
354 }
355
356 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
357 let syntax_ptr = LocalSyntaxPtr::new(expr.syntax());
358 match expr {
359 ast::Expr::IfExpr(e) => {
360 if let Some(pat) = e.condition().and_then(|c| c.pat()) {
361 // if let -- desugar to match
362 let pat = self.collect_pat(pat);
363 let match_expr =
364 self.collect_expr_opt(e.condition().expect("checked above").expr());
365 let then_branch = self.collect_block_opt(e.then_branch());
366 let else_branch = e
367 .else_branch()
368 .map(|e| self.collect_block(e))
369 .unwrap_or_else(|| self.empty_block());
370 let placeholder_pat = self.pats.alloc(Pat::Missing);
371 let arms = vec![
372 MatchArm {
373 pats: vec![pat],
374 expr: then_branch,
375 },
376 MatchArm {
377 pats: vec![placeholder_pat],
378 expr: else_branch,
379 },
380 ];
381 self.alloc_expr(
382 Expr::Match {
383 expr: match_expr,
384 arms,
385 },
386 syntax_ptr,
387 )
388 } else {
389 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
390 let then_branch = self.collect_block_opt(e.then_branch());
391 let else_branch = e.else_branch().map(|e| self.collect_block(e));
392 self.alloc_expr(
393 Expr::If {
394 condition,
395 then_branch,
396 else_branch,
397 },
398 syntax_ptr,
399 )
400 }
401 }
402 ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
403 ast::Expr::LoopExpr(e) => {
404 let body = self.collect_block_opt(e.loop_body());
405 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
406 }
407 ast::Expr::WhileExpr(e) => {
408 let condition = if let Some(condition) = e.condition() {
409 if condition.pat().is_none() {
410 self.collect_expr_opt(condition.expr())
411 } else {
412 // TODO handle while let
413 return self.alloc_expr(Expr::Missing, syntax_ptr);
414 }
415 } else {
416 self.exprs.alloc(Expr::Missing)
417 };
418 let body = self.collect_block_opt(e.loop_body());
419 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
420 }
421 ast::Expr::ForExpr(e) => {
422 let iterable = self.collect_expr_opt(e.iterable());
423 let pat = self.collect_pat_opt(e.pat());
424 let body = self.collect_block_opt(e.loop_body());
425 self.alloc_expr(
426 Expr::For {
427 iterable,
428 pat,
429 body,
430 },
431 syntax_ptr,
432 )
433 }
434 ast::Expr::CallExpr(e) => {
435 let callee = self.collect_expr_opt(e.expr());
436 let args = if let Some(arg_list) = e.arg_list() {
437 arg_list.args().map(|e| self.collect_expr(e)).collect()
438 } else {
439 Vec::new()
440 };
441 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
442 }
443 ast::Expr::MethodCallExpr(e) => {
444 let receiver = self.collect_expr_opt(e.expr());
445 let args = if let Some(arg_list) = e.arg_list() {
446 arg_list.args().map(|e| self.collect_expr(e)).collect()
447 } else {
448 Vec::new()
449 };
450 let method_name = e
451 .name_ref()
452 .map(|nr| nr.as_name())
453 .unwrap_or_else(Name::missing);
454 self.alloc_expr(
455 Expr::MethodCall {
456 receiver,
457 method_name,
458 args,
459 },
460 syntax_ptr,
461 )
462 }
463 ast::Expr::MatchExpr(e) => {
464 let expr = self.collect_expr_opt(e.expr());
465 let arms = if let Some(match_arm_list) = e.match_arm_list() {
466 match_arm_list
467 .arms()
468 .map(|arm| MatchArm {
469 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
470 expr: self.collect_expr_opt(arm.expr()),
471 })
472 .collect()
473 } else {
474 Vec::new()
475 };
476 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
477 }
478 ast::Expr::PathExpr(e) => {
479 let path = e
480 .path()
481 .and_then(Path::from_ast)
482 .map(Expr::Path)
483 .unwrap_or(Expr::Missing);
484 self.alloc_expr(path, syntax_ptr)
485 }
486 ast::Expr::ContinueExpr(_e) => {
487 // TODO: labels
488 self.alloc_expr(Expr::Continue, syntax_ptr)
489 }
490 ast::Expr::BreakExpr(e) => {
491 let expr = e.expr().map(|e| self.collect_expr(e));
492 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
493 }
494 ast::Expr::ParenExpr(e) => {
495 let inner = self.collect_expr_opt(e.expr());
496 // make the paren expr point to the inner expression as well
497 self.expr_syntax_mapping.insert(syntax_ptr, inner);
498 inner
499 }
500 ast::Expr::ReturnExpr(e) => {
501 let expr = e.expr().map(|e| self.collect_expr(e));
502 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
503 }
504 ast::Expr::StructLit(e) => {
505 let path = e.path().and_then(Path::from_ast);
506 let fields = if let Some(nfl) = e.named_field_list() {
507 nfl.fields()
508 .map(|field| StructLitField {
509 name: field
510 .name_ref()
511 .map(|nr| nr.as_name())
512 .unwrap_or_else(Name::missing),
513 expr: if let Some(e) = field.expr() {
514 self.collect_expr(e)
515 } else if let Some(nr) = field.name_ref() {
516 // field shorthand
517 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(nr)));
518 self.expr_syntax_mapping
519 .insert(LocalSyntaxPtr::new(nr.syntax()), id);
520 self.expr_syntax_mapping_back
521 .insert(id, LocalSyntaxPtr::new(nr.syntax()));
522 id
523 } else {
524 self.exprs.alloc(Expr::Missing)
525 },
526 })
527 .collect()
528 } else {
529 Vec::new()
530 };
531 let spread = e.spread().map(|s| self.collect_expr(s));
532 self.alloc_expr(
533 Expr::StructLit {
534 path,
535 fields,
536 spread,
537 },
538 syntax_ptr,
539 )
540 }
541 ast::Expr::FieldExpr(e) => {
542 let expr = self.collect_expr_opt(e.expr());
543 let name = e
544 .name_ref()
545 .map(|nr| nr.as_name())
546 .unwrap_or_else(Name::missing);
547 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
548 }
549 ast::Expr::TryExpr(e) => {
550 let expr = self.collect_expr_opt(e.expr());
551 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
552 }
553 ast::Expr::CastExpr(e) => {
554 let expr = self.collect_expr_opt(e.expr());
555 let type_ref = TypeRef::from_ast_opt(e.type_ref());
556 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
557 }
558 ast::Expr::RefExpr(e) => {
559 let expr = self.collect_expr_opt(e.expr());
560 let mutability = Mutability::from_mutable(e.is_mut());
561 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
562 }
563 ast::Expr::PrefixExpr(e) => {
564 let expr = self.collect_expr_opt(e.expr());
565 let op = e.op();
566 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
567 }
568 ast::Expr::LambdaExpr(e) => {
569 let mut args = Vec::new();
570 let mut arg_types = Vec::new();
571 if let Some(pl) = e.param_list() {
572 for param in pl.params() {
573 let pat = self.collect_pat_opt(param.pat());
574 let type_ref = param.type_ref().map(TypeRef::from_ast);
575 args.push(pat);
576 arg_types.push(type_ref);
577 }
578 }
579 let body = self.collect_expr_opt(e.body());
580 self.alloc_expr(
581 Expr::Lambda {
582 args,
583 arg_types,
584 body,
585 },
586 syntax_ptr,
587 )
588 }
589
590 // TODO implement HIR for these:
591 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
592 ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
593 ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
594 ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
595 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
596 ast::Expr::BinExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
597 ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
598 }
599 }
600
601 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
602 if let Some(expr) = expr {
603 self.collect_expr(expr)
604 } else {
605 self.exprs.alloc(Expr::Missing)
606 }
607 }
608
609 fn collect_block(&mut self, block: ast::Block) -> ExprId {
610 let statements = block
611 .statements()
612 .map(|s| match s {
613 ast::Stmt::LetStmt(stmt) => {
614 let pat = self.collect_pat_opt(stmt.pat());
615 let type_ref = stmt.type_ref().map(TypeRef::from_ast);
616 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
617 Statement::Let {
618 pat,
619 type_ref,
620 initializer,
621 }
622 }
623 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
624 })
625 .collect();
626 let tail = block.expr().map(|e| self.collect_expr(e));
627 self.alloc_expr(
628 Expr::Block { statements, tail },
629 LocalSyntaxPtr::new(block.syntax()),
630 )
631 }
632
633 fn collect_block_opt(&mut self, block: Option<ast::Block>) -> ExprId {
634 if let Some(block) = block {
635 self.collect_block(block)
636 } else {
637 self.exprs.alloc(Expr::Missing)
638 }
639 }
640
641 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
642 let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
643 match pat {
644 ast::Pat::BindPat(bp) => {
645 let name = bp
646 .name()
647 .map(|nr| nr.as_name())
648 .unwrap_or_else(Name::missing);
649 self.alloc_pat(Pat::Bind { name }, syntax_ptr)
650 }
651 ast::Pat::TupleStructPat(p) => {
652 let path = p.path().and_then(Path::from_ast);
653 let args = p.args().map(|p| self.collect_pat(p)).collect();
654 self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr)
655 }
656 _ => {
657 // TODO
658 self.alloc_pat(Pat::Missing, syntax_ptr)
659 }
660 }
661 }
662
663 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
664 if let Some(pat) = pat {
665 self.collect_pat(pat)
666 } else {
667 self.pats.alloc(Pat::Missing)
668 }
669 }
670
671 fn into_body_syntax_mapping(self, args: Vec<PatId>, body_expr: ExprId) -> BodySyntaxMapping {
672 let body = Body {
673 exprs: self.exprs,
674 pats: self.pats,
675 args,
676 body_expr,
677 };
678 BodySyntaxMapping {
679 body: Arc::new(body),
680 expr_syntax_mapping: self.expr_syntax_mapping,
681 expr_syntax_mapping_back: self.expr_syntax_mapping_back,
682 pat_syntax_mapping: self.pat_syntax_mapping,
683 pat_syntax_mapping_back: self.pat_syntax_mapping_back,
684 }
685 }
686}
687
688pub(crate) fn collect_fn_body_syntax(node: ast::FnDef) -> BodySyntaxMapping {
689 let mut collector = ExprCollector::new();
690
691 let args = if let Some(param_list) = node.param_list() {
692 let mut args = Vec::new();
693
694 if let Some(self_param) = param_list.self_param() {
695 let self_param = LocalSyntaxPtr::new(
696 self_param
697 .self_kw()
698 .expect("self param without self keyword")
699 .syntax(),
700 );
701 let arg = collector.alloc_pat(
702 Pat::Bind {
703 name: Name::self_param(),
704 },
705 self_param,
706 );
707 args.push(arg);
708 }
709
710 for param in param_list.params() {
711 let pat = if let Some(pat) = param.pat() {
712 pat
713 } else {
714 continue;
715 };
716 args.push(collector.collect_pat(pat));
717 }
718 args
719 } else {
720 Vec::new()
721 };
722
723 let body = collector.collect_block_opt(node.body());
724 collector.into_body_syntax_mapping(args, body)
725}
726
727pub(crate) fn body_syntax_mapping(
728 db: &impl HirDatabase,
729 def_id: DefId,
730) -> Cancelable<Arc<BodySyntaxMapping>> {
731 let def = def_id.resolve(db)?;
732
733 let body_syntax_mapping = match def {
734 Def::Function(f) => {
735 let node = f.syntax(db);
736 let node = node.borrowed();
737
738 collect_fn_body_syntax(node)
739 }
740 // TODO: consts, etc.
741 _ => panic!("Trying to get body for item type without body"),
742 };
743
744 Ok(Arc::new(body_syntax_mapping))
745}
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index 75ef308ae..4627be071 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -11,9 +11,9 @@ use ra_syntax::{
11 ast::{self, AstNode, DocCommentsOwner, NameOwner}, 11 ast::{self, AstNode, DocCommentsOwner, NameOwner},
12}; 12};
13 13
14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock}; 14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock, expr::{Body, BodySyntaxMapping}, type_ref::{TypeRef, Mutability}, Name};
15 15
16pub use self::scope::FnScopes; 16pub use self::scope::{FnScopes, ScopesWithSyntaxMapping};
17 17
18#[derive(Debug, Clone, PartialEq, Eq)] 18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Function { 19pub struct Function {
@@ -36,8 +36,25 @@ impl Function {
36 ast::FnDef::cast(syntax.borrowed()).unwrap().owned() 36 ast::FnDef::cast(syntax.borrowed()).unwrap().owned()
37 } 37 }
38 38
39 pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> { 39 pub fn body(&self, db: &impl HirDatabase) -> Cancelable<Arc<Body>> {
40 db.fn_scopes(self.def_id) 40 db.body_hir(self.def_id)
41 }
42
43 pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Cancelable<Arc<BodySyntaxMapping>> {
44 db.body_syntax_mapping(self.def_id)
45 }
46
47 pub fn scopes(&self, db: &impl HirDatabase) -> Cancelable<ScopesWithSyntaxMapping> {
48 let scopes = db.fn_scopes(self.def_id)?;
49 let syntax_mapping = db.body_syntax_mapping(self.def_id)?;
50 Ok(ScopesWithSyntaxMapping {
51 scopes,
52 syntax_mapping,
53 })
54 }
55
56 pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> {
57 db.fn_signature(self.def_id)
41 } 58 }
42 59
43 pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> { 60 pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> {
@@ -63,6 +80,60 @@ impl Function {
63 } 80 }
64} 81}
65 82
83/// The declared signature of a function.
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct FnSignature {
86 args: Vec<TypeRef>,
87 ret_type: TypeRef,
88}
89
90impl FnSignature {
91 pub fn args(&self) -> &[TypeRef] {
92 &self.args
93 }
94
95 pub fn ret_type(&self) -> &TypeRef {
96 &self.ret_type
97 }
98}
99
100pub(crate) fn fn_signature(db: &impl HirDatabase, def_id: DefId) -> Arc<FnSignature> {
101 let func = Function::new(def_id);
102 let syntax = func.syntax(db);
103 let node = syntax.borrowed();
104 let mut args = Vec::new();
105 if let Some(param_list) = node.param_list() {
106 if let Some(self_param) = param_list.self_param() {
107 let self_type = if let Some(type_ref) = self_param.type_ref() {
108 TypeRef::from_ast(type_ref)
109 } else {
110 let self_type = TypeRef::Path(Name::self_type().into());
111 match self_param.flavor() {
112 ast::SelfParamFlavor::Owned => self_type,
113 ast::SelfParamFlavor::Ref => {
114 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
115 }
116 ast::SelfParamFlavor::MutRef => {
117 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
118 }
119 }
120 };
121 args.push(self_type);
122 }
123 for param in param_list.params() {
124 let type_ref = TypeRef::from_ast_opt(param.type_ref());
125 args.push(type_ref);
126 }
127 }
128 let ret_type = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
129 TypeRef::from_ast(type_ref)
130 } else {
131 TypeRef::unit()
132 };
133 let sig = FnSignature { args, ret_type };
134 Arc::new(sig)
135}
136
66#[derive(Debug, Clone)] 137#[derive(Debug, Clone)]
67pub struct FnSignatureInfo { 138pub struct FnSignatureInfo {
68 pub name: String, 139 pub name: String,
diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs
index 42bfe4f32..0a12f0b35 100644
--- a/crates/ra_hir/src/function/scope.rs
+++ b/crates/ra_hir/src/function/scope.rs
@@ -1,14 +1,16 @@
1use std::sync::Arc;
2
1use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
2 4
3use ra_syntax::{ 5use ra_syntax::{
4 AstNode, SyntaxNodeRef, TextUnit, TextRange, 6 AstNode, SyntaxNodeRef, TextUnit, TextRange,
5 algo::generate, 7 algo::generate,
6 ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, 8 ast,
7}; 9};
8use ra_arena::{Arena, RawId, impl_arena_id}; 10use ra_arena::{Arena, RawId, impl_arena_id};
9use ra_db::LocalSyntaxPtr; 11use ra_db::LocalSyntaxPtr;
10 12
11use crate::{Name, AsName}; 13use crate::{Name, AsName, expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySyntaxMapping}};
12 14
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct ScopeId(RawId); 16pub struct ScopeId(RawId);
@@ -16,15 +18,15 @@ impl_arena_id!(ScopeId);
16 18
17#[derive(Debug, PartialEq, Eq)] 19#[derive(Debug, PartialEq, Eq)]
18pub struct FnScopes { 20pub struct FnScopes {
19 pub self_param: Option<LocalSyntaxPtr>, 21 body: Arc<Body>,
20 scopes: Arena<ScopeId, ScopeData>, 22 scopes: Arena<ScopeId, ScopeData>,
21 scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>, 23 scope_for: FxHashMap<ExprId, ScopeId>,
22} 24}
23 25
24#[derive(Debug, PartialEq, Eq)] 26#[derive(Debug, PartialEq, Eq)]
25pub struct ScopeEntry { 27pub struct ScopeEntry {
26 name: Name, 28 name: Name,
27 ptr: LocalSyntaxPtr, 29 pat: PatId,
28} 30}
29 31
30#[derive(Debug, PartialEq, Eq)] 32#[derive(Debug, PartialEq, Eq)]
@@ -34,28 +36,100 @@ pub struct ScopeData {
34} 36}
35 37
36impl FnScopes { 38impl FnScopes {
37 pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes { 39 pub(crate) fn new(body: Arc<Body>) -> FnScopes {
38 let mut scopes = FnScopes { 40 let mut scopes = FnScopes {
39 self_param: fn_def 41 body: body.clone(),
40 .param_list()
41 .and_then(|it| it.self_param())
42 .map(|it| LocalSyntaxPtr::new(it.syntax())),
43 scopes: Arena::default(), 42 scopes: Arena::default(),
44 scope_for: FxHashMap::default(), 43 scope_for: FxHashMap::default(),
45 }; 44 };
46 let root = scopes.root_scope(); 45 let root = scopes.root_scope();
47 scopes.add_params_bindings(root, fn_def.param_list()); 46 scopes.add_params_bindings(root, body.args());
48 if let Some(body) = fn_def.body() { 47 compute_expr_scopes(body.body_expr(), &body, &mut scopes, root);
49 compute_block_scopes(body, &mut scopes, root)
50 }
51 scopes 48 scopes
52 } 49 }
53 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { 50 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
54 &self.scopes[scope].entries 51 &self.scopes[scope].entries
55 } 52 }
53 pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + 'a {
54 generate(self.scope_for(expr), move |&scope| {
55 self.scopes[scope].parent
56 })
57 }
58
59 pub fn resolve_local_name<'a>(
60 &'a self,
61 context_expr: ExprId,
62 name: Name,
63 ) -> Option<&'a ScopeEntry> {
64 let mut shadowed = FxHashSet::default();
65 let ret = self
66 .scope_chain_for(context_expr)
67 .flat_map(|scope| self.entries(scope).iter())
68 .filter(|entry| shadowed.insert(entry.name()))
69 .find(|entry| entry.name() == &name);
70 ret
71 }
72
73 fn root_scope(&mut self) -> ScopeId {
74 self.scopes.alloc(ScopeData {
75 parent: None,
76 entries: vec![],
77 })
78 }
79 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
80 self.scopes.alloc(ScopeData {
81 parent: Some(parent),
82 entries: vec![],
83 })
84 }
85 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
86 match &body[pat] {
87 Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry {
88 name: name.clone(),
89 pat,
90 }),
91 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
92 }
93 }
94 fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) {
95 let body = Arc::clone(&self.body);
96 params
97 .into_iter()
98 .for_each(|pat| self.add_bindings(&body, scope, *pat));
99 }
100 fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
101 self.scope_for.insert(node, scope);
102 }
103 fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
104 self.scope_for.get(&expr).map(|&scope| scope)
105 }
106}
107
108#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct ScopesWithSyntaxMapping {
110 pub syntax_mapping: Arc<BodySyntaxMapping>,
111 pub scopes: Arc<FnScopes>,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct ScopeEntryWithSyntax {
116 name: Name,
117 ptr: LocalSyntaxPtr,
118}
119
120impl ScopeEntryWithSyntax {
121 pub fn name(&self) -> &Name {
122 &self.name
123 }
124 pub fn ptr(&self) -> LocalSyntaxPtr {
125 self.ptr
126 }
127}
128
129impl ScopesWithSyntaxMapping {
56 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { 130 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
57 generate(self.scope_for(node), move |&scope| { 131 generate(self.scope_for(node), move |&scope| {
58 self.scopes[scope].parent 132 self.scopes.scopes[scope].parent
59 }) 133 })
60 } 134 }
61 pub fn scope_chain_for_offset<'a>( 135 pub fn scope_chain_for_offset<'a>(
@@ -63,26 +137,30 @@ impl FnScopes {
63 offset: TextUnit, 137 offset: TextUnit,
64 ) -> impl Iterator<Item = ScopeId> + 'a { 138 ) -> impl Iterator<Item = ScopeId> + 'a {
65 let scope = self 139 let scope = self
140 .scopes
66 .scope_for 141 .scope_for
67 .iter() 142 .iter()
68 // find containin scope 143 .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
144 // find containing scope
69 .min_by_key(|(ptr, _scope)| { 145 .min_by_key(|(ptr, _scope)| {
70 ( 146 (
71 !(ptr.range().start() <= offset && offset <= ptr.range().end()), 147 !(ptr.range().start() <= offset && offset <= ptr.range().end()),
72 ptr.range().len(), 148 ptr.range().len(),
73 ) 149 )
74 }) 150 })
75 .map(|(ptr, scope)| self.adjust(*ptr, *scope, offset)); 151 .map(|(ptr, scope)| self.adjust(ptr, *scope, offset));
76 152
77 generate(scope, move |&scope| self.scopes[scope].parent) 153 generate(scope, move |&scope| self.scopes.scopes[scope].parent)
78 } 154 }
79 // XXX: during completion, cursor might be outside of any particular 155 // XXX: during completion, cursor might be outside of any particular
80 // expression. Try to figure out the correct scope... 156 // expression. Try to figure out the correct scope...
81 fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { 157 fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId {
82 let r = ptr.range(); 158 let r = ptr.range();
83 let child_scopes = self 159 let child_scopes = self
160 .scopes
84 .scope_for 161 .scope_for
85 .iter() 162 .iter()
163 .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
86 .map(|(ptr, scope)| (ptr.range(), scope)) 164 .map(|(ptr, scope)| (ptr.range(), scope))
87 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); 165 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
88 166
@@ -100,22 +178,27 @@ impl FnScopes {
100 .unwrap_or(original_scope) 178 .unwrap_or(original_scope)
101 } 179 }
102 180
103 pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> { 181 pub fn resolve_local_name(&self, name_ref: ast::NameRef) -> Option<ScopeEntryWithSyntax> {
104 let mut shadowed = FxHashSet::default(); 182 let mut shadowed = FxHashSet::default();
105 let name = name_ref.as_name(); 183 let name = name_ref.as_name();
106 let ret = self 184 let ret = self
107 .scope_chain(name_ref.syntax()) 185 .scope_chain(name_ref.syntax())
108 .flat_map(|scope| self.entries(scope).iter()) 186 .flat_map(|scope| self.scopes.entries(scope).iter())
109 .filter(|entry| shadowed.insert(entry.name())) 187 .filter(|entry| shadowed.insert(entry.name()))
110 .filter(|entry| entry.name() == &name) 188 .filter(|entry| entry.name() == &name)
111 .nth(0); 189 .nth(0);
112 ret 190 ret.and_then(|entry| {
191 Some(ScopeEntryWithSyntax {
192 name: entry.name().clone(),
193 ptr: self.syntax_mapping.pat_syntax(entry.pat())?,
194 })
195 })
113 } 196 }
114 197
115 pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> { 198 pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> {
116 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 199 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
117 let name_ptr = LocalSyntaxPtr::new(pat.syntax()); 200 let name_ptr = LocalSyntaxPtr::new(pat.syntax());
118 let refs: Vec<_> = fn_def 201 fn_def
119 .syntax() 202 .syntax()
120 .descendants() 203 .descendants()
121 .filter_map(ast::NameRef::cast) 204 .filter_map(ast::NameRef::cast)
@@ -127,203 +210,94 @@ impl FnScopes {
127 name: name_ref.syntax().text().to_string(), 210 name: name_ref.syntax().text().to_string(),
128 range: name_ref.syntax().range(), 211 range: name_ref.syntax().range(),
129 }) 212 })
130 .collect(); 213 .collect()
131
132 refs
133 } 214 }
134 215
135 fn root_scope(&mut self) -> ScopeId {
136 self.scopes.alloc(ScopeData {
137 parent: None,
138 entries: vec![],
139 })
140 }
141 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
142 self.scopes.alloc(ScopeData {
143 parent: Some(parent),
144 entries: vec![],
145 })
146 }
147 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
148 let entries = pat
149 .syntax()
150 .descendants()
151 .filter_map(ast::BindPat::cast)
152 .filter_map(ScopeEntry::new);
153 self.scopes[scope].entries.extend(entries);
154 }
155 fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
156 params
157 .into_iter()
158 .flat_map(|it| it.params())
159 .filter_map(|it| it.pat())
160 .for_each(|it| self.add_bindings(scope, it));
161 }
162 fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
163 self.scope_for.insert(LocalSyntaxPtr::new(node), scope);
164 }
165 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { 216 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
166 node.ancestors() 217 node.ancestors()
167 .map(LocalSyntaxPtr::new) 218 .map(LocalSyntaxPtr::new)
168 .filter_map(|it| self.scope_for.get(&it).map(|&scope| scope)) 219 .filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr))
169 .next() 220 .find_map(|it| self.scopes.scope_for(it))
170 } 221 }
171} 222}
172 223
173impl ScopeEntry { 224impl ScopeEntry {
174 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
175 let name = pat.name()?.as_name();
176 let res = ScopeEntry {
177 name,
178 ptr: LocalSyntaxPtr::new(pat.syntax()),
179 };
180 Some(res)
181 }
182 pub fn name(&self) -> &Name { 225 pub fn name(&self) -> &Name {
183 &self.name 226 &self.name
184 } 227 }
185 pub fn ptr(&self) -> LocalSyntaxPtr { 228 pub fn pat(&self) -> PatId {
186 self.ptr 229 self.pat
187 } 230 }
188} 231}
189 232
190fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) { 233fn compute_block_scopes(
191 // A hack for completion :( 234 statements: &[Statement],
192 scopes.set_scope(block.syntax(), scope); 235 tail: Option<ExprId>,
193 for stmt in block.statements() { 236 body: &Body,
237 scopes: &mut FnScopes,
238 mut scope: ScopeId,
239) {
240 for stmt in statements {
194 match stmt { 241 match stmt {
195 ast::Stmt::LetStmt(stmt) => { 242 Statement::Let {
196 if let Some(expr) = stmt.initializer() { 243 pat, initializer, ..
197 scopes.set_scope(expr.syntax(), scope); 244 } => {
198 compute_expr_scopes(expr, scopes, scope); 245 if let Some(expr) = initializer {
246 scopes.set_scope(*expr, scope);
247 compute_expr_scopes(*expr, body, scopes, scope);
199 } 248 }
200 scope = scopes.new_scope(scope); 249 scope = scopes.new_scope(scope);
201 if let Some(pat) = stmt.pat() { 250 scopes.add_bindings(body, scope, *pat);
202 scopes.add_bindings(scope, pat);
203 }
204 } 251 }
205 ast::Stmt::ExprStmt(expr_stmt) => { 252 Statement::Expr(expr) => {
206 if let Some(expr) = expr_stmt.expr() { 253 scopes.set_scope(*expr, scope);
207 scopes.set_scope(expr.syntax(), scope); 254 compute_expr_scopes(*expr, body, scopes, scope);
208 compute_expr_scopes(expr, scopes, scope);
209 }
210 } 255 }
211 } 256 }
212 } 257 }
213 if let Some(expr) = block.expr() { 258 if let Some(expr) = tail {
214 scopes.set_scope(expr.syntax(), scope); 259 compute_expr_scopes(expr, body, scopes, scope);
215 compute_expr_scopes(expr, scopes, scope);
216 } 260 }
217} 261}
218 262
219fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { 263fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut FnScopes, scope: ScopeId) {
220 match expr { 264 scopes.set_scope(expr, scope);
221 ast::Expr::IfExpr(e) => { 265 match &body[expr] {
222 let cond_scope = e 266 Expr::Block { statements, tail } => {
223 .condition() 267 compute_block_scopes(&statements, *tail, body, scopes, scope);
224 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
225 if let Some(block) = e.then_branch() {
226 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
227 }
228 if let Some(block) = e.else_branch() {
229 compute_block_scopes(block, scopes, scope);
230 }
231 }
232 ast::Expr::BlockExpr(e) => {
233 if let Some(block) = e.block() {
234 compute_block_scopes(block, scopes, scope);
235 }
236 }
237 ast::Expr::LoopExpr(e) => {
238 if let Some(block) = e.loop_body() {
239 compute_block_scopes(block, scopes, scope);
240 }
241 }
242 ast::Expr::WhileExpr(e) => {
243 let cond_scope = e
244 .condition()
245 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
246 if let Some(block) = e.loop_body() {
247 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
248 }
249 } 268 }
250 ast::Expr::ForExpr(e) => { 269 Expr::For {
251 if let Some(expr) = e.iterable() { 270 iterable,
252 compute_expr_scopes(expr, scopes, scope); 271 pat,
253 } 272 body: body_expr,
254 let mut scope = scope; 273 } => {
255 if let Some(pat) = e.pat() { 274 compute_expr_scopes(*iterable, body, scopes, scope);
256 scope = scopes.new_scope(scope);
257 scopes.add_bindings(scope, pat);
258 }
259 if let Some(block) = e.loop_body() {
260 compute_block_scopes(block, scopes, scope);
261 }
262 }
263 ast::Expr::LambdaExpr(e) => {
264 let scope = scopes.new_scope(scope); 275 let scope = scopes.new_scope(scope);
265 scopes.add_params_bindings(scope, e.param_list()); 276 scopes.add_bindings(body, scope, *pat);
266 if let Some(body) = e.body() { 277 compute_expr_scopes(*body_expr, body, scopes, scope);
267 scopes.set_scope(body.syntax(), scope);
268 compute_expr_scopes(body, scopes, scope);
269 }
270 } 278 }
271 ast::Expr::CallExpr(e) => { 279 Expr::Lambda {
272 compute_call_scopes(e.expr(), e.arg_list(), scopes, scope); 280 args,
273 } 281 body: body_expr,
274 ast::Expr::MethodCallExpr(e) => { 282 ..
275 compute_call_scopes(e.expr(), e.arg_list(), scopes, scope); 283 } => {
284 let scope = scopes.new_scope(scope);
285 scopes.add_params_bindings(scope, &args);
286 compute_expr_scopes(*body_expr, body, scopes, scope);
276 } 287 }
277 ast::Expr::MatchExpr(e) => { 288 Expr::Match { expr, arms } => {
278 if let Some(expr) = e.expr() { 289 compute_expr_scopes(*expr, body, scopes, scope);
279 compute_expr_scopes(expr, scopes, scope); 290 for arm in arms {
280 }
281 for arm in e.match_arm_list().into_iter().flat_map(|it| it.arms()) {
282 let scope = scopes.new_scope(scope); 291 let scope = scopes.new_scope(scope);
283 for pat in arm.pats() { 292 for pat in &arm.pats {
284 scopes.add_bindings(scope, pat); 293 scopes.add_bindings(body, scope, *pat);
285 }
286 if let Some(expr) = arm.expr() {
287 compute_expr_scopes(expr, scopes, scope);
288 } 294 }
295 scopes.set_scope(arm.expr, scope);
296 compute_expr_scopes(arm.expr, body, scopes, scope);
289 } 297 }
290 } 298 }
291 _ => expr 299 e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
292 .syntax()
293 .children()
294 .filter_map(ast::Expr::cast)
295 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)),
296 }; 300 };
297
298 fn compute_call_scopes(
299 receiver: Option<ast::Expr>,
300 arg_list: Option<ast::ArgList>,
301 scopes: &mut FnScopes,
302 scope: ScopeId,
303 ) {
304 arg_list
305 .into_iter()
306 .flat_map(|it| it.args())
307 .chain(receiver)
308 .for_each(|expr| compute_expr_scopes(expr, scopes, scope));
309 }
310
311 fn compute_cond_scopes(
312 cond: ast::Condition,
313 scopes: &mut FnScopes,
314 scope: ScopeId,
315 ) -> Option<ScopeId> {
316 if let Some(expr) = cond.expr() {
317 compute_expr_scopes(expr, scopes, scope);
318 }
319 if let Some(pat) = cond.pat() {
320 let s = scopes.new_scope(scope);
321 scopes.add_bindings(s, pat);
322 Some(s)
323 } else {
324 None
325 }
326 }
327} 301}
328 302
329#[derive(Debug)] 303#[derive(Debug)]
@@ -338,6 +312,8 @@ mod tests {
338 use ra_syntax::SourceFileNode; 312 use ra_syntax::SourceFileNode;
339 use test_utils::{extract_offset, assert_eq_text}; 313 use test_utils::{extract_offset, assert_eq_text};
340 314
315 use crate::expr;
316
341 use super::*; 317 use super::*;
342 318
343 fn do_check(code: &str, expected: &[&str]) { 319 fn do_check(code: &str, expected: &[&str]) {
@@ -353,15 +329,20 @@ mod tests {
353 let file = SourceFileNode::parse(&code); 329 let file = SourceFileNode::parse(&code);
354 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 330 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
355 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 331 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
356 let scopes = FnScopes::new(fn_def); 332 let body_hir = expr::collect_fn_body_syntax(fn_def);
333 let scopes = FnScopes::new(Arc::clone(body_hir.body()));
334 let scopes = ScopesWithSyntaxMapping {
335 scopes: Arc::new(scopes),
336 syntax_mapping: Arc::new(body_hir),
337 };
357 let actual = scopes 338 let actual = scopes
358 .scope_chain(marker.syntax()) 339 .scope_chain(marker.syntax())
359 .flat_map(|scope| scopes.entries(scope)) 340 .flat_map(|scope| scopes.scopes.entries(scope))
360 .map(|it| it.name().to_string()) 341 .map(|it| it.name().to_string())
361 .collect::<Vec<_>>() 342 .collect::<Vec<_>>()
362 .join("\n"); 343 .join("\n");
363 let expected = expected.join("\n"); 344 let expected = expected.join("\n");
364 assert_eq_text!(&actual, &expected); 345 assert_eq_text!(&expected, &actual);
365 } 346 }
366 347
367 #[test] 348 #[test]
@@ -389,7 +370,7 @@ mod tests {
389 } 370 }
390 371
391 #[test] 372 #[test]
392 fn test_metod_call_scope() { 373 fn test_method_call_scope() {
393 do_check( 374 do_check(
394 r" 375 r"
395 fn quux() { 376 fn quux() {
@@ -445,10 +426,15 @@ mod tests {
445 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 426 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
446 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 427 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
447 428
448 let scopes = FnScopes::new(fn_def); 429 let body_hir = expr::collect_fn_body_syntax(fn_def);
430 let scopes = FnScopes::new(Arc::clone(body_hir.body()));
431 let scopes = ScopesWithSyntaxMapping {
432 scopes: Arc::new(scopes),
433 syntax_mapping: Arc::new(body_hir),
434 };
449 435
450 let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); 436 let local_name_entry = scopes.resolve_local_name(name_ref).unwrap();
451 let local_name = local_name_entry.ptr().resolve(&file); 437 let local_name = local_name_entry.ptr();
452 let expected_name = 438 let expected_name =
453 find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); 439 find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
454 assert_eq!(local_name.range(), expected_name.syntax().range()); 440 assert_eq!(local_name.range(), expected_name.syntax().range());
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 4d6378e02..c7391ee05 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -2,7 +2,9 @@ use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId};
2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; 2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id}; 3use ra_arena::{Arena, RawId, impl_arena_id};
4 4
5use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, ImplBlock, Crate}; 5use crate::{HirDatabase, PerNs, ModuleId, Def, Function, Struct, Enum, ImplBlock, Crate};
6
7use crate::code_model_api::Module;
6 8
7/// hir makes a heavy use of ids: integer (u32) handlers to various things. You 9/// hir makes a heavy use of ids: integer (u32) handlers to various things. You
8/// can think of id as a pointer (but without a lifetime) or a file descriptor 10/// can think of id as a pointer (but without a lifetime) or a file descriptor
@@ -151,7 +153,7 @@ impl DefId {
151 let loc = self.loc(db); 153 let loc = self.loc(db);
152 let res = match loc.kind { 154 let res = match loc.kind {
153 DefKind::Module => { 155 DefKind::Module => {
154 let module = Module::new(db, loc.source_root_id, loc.module_id)?; 156 let module = Module::from_module_id(db, loc.source_root_id, loc.module_id)?;
155 Def::Module(module) 157 Def::Module(module)
156 } 158 }
157 DefKind::Function => { 159 DefKind::Function => {
@@ -175,12 +177,12 @@ impl DefId {
175 /// For a module, returns that module; for any other def, returns the containing module. 177 /// For a module, returns that module; for any other def, returns the containing module.
176 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> { 178 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> {
177 let loc = self.loc(db); 179 let loc = self.loc(db);
178 Module::new(db, loc.source_root_id, loc.module_id) 180 Module::from_module_id(db, loc.source_root_id, loc.module_id)
179 } 181 }
180 182
181 /// Returns the containing crate. 183 /// Returns the containing crate.
182 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> { 184 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
183 Ok(self.module(db)?.krate(db)) 185 Ok(self.module(db)?.krate(db)?)
184 } 186 }
185 187
186 /// Returns the containing impl block, if this is an impl item. 188 /// Returns the containing impl block, if this is an impl item.
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 01afa84c4..7ce8d17e6 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -7,12 +7,14 @@ use ra_db::{LocationIntener, Cancelable, SourceRootId};
7 7
8use crate::{ 8use crate::{
9 DefId, DefLoc, DefKind, SourceItemId, SourceFileItems, 9 DefId, DefLoc, DefKind, SourceItemId, SourceFileItems,
10 Module, Function, 10 Function,
11 db::HirDatabase, 11 db::HirDatabase,
12 type_ref::TypeRef, 12 type_ref::TypeRef,
13 module::{ModuleSourceNode, ModuleId}, 13 module_tree::ModuleId,
14}; 14};
15 15
16use crate::code_model_api::{Module, ModuleSource};
17
16#[derive(Debug, Clone, PartialEq, Eq)] 18#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ImplBlock { 19pub struct ImplBlock {
18 module_impl_blocks: Arc<ModuleImplBlocks>, 20 module_impl_blocks: Arc<ModuleImplBlocks>,
@@ -64,7 +66,7 @@ impl ImplData {
64 ) -> Self { 66 ) -> Self {
65 let target_trait = node.target_type().map(TypeRef::from_ast); 67 let target_trait = node.target_type().map(TypeRef::from_ast);
66 let target_type = TypeRef::from_ast_opt(node.target_type()); 68 let target_type = TypeRef::from_ast_opt(node.target_type());
67 let file_id = module.source().file_id(); 69 let module_loc = module.def_id.loc(db);
68 let items = if let Some(item_list) = node.item_list() { 70 let items = if let Some(item_list) = node.item_list() {
69 item_list 71 item_list
70 .impl_items() 72 .impl_items()
@@ -75,14 +77,14 @@ impl ImplData {
75 ast::ImplItem::TypeDef(..) => DefKind::Item, 77 ast::ImplItem::TypeDef(..) => DefKind::Item,
76 }; 78 };
77 let item_id = file_items.id_of_unchecked(item_node.syntax()); 79 let item_id = file_items.id_of_unchecked(item_node.syntax());
80 let source_item_id = SourceItemId {
81 file_id: module_loc.source_item_id.file_id,
82 item_id: Some(item_id),
83 };
78 let def_loc = DefLoc { 84 let def_loc = DefLoc {
79 kind, 85 kind,
80 source_root_id: module.source_root_id, 86 source_item_id,
81 module_id: module.module_id, 87 ..module_loc
82 source_item_id: SourceItemId {
83 file_id,
84 item_id: Some(item_id),
85 },
86 }; 88 };
87 let def_id = def_loc.id(db); 89 let def_id = def_loc.id(db);
88 match item_node { 90 match item_node {
@@ -148,13 +150,13 @@ impl ModuleImplBlocks {
148 } 150 }
149 151
150 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> { 152 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> {
151 let module_source_node = module.source().resolve(db); 153 let (file_id, module_source) = module.defenition_source(db)?;
152 let node = match &module_source_node { 154 let node = match &module_source {
153 ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(), 155 ModuleSource::SourceFile(node) => node.borrowed().syntax(),
154 ModuleSourceNode::Module(node) => node.borrowed().syntax(), 156 ModuleSource::Module(node) => node.borrowed().syntax(),
155 }; 157 };
156 158
157 let source_file_items = db.file_items(module.source().file_id()); 159 let source_file_items = db.file_items(file_id.into());
158 160
159 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { 161 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
160 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast); 162 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast);
@@ -174,7 +176,7 @@ pub(crate) fn impls_in_module(
174 module_id: ModuleId, 176 module_id: ModuleId,
175) -> Cancelable<Arc<ModuleImplBlocks>> { 177) -> Cancelable<Arc<ModuleImplBlocks>> {
176 let mut result = ModuleImplBlocks::new(); 178 let mut result = ModuleImplBlocks::new();
177 let module = Module::new(db, source_root_id, module_id)?; 179 let module = Module::from_module_id(db, source_root_id, module_id)?;
178 result.collect(db, module)?; 180 result.collect(db, module)?;
179 Ok(Arc::new(result)) 181 Ok(Arc::new(result))
180} 182}
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
deleted file mode 100644
index 5194e280b..000000000
--- a/crates/ra_hir/src/krate.rs
+++ /dev/null
@@ -1,48 +0,0 @@
1pub use ra_db::{CrateId, Cancelable};
2
3use crate::{HirDatabase, Module, Name, AsName, HirFileId};
4
5/// hir::Crate describes a single crate. It's the main inteface with which
6/// crate's dependencies interact. Mostly, it should be just a proxy for the
7/// root module.
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct Crate {
10 crate_id: CrateId,
11}
12
13#[derive(Debug)]
14pub struct CrateDependency {
15 pub krate: Crate,
16 pub name: Name,
17}
18
19impl Crate {
20 pub(crate) fn new(crate_id: CrateId) -> Crate {
21 Crate { crate_id }
22 }
23 pub fn dependencies(&self, db: &impl HirDatabase) -> Vec<CrateDependency> {
24 let crate_graph = db.crate_graph();
25 crate_graph
26 .dependencies(self.crate_id)
27 .map(|dep| {
28 let krate = Crate::new(dep.crate_id());
29 let name = dep.as_name();
30 CrateDependency { krate, name }
31 })
32 .collect()
33 }
34 pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
35 let crate_graph = db.crate_graph();
36 let file_id = crate_graph.crate_root(self.crate_id);
37 let source_root_id = db.file_source_root(file_id);
38 let file_id = HirFileId::from(file_id);
39 let module_tree = db.module_tree(source_root_id)?;
40 // FIXME: teach module tree about crate roots instead of guessing
41 let (module_id, _) = ctry!(module_tree
42 .modules_with_sources()
43 .find(|(_, src)| src.file_id() == file_id));
44
45 let module = Module::new(db, source_root_id, module_id)?;
46 Ok(Some(module))
47 }
48}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 2abcec441..9f133f174 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -24,14 +24,17 @@ pub mod source_binder;
24mod ids; 24mod ids;
25mod macros; 25mod macros;
26mod name; 26mod name;
27// can't use `crate` or `r#crate` here :( 27mod module_tree;
28mod krate; 28mod nameres;
29mod module;
30mod function; 29mod function;
31mod adt; 30mod adt;
32mod type_ref; 31mod type_ref;
33mod ty; 32mod ty;
34mod impl_block; 33mod impl_block;
34mod expr;
35
36mod code_model_api;
37mod code_model_impl;
35 38
36use crate::{ 39use crate::{
37 db::HirDatabase, 40 db::HirDatabase,
@@ -42,11 +45,11 @@ use crate::{
42pub use self::{ 45pub use self::{
43 path::{Path, PathKind}, 46 path::{Path, PathKind},
44 name::Name, 47 name::Name,
45 krate::Crate,
46 ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc}, 48 ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc},
47 macros::{MacroDef, MacroInput, MacroExpansion}, 49 macros::{MacroDef, MacroInput, MacroExpansion},
48 module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, 50 module_tree::ModuleId,
49 function::{Function, FnScopes}, 51 nameres::{ItemMap, PerNs, Namespace, Resolution},
52 function::{Function, FnSignature, FnScopes, ScopesWithSyntaxMapping},
50 adt::{Struct, Enum}, 53 adt::{Struct, Enum},
51 ty::Ty, 54 ty::Ty,
52 impl_block::{ImplBlock, ImplItem}, 55 impl_block::{ImplBlock, ImplItem},
@@ -54,6 +57,11 @@ pub use self::{
54 57
55pub use self::function::FnSignatureInfo; 58pub use self::function::FnSignatureInfo;
56 59
60pub use self::code_model_api::{
61 Crate, CrateDependency,
62 Module, ModuleSource, Problem,
63};
64
57pub enum Def { 65pub enum Def {
58 Module(Module), 66 Module(Module),
59 Function(Function), 67 Function(Function),
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index a9db932ff..8d176662c 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -208,6 +208,9 @@ salsa::database_storage! {
208 fn struct_data() for db::StructDataQuery; 208 fn struct_data() for db::StructDataQuery;
209 fn enum_data() for db::EnumDataQuery; 209 fn enum_data() for db::EnumDataQuery;
210 fn impls_in_module() for db::ImplsInModuleQuery; 210 fn impls_in_module() for db::ImplsInModuleQuery;
211 fn body_hir() for db::BodyHirQuery;
212 fn body_syntax_mapping() for db::BodySyntaxMappingQuery;
213 fn fn_signature() for db::FnSignatureQuery;
211 } 214 }
212 } 215 }
213} 216}
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
deleted file mode 100644
index b9821115c..000000000
--- a/crates/ra_hir/src/module.rs
+++ /dev/null
@@ -1,376 +0,0 @@
1pub(super) mod imp;
2pub(super) mod nameres;
3
4use std::sync::Arc;
5use log;
6
7use ra_syntax::{
8 algo::generate,
9 ast::{self, AstNode, NameOwner},
10 SyntaxNode,
11};
12use ra_arena::{Arena, RawId, impl_arena_id};
13use ra_db::{SourceRootId, FileId, Cancelable};
14use relative_path::RelativePathBuf;
15
16use crate::{
17 Def, DefKind, DefLoc, DefId,
18 Name, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate,
19 HirFileId,
20};
21
22pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs};
23
24/// `Module` is API entry point to get all the information
25/// about a particular module.
26#[derive(Debug, Clone)]
27pub struct Module {
28 tree: Arc<ModuleTree>,
29 pub(crate) source_root_id: SourceRootId,
30 pub(crate) module_id: ModuleId,
31}
32
33impl Module {
34 pub(super) fn new(
35 db: &impl HirDatabase,
36 source_root_id: SourceRootId,
37 module_id: ModuleId,
38 ) -> Cancelable<Module> {
39 let module_tree = db.module_tree(source_root_id)?;
40 let res = Module {
41 tree: module_tree,
42 source_root_id,
43 module_id,
44 };
45 Ok(res)
46 }
47
48 /// Returns `mod foo;` or `mod foo {}` node whihc declared this module.
49 /// Returns `None` for the root module
50 pub fn parent_link_source(&self, db: &impl HirDatabase) -> Option<(FileId, ast::ModuleNode)> {
51 let link = self.module_id.parent_link(&self.tree)?;
52 let file_id = link
53 .owner(&self.tree)
54 .source(&self.tree)
55 .file_id()
56 .as_original_file();
57 let src = link.bind_source(&self.tree, db);
58 Some((file_id, src))
59 }
60
61 pub fn file_id(&self) -> FileId {
62 self.source().file_id().as_original_file()
63 }
64
65 /// Parent module. Returns `None` if this is a root module.
66 pub fn parent(&self) -> Option<Module> {
67 let parent_id = self.module_id.parent(&self.tree)?;
68 Some(Module {
69 module_id: parent_id,
70 ..self.clone()
71 })
72 }
73
74 /// Returns an iterator of all children of this module.
75 pub fn children<'a>(&'a self) -> impl Iterator<Item = (Name, Module)> + 'a {
76 self.module_id
77 .children(&self.tree)
78 .map(move |(name, module_id)| {
79 (
80 name,
81 Module {
82 module_id,
83 ..self.clone()
84 },
85 )
86 })
87 }
88
89 /// Returns the crate this module is part of.
90 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
91 let root_id = self.module_id.crate_root(&self.tree);
92 let file_id = root_id.source(&self.tree).file_id().as_original_file();
93 let crate_graph = db.crate_graph();
94 let crate_id = crate_graph.crate_id_for_crate_root(file_id)?;
95 Some(Crate::new(crate_id))
96 }
97
98 /// Returns the all modules on the way to the root.
99 pub fn path_to_root(&self) -> Vec<Module> {
100 generate(Some(self.clone()), move |it| it.parent()).collect::<Vec<Module>>()
101 }
102
103 /// The root of the tree this module is part of
104 pub fn crate_root(&self) -> Module {
105 let root_id = self.module_id.crate_root(&self.tree);
106 Module {
107 module_id: root_id,
108 ..self.clone()
109 }
110 }
111
112 /// `name` is `None` for the crate's root module
113 pub fn name(&self) -> Option<&Name> {
114 let link = self.module_id.parent_link(&self.tree)?;
115 Some(link.name(&self.tree))
116 }
117
118 pub fn def_id(&self, db: &impl HirDatabase) -> DefId {
119 let def_loc = DefLoc {
120 kind: DefKind::Module,
121 source_root_id: self.source_root_id,
122 module_id: self.module_id,
123 source_item_id: self.module_id.source(&self.tree).0,
124 };
125 def_loc.id(db)
126 }
127
128 /// Finds a child module with the specified name.
129 pub fn child(&self, name: &Name) -> Option<Module> {
130 let child_id = self.module_id.child(&self.tree, name)?;
131 Some(Module {
132 module_id: child_id,
133 ..self.clone()
134 })
135 }
136
137 /// Returns a `ModuleScope`: a set of items, visible in this module.
138 pub fn scope(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
139 let item_map = db.item_map(self.source_root_id)?;
140 let res = item_map.per_module[&self.module_id].clone();
141 Ok(res)
142 }
143
144 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
145 let mut curr_per_ns = PerNs::types(
146 match path.kind {
147 PathKind::Crate => self.crate_root(),
148 PathKind::Self_ | PathKind::Plain => self.clone(),
149 PathKind::Super => {
150 if let Some(p) = self.parent() {
151 p
152 } else {
153 return Ok(PerNs::none());
154 }
155 }
156 }
157 .def_id(db),
158 );
159
160 let segments = &path.segments;
161 for name in segments.iter() {
162 let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) {
163 r
164 } else {
165 return Ok(PerNs::none());
166 };
167 let module = match curr.resolve(db)? {
168 Def::Module(it) => it,
169 // TODO here would be the place to handle enum variants...
170 _ => return Ok(PerNs::none()),
171 };
172 let scope = module.scope(db)?;
173 curr_per_ns = if let Some(r) = scope.get(&name) {
174 r.def_id
175 } else {
176 return Ok(PerNs::none());
177 };
178 }
179 Ok(curr_per_ns)
180 }
181
182 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
183 self.module_id.problems(&self.tree, db)
184 }
185
186 pub(crate) fn source(&self) -> ModuleSource {
187 self.module_id.source(&self.tree)
188 }
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
192pub struct ModuleId(RawId);
193impl_arena_id!(ModuleId);
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
196pub struct LinkId(RawId);
197impl_arena_id!(LinkId);
198
199/// Physically, rust source is organized as a set of files, but logically it is
200/// organized as a tree of modules. Usually, a single file corresponds to a
201/// single module, but it is not nessary the case.
202///
203/// Module encapsulate the logic of transitioning from the fuzzy world of files
204/// (which can have multiple parents) to the precise world of modules (which
205/// always have one parent).
206#[derive(Default, Debug, PartialEq, Eq)]
207pub struct ModuleTree {
208 mods: Arena<ModuleId, ModuleData>,
209 links: Arena<LinkId, LinkData>,
210}
211
212impl ModuleTree {
213 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
214 self.mods.iter().map(|(id, _)| id)
215 }
216
217 pub(crate) fn modules_with_sources<'a>(
218 &'a self,
219 ) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a {
220 self.mods.iter().map(|(id, m)| (id, m.source))
221 }
222}
223
224/// `ModuleSource` is the syntax tree element that produced this module:
225/// either a file, or an inlinde module.
226#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
227pub struct ModuleSource(SourceItemId);
228
229/// An owned syntax node for a module. Unlike `ModuleSource`,
230/// this holds onto the AST for the whole file.
231pub(crate) enum ModuleSourceNode {
232 SourceFile(ast::SourceFileNode),
233 Module(ast::ModuleNode),
234}
235
236#[derive(Clone, Debug, Hash, PartialEq, Eq)]
237pub enum Problem {
238 UnresolvedModule {
239 candidate: RelativePathBuf,
240 },
241 NotDirOwner {
242 move_to: RelativePathBuf,
243 candidate: RelativePathBuf,
244 },
245}
246
247impl ModuleId {
248 pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource {
249 tree.mods[self].source
250 }
251 fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
252 tree.mods[self].parent
253 }
254 fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
255 let link = self.parent_link(tree)?;
256 Some(tree.links[link].owner)
257 }
258 fn crate_root(self, tree: &ModuleTree) -> ModuleId {
259 generate(Some(self), move |it| it.parent(tree))
260 .last()
261 .unwrap()
262 }
263 fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
264 let link = tree.mods[self]
265 .children
266 .iter()
267 .map(|&it| &tree.links[it])
268 .find(|it| it.name == *name)?;
269 Some(*link.points_to.first()?)
270 }
271 fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
272 tree.mods[self].children.iter().filter_map(move |&it| {
273 let link = &tree.links[it];
274 let module = *link.points_to.first()?;
275 Some((link.name.clone(), module))
276 })
277 }
278 fn problems(self, tree: &ModuleTree, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
279 tree.mods[self]
280 .children
281 .iter()
282 .filter_map(|&it| {
283 let p = tree.links[it].problem.clone()?;
284 let s = it.bind_source(tree, db);
285 let s = s.borrowed().name().unwrap().syntax().owned();
286 Some((s, p))
287 })
288 .collect()
289 }
290}
291
292impl LinkId {
293 fn owner(self, tree: &ModuleTree) -> ModuleId {
294 tree.links[self].owner
295 }
296 fn name(self, tree: &ModuleTree) -> &Name {
297 &tree.links[self].name
298 }
299 fn bind_source<'a>(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode {
300 let owner = self.owner(tree);
301 match owner.source(tree).resolve(db) {
302 ModuleSourceNode::SourceFile(root) => {
303 let ast = imp::modules(root.borrowed())
304 .find(|(name, _)| name == &tree.links[self].name)
305 .unwrap()
306 .1;
307 ast.owned()
308 }
309 ModuleSourceNode::Module(it) => it,
310 }
311 }
312}
313
314#[derive(Debug, PartialEq, Eq, Hash)]
315pub struct ModuleData {
316 source: ModuleSource,
317 parent: Option<LinkId>,
318 children: Vec<LinkId>,
319}
320
321impl ModuleSource {
322 // precondition: item_id **must** point to module
323 fn new(file_id: HirFileId, item_id: Option<SourceFileItemId>) -> ModuleSource {
324 let source_item_id = SourceItemId { file_id, item_id };
325 ModuleSource(source_item_id)
326 }
327
328 pub(crate) fn new_file(file_id: HirFileId) -> ModuleSource {
329 ModuleSource::new(file_id, None)
330 }
331
332 pub(crate) fn new_inline(
333 db: &impl HirDatabase,
334 file_id: HirFileId,
335 m: ast::Module,
336 ) -> ModuleSource {
337 assert!(!m.has_semi());
338 let file_items = db.file_items(file_id);
339 let item_id = file_items.id_of(file_id, m.syntax());
340 ModuleSource::new(file_id, Some(item_id))
341 }
342
343 pub(crate) fn file_id(self) -> HirFileId {
344 self.0.file_id
345 }
346
347 pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
348 let syntax_node = db.file_item(self.0);
349 let syntax_node = syntax_node.borrowed();
350 if let Some(file) = ast::SourceFile::cast(syntax_node) {
351 return ModuleSourceNode::SourceFile(file.owned());
352 }
353 let module = ast::Module::cast(syntax_node).unwrap();
354 ModuleSourceNode::Module(module.owned())
355 }
356}
357
358#[derive(Hash, Debug, PartialEq, Eq)]
359struct LinkData {
360 owner: ModuleId,
361 name: Name,
362 points_to: Vec<ModuleId>,
363 problem: Option<Problem>,
364}
365
366impl ModuleTree {
367 fn push_mod(&mut self, data: ModuleData) -> ModuleId {
368 self.mods.alloc(data)
369 }
370 fn push_link(&mut self, data: LinkData) -> LinkId {
371 let owner = data.owner;
372 let id = self.links.alloc(data);
373 self.mods[owner].children.push(id);
374 id
375 }
376}
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
deleted file mode 100644
index 3849026db..000000000
--- a/crates/ra_hir/src/module/imp.rs
+++ /dev/null
@@ -1,190 +0,0 @@
1use std::sync::Arc;
2
3use ra_syntax::ast::{self, NameOwner};
4use relative_path::RelativePathBuf;
5use rustc_hash::{FxHashMap, FxHashSet};
6use arrayvec::ArrayVec;
7use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
8
9use crate::{
10 HirDatabase, Name, AsName,
11};
12
13use super::{
14 LinkData, LinkId, ModuleData, ModuleId, ModuleSource,
15 ModuleTree, Problem,
16};
17
18#[derive(Clone, Hash, PartialEq, Eq, Debug)]
19pub enum Submodule {
20 Declaration(Name),
21 Definition(Name, ModuleSource),
22}
23
24impl Submodule {
25 fn name(&self) -> &Name {
26 match self {
27 Submodule::Declaration(name) => name,
28 Submodule::Definition(name, _) => name,
29 }
30 }
31}
32
33pub(crate) fn modules<'a>(
34 root: impl ast::ModuleItemOwner<'a>,
35) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
36 root.items()
37 .filter_map(|item| match item {
38 ast::ModuleItem::Module(m) => Some(m),
39 _ => None,
40 })
41 .filter_map(|module| {
42 let name = module.name()?.as_name();
43 Some((name, module))
44 })
45}
46
47pub(crate) fn module_tree(
48 db: &impl HirDatabase,
49 source_root: SourceRootId,
50) -> Cancelable<Arc<ModuleTree>> {
51 db.check_canceled()?;
52 let res = create_module_tree(db, source_root)?;
53 Ok(Arc::new(res))
54}
55
56fn create_module_tree<'a>(
57 db: &impl HirDatabase,
58 source_root: SourceRootId,
59) -> Cancelable<ModuleTree> {
60 let mut tree = ModuleTree::default();
61
62 let mut roots = FxHashMap::default();
63 let mut visited = FxHashSet::default();
64
65 let source_root = db.source_root(source_root);
66 for &file_id in source_root.files.values() {
67 let source = ModuleSource::new_file(file_id.into());
68 if visited.contains(&source) {
69 continue; // TODO: use explicit crate_roots here
70 }
71 assert!(!roots.contains_key(&file_id));
72 let module_id = build_subtree(
73 db,
74 &source_root,
75 &mut tree,
76 &mut visited,
77 &mut roots,
78 None,
79 source,
80 )?;
81 roots.insert(file_id, module_id);
82 }
83 Ok(tree)
84}
85
86fn build_subtree(
87 db: &impl HirDatabase,
88 source_root: &SourceRoot,
89 tree: &mut ModuleTree,
90 visited: &mut FxHashSet<ModuleSource>,
91 roots: &mut FxHashMap<FileId, ModuleId>,
92 parent: Option<LinkId>,
93 source: ModuleSource,
94) -> Cancelable<ModuleId> {
95 visited.insert(source);
96 let id = tree.push_mod(ModuleData {
97 source,
98 parent,
99 children: Vec::new(),
100 });
101 for sub in db.submodules(source)?.iter() {
102 let link = tree.push_link(LinkData {
103 name: sub.name().clone(),
104 owner: id,
105 points_to: Vec::new(),
106 problem: None,
107 });
108
109 let (points_to, problem) = match sub {
110 Submodule::Declaration(name) => {
111 let (points_to, problem) = resolve_submodule(db, source, &name);
112 let points_to = points_to
113 .into_iter()
114 .map(|file_id| match roots.remove(&file_id) {
115 Some(module_id) => {
116 tree.mods[module_id].parent = Some(link);
117 Ok(module_id)
118 }
119 None => build_subtree(
120 db,
121 source_root,
122 tree,
123 visited,
124 roots,
125 Some(link),
126 ModuleSource::new_file(file_id.into()),
127 ),
128 })
129 .collect::<Cancelable<Vec<_>>>()?;
130 (points_to, problem)
131 }
132 Submodule::Definition(_name, submodule_source) => {
133 let points_to = build_subtree(
134 db,
135 source_root,
136 tree,
137 visited,
138 roots,
139 Some(link),
140 *submodule_source,
141 )?;
142 (vec![points_to], None)
143 }
144 };
145
146 tree.links[link].points_to = points_to;
147 tree.links[link].problem = problem;
148 }
149 Ok(id)
150}
151
152fn resolve_submodule(
153 db: &impl HirDatabase,
154 source: ModuleSource,
155 name: &Name,
156) -> (Vec<FileId>, Option<Problem>) {
157 // FIXME: handle submodules of inline modules properly
158 let file_id = source.file_id().original_file(db);
159 let source_root_id = db.file_source_root(file_id);
160 let path = db.file_relative_path(file_id);
161 let root = RelativePathBuf::default();
162 let dir_path = path.parent().unwrap_or(&root);
163 let mod_name = path.file_stem().unwrap_or("unknown");
164 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
165
166 let file_mod = dir_path.join(format!("{}.rs", name));
167 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
168 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
169 let mut candidates = ArrayVec::<[_; 2]>::new();
170 if is_dir_owner {
171 candidates.push(file_mod.clone());
172 candidates.push(dir_mod);
173 } else {
174 candidates.push(file_dir_mod.clone());
175 };
176 let sr = db.source_root(source_root_id);
177 let points_to = candidates
178 .into_iter()
179 .filter_map(|path| sr.files.get(&path))
180 .map(|&it| it)
181 .collect::<Vec<_>>();
182 let problem = if points_to.is_empty() {
183 Some(Problem::UnresolvedModule {
184 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
185 })
186 } else {
187 None
188 };
189 (points_to, problem)
190}
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
new file mode 100644
index 000000000..c7a442319
--- /dev/null
+++ b/crates/ra_hir/src/module_tree.rs
@@ -0,0 +1,368 @@
1use std::sync::Arc;
2
3use rustc_hash::{FxHashMap, FxHashSet};
4use arrayvec::ArrayVec;
5use relative_path::RelativePathBuf;
6use ra_db::{FileId, SourceRootId, Cancelable, SourceRoot};
7use ra_syntax::{
8 algo::generate,
9 ast::{self, AstNode, NameOwner},
10 SyntaxNode,
11};
12use ra_arena::{Arena, RawId, impl_arena_id};
13
14use crate::{Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource};
15
16impl ModuleSource {
17 pub fn from_source_item_id(
18 db: &impl HirDatabase,
19 source_item_id: SourceItemId,
20 ) -> ModuleSource {
21 let module_syntax = db.file_item(source_item_id);
22 let module_syntax = module_syntax.borrowed();
23 if let Some(source_file) = ast::SourceFile::cast(module_syntax) {
24 ModuleSource::SourceFile(source_file.owned())
25 } else if let Some(module) = ast::Module::cast(module_syntax) {
26 assert!(module.item_list().is_some(), "expected inline module");
27 ModuleSource::Module(module.owned())
28 } else {
29 panic!("expected file or inline module")
30 }
31 }
32}
33
34#[derive(Clone, Hash, PartialEq, Eq, Debug)]
35pub struct Submodule {
36 name: Name,
37 is_declaration: bool,
38 source: SourceItemId,
39}
40
41impl Submodule {
42 pub(crate) fn submodules_query(
43 db: &impl HirDatabase,
44 source: SourceItemId,
45 ) -> Cancelable<Arc<Vec<Submodule>>> {
46 db.check_canceled()?;
47 let file_id = source.file_id;
48 let file_items = db.file_items(file_id);
49 let module_source = ModuleSource::from_source_item_id(db, source);
50 let submodules = match module_source {
51 ModuleSource::SourceFile(source_file) => {
52 collect_submodules(file_id, &file_items, source_file.borrowed())
53 }
54 ModuleSource::Module(module) => {
55 let module = module.borrowed();
56 collect_submodules(file_id, &file_items, module.item_list().unwrap())
57 }
58 };
59 return Ok(Arc::new(submodules));
60
61 fn collect_submodules<'a>(
62 file_id: HirFileId,
63 file_items: &SourceFileItems,
64 root: impl ast::ModuleItemOwner<'a>,
65 ) -> Vec<Submodule> {
66 modules(root)
67 .map(|(name, m)| Submodule {
68 name,
69 is_declaration: m.has_semi(),
70 source: SourceItemId {
71 file_id,
72 item_id: Some(file_items.id_of(file_id, m.syntax())),
73 },
74 })
75 .collect()
76 }
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
81pub struct ModuleId(RawId);
82impl_arena_id!(ModuleId);
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
85pub struct LinkId(RawId);
86impl_arena_id!(LinkId);
87
88/// Physically, rust source is organized as a set of files, but logically it is
89/// organized as a tree of modules. Usually, a single file corresponds to a
90/// single module, but it is not nessary the case.
91///
92/// Module encapsulate the logic of transitioning from the fuzzy world of files
93/// (which can have multiple parents) to the precise world of modules (which
94/// always have one parent).
95#[derive(Default, Debug, PartialEq, Eq)]
96pub struct ModuleTree {
97 mods: Arena<ModuleId, ModuleData>,
98 links: Arena<LinkId, LinkData>,
99}
100
101#[derive(Debug, PartialEq, Eq, Hash)]
102pub struct ModuleData {
103 source: SourceItemId,
104 parent: Option<LinkId>,
105 children: Vec<LinkId>,
106}
107
108#[derive(Hash, Debug, PartialEq, Eq)]
109struct LinkData {
110 source: SourceItemId,
111 owner: ModuleId,
112 name: Name,
113 points_to: Vec<ModuleId>,
114 problem: Option<Problem>,
115}
116
117impl ModuleTree {
118 pub(crate) fn module_tree_query(
119 db: &impl HirDatabase,
120 source_root: SourceRootId,
121 ) -> Cancelable<Arc<ModuleTree>> {
122 db.check_canceled()?;
123 let res = create_module_tree(db, source_root)?;
124 Ok(Arc::new(res))
125 }
126
127 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
128 self.mods.iter().map(|(id, _)| id)
129 }
130
131 pub(crate) fn find_module_by_source(&self, source: SourceItemId) -> Option<ModuleId> {
132 let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?;
133 Some(res)
134 }
135}
136
137impl ModuleId {
138 pub(crate) fn source(self, tree: &ModuleTree) -> SourceItemId {
139 tree.mods[self].source
140 }
141 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
142 tree.mods[self].parent
143 }
144 pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
145 let link = self.parent_link(tree)?;
146 Some(tree.links[link].owner)
147 }
148 pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
149 generate(Some(self), move |it| it.parent(tree))
150 .last()
151 .unwrap()
152 }
153 pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
154 let link = tree.mods[self]
155 .children
156 .iter()
157 .map(|&it| &tree.links[it])
158 .find(|it| it.name == *name)?;
159 Some(*link.points_to.first()?)
160 }
161 pub(crate) fn children<'a>(
162 self,
163 tree: &'a ModuleTree,
164 ) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
165 tree.mods[self].children.iter().filter_map(move |&it| {
166 let link = &tree.links[it];
167 let module = *link.points_to.first()?;
168 Some((link.name.clone(), module))
169 })
170 }
171 pub(crate) fn problems(
172 self,
173 tree: &ModuleTree,
174 db: &impl HirDatabase,
175 ) -> Vec<(SyntaxNode, Problem)> {
176 tree.mods[self]
177 .children
178 .iter()
179 .filter_map(|&link| {
180 let p = tree.links[link].problem.clone()?;
181 let s = link.source(tree, db);
182 let s = s.borrowed().name().unwrap().syntax().owned();
183 Some((s, p))
184 })
185 .collect()
186 }
187}
188
189impl LinkId {
190 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
191 tree.links[self].owner
192 }
193 pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
194 &tree.links[self].name
195 }
196 pub(crate) fn source(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode {
197 let syntax_node = db.file_item(tree.links[self].source);
198 ast::ModuleNode::cast(syntax_node.borrowed())
199 .unwrap()
200 .owned()
201 }
202}
203
204impl ModuleTree {
205 fn push_mod(&mut self, data: ModuleData) -> ModuleId {
206 self.mods.alloc(data)
207 }
208 fn push_link(&mut self, data: LinkData) -> LinkId {
209 let owner = data.owner;
210 let id = self.links.alloc(data);
211 self.mods[owner].children.push(id);
212 id
213 }
214}
215
216fn modules<'a>(
217 root: impl ast::ModuleItemOwner<'a>,
218) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
219 root.items()
220 .filter_map(|item| match item {
221 ast::ModuleItem::Module(m) => Some(m),
222 _ => None,
223 })
224 .filter_map(|module| {
225 let name = module.name()?.as_name();
226 Some((name, module))
227 })
228}
229
230fn create_module_tree<'a>(
231 db: &impl HirDatabase,
232 source_root: SourceRootId,
233) -> Cancelable<ModuleTree> {
234 let mut tree = ModuleTree::default();
235
236 let mut roots = FxHashMap::default();
237 let mut visited = FxHashSet::default();
238
239 let source_root = db.source_root(source_root);
240 for &file_id in source_root.files.values() {
241 let source = SourceItemId {
242 file_id: file_id.into(),
243 item_id: None,
244 };
245 if visited.contains(&source) {
246 continue; // TODO: use explicit crate_roots here
247 }
248 assert!(!roots.contains_key(&file_id));
249 let module_id = build_subtree(
250 db,
251 &source_root,
252 &mut tree,
253 &mut visited,
254 &mut roots,
255 None,
256 source,
257 )?;
258 roots.insert(file_id, module_id);
259 }
260 Ok(tree)
261}
262
263fn build_subtree(
264 db: &impl HirDatabase,
265 source_root: &SourceRoot,
266 tree: &mut ModuleTree,
267 visited: &mut FxHashSet<SourceItemId>,
268 roots: &mut FxHashMap<FileId, ModuleId>,
269 parent: Option<LinkId>,
270 source: SourceItemId,
271) -> Cancelable<ModuleId> {
272 visited.insert(source);
273 let id = tree.push_mod(ModuleData {
274 source,
275 parent,
276 children: Vec::new(),
277 });
278 for sub in db.submodules(source)?.iter() {
279 let link = tree.push_link(LinkData {
280 source: sub.source,
281 name: sub.name.clone(),
282 owner: id,
283 points_to: Vec::new(),
284 problem: None,
285 });
286
287 let (points_to, problem) = if sub.is_declaration {
288 let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name);
289 let points_to = points_to
290 .into_iter()
291 .map(|file_id| match roots.remove(&file_id) {
292 Some(module_id) => {
293 tree.mods[module_id].parent = Some(link);
294 Ok(module_id)
295 }
296 None => build_subtree(
297 db,
298 source_root,
299 tree,
300 visited,
301 roots,
302 Some(link),
303 SourceItemId {
304 file_id: file_id.into(),
305 item_id: None,
306 },
307 ),
308 })
309 .collect::<Cancelable<Vec<_>>>()?;
310 (points_to, problem)
311 } else {
312 let points_to = build_subtree(
313 db,
314 source_root,
315 tree,
316 visited,
317 roots,
318 Some(link),
319 sub.source,
320 )?;
321 (vec![points_to], None)
322 };
323
324 tree.links[link].points_to = points_to;
325 tree.links[link].problem = problem;
326 }
327 Ok(id)
328}
329
330fn resolve_submodule(
331 db: &impl HirDatabase,
332 file_id: HirFileId,
333 name: &Name,
334) -> (Vec<FileId>, Option<Problem>) {
335 // FIXME: handle submodules of inline modules properly
336 let file_id = file_id.original_file(db);
337 let source_root_id = db.file_source_root(file_id);
338 let path = db.file_relative_path(file_id);
339 let root = RelativePathBuf::default();
340 let dir_path = path.parent().unwrap_or(&root);
341 let mod_name = path.file_stem().unwrap_or("unknown");
342 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
343
344 let file_mod = dir_path.join(format!("{}.rs", name));
345 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
346 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
347 let mut candidates = ArrayVec::<[_; 2]>::new();
348 if is_dir_owner {
349 candidates.push(file_mod.clone());
350 candidates.push(dir_mod);
351 } else {
352 candidates.push(file_dir_mod.clone());
353 };
354 let sr = db.source_root(source_root_id);
355 let points_to = candidates
356 .into_iter()
357 .filter_map(|path| sr.files.get(&path))
358 .map(|&it| it)
359 .collect::<Vec<_>>();
360 let problem = if points_to.is_empty() {
361 Some(Problem::UnresolvedModule {
362 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
363 })
364 } else {
365 None
366 };
367 (points_to, problem)
368}
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 017caf442..90229bc54 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -31,6 +31,14 @@ impl Name {
31 Name::new("[missing name]".into()) 31 Name::new("[missing name]".into())
32 } 32 }
33 33
34 pub(crate) fn self_param() -> Name {
35 Name::new("self".into())
36 }
37
38 pub(crate) fn self_type() -> Name {
39 Name::new("Self".into())
40 }
41
34 pub(crate) fn tuple_field_name(idx: usize) -> Name { 42 pub(crate) fn tuple_field_name(idx: usize) -> Name {
35 Name::new(idx.to_string().into()) 43 Name::new(idx.to_string().into())
36 } 44 }
@@ -51,7 +59,8 @@ impl Name {
51 "u128" => KnownName::U128, 59 "u128" => KnownName::U128,
52 "f32" => KnownName::F32, 60 "f32" => KnownName::F32,
53 "f64" => KnownName::F64, 61 "f64" => KnownName::F64,
54 "Self" => KnownName::Self_, 62 "Self" => KnownName::SelfType,
63 "self" => KnownName::SelfParam,
55 _ => return None, 64 _ => return None,
56 }; 65 };
57 Some(name) 66 Some(name)
@@ -104,5 +113,6 @@ pub(crate) enum KnownName {
104 F32, 113 F32,
105 F64, 114 F64,
106 115
107 Self_, 116 SelfType,
117 SelfParam,
108} 118}
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/nameres.rs
index 3c6851a0a..9a412bc82 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -31,7 +31,7 @@ use crate::{
31 Path, PathKind, 31 Path, PathKind,
32 HirDatabase, Crate, 32 HirDatabase, Crate,
33 Name, AsName, 33 Name, AsName,
34 module::{Module, ModuleId, ModuleTree}, 34 module_tree::{ModuleId, ModuleTree},
35}; 35};
36 36
37/// Item map is the result of the name resolution. Item map contains, for each 37/// Item map is the result of the name resolution. Item map contains, for each
@@ -177,11 +177,11 @@ impl<T> PerNs<T> {
177 } 177 }
178 178
179 pub fn take_types(self) -> Option<T> { 179 pub fn take_types(self) -> Option<T> {
180 self.types 180 self.take(Namespace::Types)
181 } 181 }
182 182
183 pub fn take_values(self) -> Option<T> { 183 pub fn take_values(self) -> Option<T> {
184 self.values 184 self.take(Namespace::Values)
185 } 185 }
186 186
187 pub fn get(&self, namespace: Namespace) -> Option<&T> { 187 pub fn get(&self, namespace: Namespace) -> Option<&T> {
@@ -339,14 +339,14 @@ where
339 // Populate extern crates prelude 339 // Populate extern crates prelude
340 { 340 {
341 let root_id = module_id.crate_root(&self.module_tree); 341 let root_id = module_id.crate_root(&self.module_tree);
342 let file_id = root_id.source(&self.module_tree).file_id(); 342 let file_id = root_id.source(&self.module_tree).file_id;
343 let crate_graph = self.db.crate_graph(); 343 let crate_graph = self.db.crate_graph();
344 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) 344 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
345 { 345 {
346 let krate = Crate::new(crate_id); 346 let krate = Crate::new(crate_id);
347 for dep in krate.dependencies(self.db) { 347 for dep in krate.dependencies(self.db)? {
348 if let Some(module) = dep.krate.root_module(self.db)? { 348 if let Some(module) = dep.krate.root_module(self.db)? {
349 let def_id = module.def_id(self.db); 349 let def_id = module.def_id;
350 self.add_module_item( 350 self.add_module_item(
351 &mut module_items, 351 &mut module_items,
352 dep.name.clone(), 352 dep.name.clone(),
@@ -399,7 +399,7 @@ where
399 kind: DefKind::Module, 399 kind: DefKind::Module,
400 source_root_id: self.source_root, 400 source_root_id: self.source_root,
401 module_id, 401 module_id,
402 source_item_id: module_id.source(&self.module_tree).0, 402 source_item_id: module_id.source(&self.module_tree),
403 }; 403 };
404 let def_id = def_loc.id(self.db); 404 let def_id = def_loc.id(self.db);
405 self.add_module_item(&mut module_items, name, PerNs::types(def_id)); 405 self.add_module_item(&mut module_items, name, PerNs::types(def_id));
@@ -466,7 +466,7 @@ where
466 if source_root_id == self.source_root { 466 if source_root_id == self.source_root {
467 target_module_id 467 target_module_id
468 } else { 468 } else {
469 let module = Module::new(self.db, source_root_id, target_module_id)?; 469 let module = crate::code_model_api::Module::new(type_def_id);
470 let path = Path { 470 let path = Path {
471 segments: import.path.segments[i + 1..].iter().cloned().collect(), 471 segments: import.path.segments[i + 1..].iter().cloned().collect(),
472 kind: PathKind::Crate, 472 kind: PathKind::Crate,
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index a6a0bea31..dcbe65aec 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -17,7 +17,7 @@ fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
17 let module = hir::source_binder::module_from_position(&db, pos) 17 let module = hir::source_binder::module_from_position(&db, pos)
18 .unwrap() 18 .unwrap()
19 .unwrap(); 19 .unwrap();
20 let module_id = module.module_id; 20 let module_id = module.def_id.loc(&db).module_id;
21 (db.item_map(source_root).unwrap(), module_id) 21 (db.item_map(source_root).unwrap(), module_id)
22} 22}
23 23
@@ -155,7 +155,7 @@ fn item_map_across_crates() {
155 let module = hir::source_binder::module_from_file_id(&db, main_id) 155 let module = hir::source_binder::module_from_file_id(&db, main_id)
156 .unwrap() 156 .unwrap()
157 .unwrap(); 157 .unwrap();
158 let module_id = module.module_id; 158 let module_id = module.def_id.loc(&db).module_id;
159 let item_map = db.item_map(source_root).unwrap(); 159 let item_map = db.item_map(source_root).unwrap();
160 160
161 check_module_item_map( 161 check_module_item_map(
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 9fdfa0d13..dcf4cf8b6 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -65,6 +65,11 @@ impl Path {
65 } 65 }
66 } 66 }
67 67
68 /// Converts an `ast::NameRef` into a single-identifier `Path`.
69 pub fn from_name_ref(name_ref: ast::NameRef) -> Path {
70 name_ref.as_name().into()
71 }
72
68 /// `true` is this path is a single identifier, like `foo` 73 /// `true` is this path is a single identifier, like `foo`
69 pub fn is_ident(&self) -> bool { 74 pub fn is_ident(&self) -> bool {
70 self.kind == PathKind::Plain && self.segments.len() == 1 75 self.kind == PathKind::Plain && self.segments.len() == 1
@@ -84,6 +89,15 @@ impl Path {
84 } 89 }
85} 90}
86 91
92impl From<Name> for Path {
93 fn from(name: Name) -> Path {
94 Path {
95 kind: PathKind::Plain,
96 segments: vec![name],
97 }
98 }
99}
100
87fn expand_use_tree( 101fn expand_use_tree(
88 prefix: Option<Path>, 102 prefix: Option<Path>,
89 tree: ast::UseTree, 103 tree: ast::UseTree,
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index a5d99beda..8f2c40669 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -6,28 +6,24 @@ use std::{
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use ra_syntax::{ 7use ra_syntax::{
8 AstNode, SyntaxNode, 8 AstNode, SyntaxNode,
9 ast::{self, NameOwner, ModuleItemOwner} 9 ast::{self, ModuleItemOwner}
10}; 10};
11use ra_db::{SourceRootId, Cancelable,}; 11use ra_db::{SourceRootId, Cancelable,};
12 12
13use crate::{ 13use crate::{
14 SourceFileItems, SourceItemId, DefKind, Function, DefId, Name, AsName, HirFileId, 14 SourceFileItems, SourceItemId, DefKind, DefId, HirFileId, ModuleSource,
15 MacroCallLoc, 15 MacroCallLoc,
16 db::HirDatabase, 16 db::HirDatabase,
17 function::FnScopes, 17 function::FnScopes,
18 module::{ 18 module_tree::ModuleId,
19 ModuleSource, ModuleSourceNode, ModuleId, 19 nameres::{InputModuleItems, ItemMap, Resolver},
20 imp::Submodule,
21 nameres::{InputModuleItems, ItemMap, Resolver},
22 },
23 adt::{StructData, EnumData}, 20 adt::{StructData, EnumData},
24}; 21};
25 22
26pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> { 23pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<FnScopes>> {
27 let function = Function::new(def_id); 24 let body = db.body_hir(def_id)?;
28 let syntax = function.syntax(db); 25 let res = FnScopes::new(body);
29 let res = FnScopes::new(syntax.borrowed()); 26 Ok(Arc::new(res))
30 Arc::new(res)
31} 27}
32 28
33pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> { 29pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
@@ -62,54 +58,6 @@ pub(super) fn file_item(db: &impl HirDatabase, source_item_id: SourceItemId) ->
62 } 58 }
63} 59}
64 60
65pub(crate) fn submodules(
66 db: &impl HirDatabase,
67 source: ModuleSource,
68) -> Cancelable<Arc<Vec<Submodule>>> {
69 db.check_canceled()?;
70 let file_id = source.file_id();
71 let submodules = match source.resolve(db) {
72 ModuleSourceNode::SourceFile(it) => collect_submodules(db, file_id, it.borrowed()),
73 ModuleSourceNode::Module(it) => it
74 .borrowed()
75 .item_list()
76 .map(|it| collect_submodules(db, file_id, it))
77 .unwrap_or_else(Vec::new),
78 };
79 return Ok(Arc::new(submodules));
80
81 fn collect_submodules<'a>(
82 db: &impl HirDatabase,
83 file_id: HirFileId,
84 root: impl ast::ModuleItemOwner<'a>,
85 ) -> Vec<Submodule> {
86 modules(root)
87 .map(|(name, m)| {
88 if m.has_semi() {
89 Submodule::Declaration(name)
90 } else {
91 let src = ModuleSource::new_inline(db, file_id, m);
92 Submodule::Definition(name, src)
93 }
94 })
95 .collect()
96 }
97}
98
99pub(crate) fn modules<'a>(
100 root: impl ast::ModuleItemOwner<'a>,
101) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
102 root.items()
103 .filter_map(|item| match item {
104 ast::ModuleItem::Module(m) => Some(m),
105 _ => None,
106 })
107 .filter_map(|module| {
108 let name = module.name()?.as_name();
109 Some((name, module))
110 })
111}
112
113pub(super) fn input_module_items( 61pub(super) fn input_module_items(
114 db: &impl HirDatabase, 62 db: &impl HirDatabase,
115 source_root_id: SourceRootId, 63 source_root_id: SourceRootId,
@@ -117,7 +65,8 @@ pub(super) fn input_module_items(
117) -> Cancelable<Arc<InputModuleItems>> { 65) -> Cancelable<Arc<InputModuleItems>> {
118 let module_tree = db.module_tree(source_root_id)?; 66 let module_tree = db.module_tree(source_root_id)?;
119 let source = module_id.source(&module_tree); 67 let source = module_id.source(&module_tree);
120 let file_id = source.file_id(); 68 let file_id = source.file_id;
69 let source = ModuleSource::from_source_item_id(db, source);
121 let file_items = db.file_items(file_id); 70 let file_items = db.file_items(file_id);
122 let fill = |acc: &mut InputModuleItems, items: &mut Iterator<Item = ast::ItemOrMacro>| { 71 let fill = |acc: &mut InputModuleItems, items: &mut Iterator<Item = ast::ItemOrMacro>| {
123 for item in items { 72 for item in items {
@@ -148,9 +97,9 @@ pub(super) fn input_module_items(
148 }; 97 };
149 98
150 let mut res = InputModuleItems::default(); 99 let mut res = InputModuleItems::default();
151 match source.resolve(db) { 100 match source {
152 ModuleSourceNode::SourceFile(it) => fill(&mut res, &mut it.borrowed().items_with_macros()), 101 ModuleSource::SourceFile(it) => fill(&mut res, &mut it.borrowed().items_with_macros()),
153 ModuleSourceNode::Module(it) => { 102 ModuleSource::Module(it) => {
154 if let Some(item_list) = it.borrowed().item_list() { 103 if let Some(item_list) = it.borrowed().item_list() {
155 fill(&mut res, &mut item_list.items_with_macros()) 104 fill(&mut res, &mut item_list.items_with_macros())
156 } 105 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 85bd84469..4c14650c0 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -13,14 +13,16 @@ use ra_syntax::{
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Module, Function, SourceItemId, 16 HirDatabase, Function, SourceItemId,
17 module::ModuleSource, 17 DefKind, DefLoc, AsName, Module,
18 DefKind, DefLoc, AsName,
19}; 18};
20 19
21/// Locates the module by `FileId`. Picks topmost module in the file. 20/// Locates the module by `FileId`. Picks topmost module in the file.
22pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> { 21pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> {
23 let module_source = ModuleSource::new_file(file_id.into()); 22 let module_source = SourceItemId {
23 file_id: file_id.into(),
24 item_id: None,
25 };
24 module_from_source(db, module_source) 26 module_from_source(db, module_source)
25} 27}
26 28
@@ -34,7 +36,7 @@ pub fn module_from_declaration(
34 let child_name = decl.name(); 36 let child_name = decl.name();
35 match (parent_module, child_name) { 37 match (parent_module, child_name) {
36 (Some(parent_module), Some(child_name)) => { 38 (Some(parent_module), Some(child_name)) => {
37 if let Some(child) = parent_module.child(&child_name.as_name()) { 39 if let Some(child) = parent_module.child(db, &child_name.as_name())? {
38 return Ok(Some(child)); 40 return Ok(Some(child));
39 } 41 }
40 } 42 }
@@ -49,11 +51,26 @@ pub fn module_from_position(
49 position: FilePosition, 51 position: FilePosition,
50) -> Cancelable<Option<Module>> { 52) -> Cancelable<Option<Module>> {
51 let file = db.source_file(position.file_id); 53 let file = db.source_file(position.file_id);
52 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) { 54 match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) {
53 Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id.into(), m), 55 Some(m) if !m.has_semi() => module_from_inline(db, position.file_id.into(), m),
54 _ => ModuleSource::new_file(position.file_id.into()), 56 _ => module_from_file_id(db, position.file_id.into()),
57 }
58}
59
60fn module_from_inline(
61 db: &impl HirDatabase,
62 file_id: FileId,
63 module: ast::Module,
64) -> Cancelable<Option<Module>> {
65 assert!(!module.has_semi());
66 let file_id = file_id.into();
67 let file_items = db.file_items(file_id);
68 let item_id = file_items.id_of(file_id, module.syntax());
69 let source = SourceItemId {
70 file_id,
71 item_id: Some(item_id),
55 }; 72 };
56 module_from_source(db, module_source) 73 module_from_source(db, source)
57} 74}
58 75
59/// Locates the module by child syntax element within the module 76/// Locates the module by child syntax element within the module
@@ -62,29 +79,34 @@ pub fn module_from_child_node(
62 file_id: FileId, 79 file_id: FileId,
63 child: SyntaxNodeRef, 80 child: SyntaxNodeRef,
64) -> Cancelable<Option<Module>> { 81) -> Cancelable<Option<Module>> {
65 let module_source = if let Some(m) = child 82 if let Some(m) = child
66 .ancestors() 83 .ancestors()
67 .filter_map(ast::Module::cast) 84 .filter_map(ast::Module::cast)
68 .find(|it| !it.has_semi()) 85 .find(|it| !it.has_semi())
69 { 86 {
70 ModuleSource::new_inline(db, file_id.into(), m) 87 module_from_inline(db, file_id.into(), m)
71 } else { 88 } else {
72 ModuleSource::new_file(file_id.into()) 89 module_from_file_id(db, file_id.into())
73 }; 90 }
74 module_from_source(db, module_source)
75} 91}
76 92
77fn module_from_source( 93fn module_from_source(db: &impl HirDatabase, source: SourceItemId) -> Cancelable<Option<Module>> {
78 db: &impl HirDatabase, 94 let source_root_id = db.file_source_root(source.file_id.as_original_file());
79 module_source: ModuleSource,
80) -> Cancelable<Option<Module>> {
81 let source_root_id = db.file_source_root(module_source.file_id().as_original_file());
82 let module_tree = db.module_tree(source_root_id)?; 95 let module_tree = db.module_tree(source_root_id)?;
83 let m = module_tree 96 let module_id = ctry!(module_tree.find_module_by_source(source));
84 .modules_with_sources() 97 Ok(Some(Module::from_module_id(db, source_root_id, module_id)?))
85 .find(|(_id, src)| src == &module_source); 98}
86 let module_id = ctry!(m).0; 99
87 Ok(Some(Module::new(db, source_root_id, module_id)?)) 100pub fn function_from_position(
101 db: &impl HirDatabase,
102 position: FilePosition,
103) -> Cancelable<Option<Function>> {
104 let file = db.source_file(position.file_id);
105 let fn_def = ctry!(find_node_at_offset::<ast::FnDef>(
106 file.syntax(),
107 position.offset
108 ));
109 function_from_source(db, position.file_id, fn_def)
88} 110}
89 111
90pub fn function_from_source( 112pub fn function_from_source(
@@ -102,7 +124,8 @@ pub fn function_from_module(
102 module: &Module, 124 module: &Module,
103 fn_def: ast::FnDef, 125 fn_def: ast::FnDef,
104) -> Function { 126) -> Function {
105 let file_id = module.source().file_id(); 127 let loc = module.def_id.loc(db);
128 let file_id = loc.source_item_id.file_id;
106 let file_items = db.file_items(file_id); 129 let file_items = db.file_items(file_id);
107 let item_id = file_items.id_of(file_id, fn_def.syntax()); 130 let item_id = file_items.id_of(file_id, fn_def.syntax());
108 let source_item_id = SourceItemId { 131 let source_item_id = SourceItemId {
@@ -111,8 +134,8 @@ pub fn function_from_module(
111 }; 134 };
112 let def_loc = DefLoc { 135 let def_loc = DefLoc {
113 kind: DefKind::Function, 136 kind: DefKind::Function,
114 source_root_id: module.source_root_id, 137 source_root_id: loc.source_root_id,
115 module_id: module.module_id, 138 module_id: loc.module_id,
116 source_item_id, 139 source_item_id,
117 }; 140 };
118 Function::new(def_loc.id(db)) 141 Function::new(def_loc.id(db))
@@ -135,7 +158,8 @@ pub fn macro_symbols(
135 Some(it) => it, 158 Some(it) => it,
136 None => return Ok(Vec::new()), 159 None => return Ok(Vec::new()),
137 }; 160 };
138 let items = db.input_module_items(module.source_root_id, module.module_id)?; 161 let loc = module.def_id.loc(db);
162 let items = db.input_module_items(loc.source_root_id, loc.module_id)?;
139 let mut res = Vec::new(); 163 let mut res = Vec::new();
140 164
141 for macro_call_id in items 165 for macro_call_id in items
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 8f56cdb15..b685259d7 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -31,10 +31,11 @@ use ra_syntax::{
31}; 31};
32 32
33use crate::{ 33use crate::{
34 Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock, 34 Def, DefId, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock,
35 db::HirDatabase, 35 db::HirDatabase,
36 type_ref::{TypeRef, Mutability}, 36 type_ref::{TypeRef, Mutability},
37 name::KnownName, 37 name::KnownName,
38 ScopesWithSyntaxMapping,
38}; 39};
39 40
40/// The ID of a type variable. 41/// The ID of a type variable.
@@ -305,7 +306,7 @@ impl Ty {
305 return Ok(Ty::Uint(uint_ty)); 306 return Ok(Ty::Uint(uint_ty));
306 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { 307 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
307 return Ok(Ty::Float(float_ty)); 308 return Ok(Ty::Float(float_ty));
308 } else if name.as_known_name() == Some(KnownName::Self_) { 309 } else if name.as_known_name() == Some(KnownName::SelfType) {
309 return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); 310 return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
310 } 311 }
311 } 312 }
@@ -515,7 +516,7 @@ impl InferenceResult {
515#[derive(Clone, Debug)] 516#[derive(Clone, Debug)]
516struct InferenceContext<'a, D: HirDatabase> { 517struct InferenceContext<'a, D: HirDatabase> {
517 db: &'a D, 518 db: &'a D,
518 scopes: Arc<FnScopes>, 519 scopes: ScopesWithSyntaxMapping,
519 /// The self param for the current method, if it exists. 520 /// The self param for the current method, if it exists.
520 self_param: Option<LocalSyntaxPtr>, 521 self_param: Option<LocalSyntaxPtr>,
521 module: Module, 522 module: Module,
@@ -543,7 +544,7 @@ fn is_boolean_operator(op: BinOp) -> bool {
543impl<'a, D: HirDatabase> InferenceContext<'a, D> { 544impl<'a, D: HirDatabase> InferenceContext<'a, D> {
544 fn new( 545 fn new(
545 db: &'a D, 546 db: &'a D,
546 scopes: Arc<FnScopes>, 547 scopes: ScopesWithSyntaxMapping,
547 module: Module, 548 module: Module,
548 impl_block: Option<ImplBlock>, 549 impl_block: Option<ImplBlock>,
549 ) -> Self { 550 ) -> Self {
@@ -840,10 +841,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
840 self.infer_expr_opt(e.expr(), &Expectation::none())?; 841 self.infer_expr_opt(e.expr(), &Expectation::none())?;
841 Ty::Never 842 Ty::Never
842 } 843 }
843 ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
844 // Can this even occur outside of a match expression?
845 Ty::Unknown
846 }
847 ast::Expr::StructLit(e) => { 844 ast::Expr::StructLit(e) => {
848 let (ty, def_id) = self.resolve_variant(e.path())?; 845 let (ty, def_id) = self.resolve_variant(e.path())?;
849 if let Some(nfl) = e.named_field_list() { 846 if let Some(nfl) = e.named_field_list() {
@@ -859,10 +856,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
859 } 856 }
860 ty 857 ty
861 } 858 }
862 ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => {
863 // Can this even occur outside of a struct literal?
864 Ty::Unknown
865 }
866 ast::Expr::IndexExpr(_e) => Ty::Unknown, 859 ast::Expr::IndexExpr(_e) => Ty::Unknown,
867 ast::Expr::FieldExpr(e) => { 860 ast::Expr::FieldExpr(e) => {
868 let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 861 let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
@@ -1047,7 +1040,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1047 1040
1048pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 1041pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
1049 let function = Function::new(def_id); // TODO: consts also need inference 1042 let function = Function::new(def_id); // TODO: consts also need inference
1050 let scopes = function.scopes(db); 1043 let scopes = function.scopes(db)?;
1051 let module = function.module(db)?; 1044 let module = function.module(db)?;
1052 let impl_block = function.impl_block(db)?; 1045 let impl_block = function.impl_block(db)?;
1053 let mut ctx = InferenceContext::new(db, scopes, module, impl_block); 1046 let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 1650606b7..25a354947 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1,7 +1,10 @@
1use std::sync::Arc;
1use std::fmt::Write; 2use std::fmt::Write;
2use std::path::{PathBuf, Path}; 3use std::path::{PathBuf, Path};
3use std::fs; 4use std::fs;
4 5
6use salsa::Database;
7
5use ra_db::{SyntaxDatabase}; 8use ra_db::{SyntaxDatabase};
6use ra_syntax::ast::{self, AstNode}; 9use ra_syntax::ast::{self, AstNode};
7use test_utils::{project_dir, assert_eq_text, read_text}; 10use test_utils::{project_dir, assert_eq_text, read_text};
@@ -241,3 +244,44 @@ fn ellipsize(mut text: String, max_len: usize) -> String {
241fn test_data_dir() -> PathBuf { 244fn test_data_dir() -> PathBuf {
242 project_dir().join("crates/ra_hir/src/ty/tests/data") 245 project_dir().join("crates/ra_hir/src/ty/tests/data")
243} 246}
247
248#[test]
249#[should_panic] // TODO this should work once hir::Expr is used
250fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
251 let (mut db, pos) = MockDatabase::with_position(
252 "
253 //- /lib.rs
254 fn foo() -> i32 {
255 <|>1 + 1
256 }
257 ",
258 );
259 let func = source_binder::function_from_position(&db, pos)
260 .unwrap()
261 .unwrap();
262 {
263 let events = db.log_executed(|| {
264 func.infer(&db).unwrap();
265 });
266 assert!(format!("{:?}", events).contains("infer"))
267 }
268
269 let new_text = "
270 fn foo() -> i32 {
271 1
272 +
273 1
274 }
275 "
276 .to_string();
277
278 db.query_mut(ra_db::FileTextQuery)
279 .set(pos.file_id, Arc::new(new_text));
280
281 {
282 let events = db.log_executed(|| {
283 func.infer(&db).unwrap();
284 });
285 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events)
286 }
287}
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
index b36bb35d8..859f330c2 100644
--- a/crates/ra_hir/src/type_ref.rs
+++ b/crates/ra_hir/src/type_ref.rs
@@ -107,4 +107,8 @@ impl TypeRef {
107 TypeRef::Error 107 TypeRef::Error
108 } 108 }
109 } 109 }
110
111 pub fn unit() -> TypeRef {
112 TypeRef::Tuple(Vec::new())
113 }
110} 114}
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 7df6a9c46..24f72393a 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -378,7 +378,11 @@ impl<R: TreeRoot<RaTypes>> BreakExprNode<R> {
378} 378}
379 379
380 380
381impl<'a> BreakExpr<'a> {} 381impl<'a> BreakExpr<'a> {
382 pub fn expr(self) -> Option<Expr<'a>> {
383 super::child_opt(self)
384 }
385}
382 386
383// Byte 387// Byte
384#[derive(Debug, Clone, Copy,)] 388#[derive(Debug, Clone, Copy,)]
@@ -923,12 +927,7 @@ pub enum Expr<'a> {
923 BlockExpr(BlockExpr<'a>), 927 BlockExpr(BlockExpr<'a>),
924 ReturnExpr(ReturnExpr<'a>), 928 ReturnExpr(ReturnExpr<'a>),
925 MatchExpr(MatchExpr<'a>), 929 MatchExpr(MatchExpr<'a>),
926 MatchArmList(MatchArmList<'a>),
927 MatchArm(MatchArm<'a>),
928 MatchGuard(MatchGuard<'a>),
929 StructLit(StructLit<'a>), 930 StructLit(StructLit<'a>),
930 NamedFieldList(NamedFieldList<'a>),
931 NamedField(NamedField<'a>),
932 CallExpr(CallExpr<'a>), 931 CallExpr(CallExpr<'a>),
933 IndexExpr(IndexExpr<'a>), 932 IndexExpr(IndexExpr<'a>),
934 MethodCallExpr(MethodCallExpr<'a>), 933 MethodCallExpr(MethodCallExpr<'a>),
@@ -960,12 +959,7 @@ impl<'a> AstNode<'a> for Expr<'a> {
960 BLOCK_EXPR => Some(Expr::BlockExpr(BlockExpr { syntax })), 959 BLOCK_EXPR => Some(Expr::BlockExpr(BlockExpr { syntax })),
961 RETURN_EXPR => Some(Expr::ReturnExpr(ReturnExpr { syntax })), 960 RETURN_EXPR => Some(Expr::ReturnExpr(ReturnExpr { syntax })),
962 MATCH_EXPR => Some(Expr::MatchExpr(MatchExpr { syntax })), 961 MATCH_EXPR => Some(Expr::MatchExpr(MatchExpr { syntax })),
963 MATCH_ARM_LIST => Some(Expr::MatchArmList(MatchArmList { syntax })),
964 MATCH_ARM => Some(Expr::MatchArm(MatchArm { syntax })),
965 MATCH_GUARD => Some(Expr::MatchGuard(MatchGuard { syntax })),
966 STRUCT_LIT => Some(Expr::StructLit(StructLit { syntax })), 962 STRUCT_LIT => Some(Expr::StructLit(StructLit { syntax })),
967 NAMED_FIELD_LIST => Some(Expr::NamedFieldList(NamedFieldList { syntax })),
968 NAMED_FIELD => Some(Expr::NamedField(NamedField { syntax })),
969 CALL_EXPR => Some(Expr::CallExpr(CallExpr { syntax })), 963 CALL_EXPR => Some(Expr::CallExpr(CallExpr { syntax })),
970 INDEX_EXPR => Some(Expr::IndexExpr(IndexExpr { syntax })), 964 INDEX_EXPR => Some(Expr::IndexExpr(IndexExpr { syntax })),
971 METHOD_CALL_EXPR => Some(Expr::MethodCallExpr(MethodCallExpr { syntax })), 965 METHOD_CALL_EXPR => Some(Expr::MethodCallExpr(MethodCallExpr { syntax })),
@@ -997,12 +991,7 @@ impl<'a> AstNode<'a> for Expr<'a> {
997 Expr::BlockExpr(inner) => inner.syntax(), 991 Expr::BlockExpr(inner) => inner.syntax(),
998 Expr::ReturnExpr(inner) => inner.syntax(), 992 Expr::ReturnExpr(inner) => inner.syntax(),
999 Expr::MatchExpr(inner) => inner.syntax(), 993 Expr::MatchExpr(inner) => inner.syntax(),
1000 Expr::MatchArmList(inner) => inner.syntax(),
1001 Expr::MatchArm(inner) => inner.syntax(),
1002 Expr::MatchGuard(inner) => inner.syntax(),
1003 Expr::StructLit(inner) => inner.syntax(), 994 Expr::StructLit(inner) => inner.syntax(),
1004 Expr::NamedFieldList(inner) => inner.syntax(),
1005 Expr::NamedField(inner) => inner.syntax(),
1006 Expr::CallExpr(inner) => inner.syntax(), 995 Expr::CallExpr(inner) => inner.syntax(),
1007 Expr::IndexExpr(inner) => inner.syntax(), 996 Expr::IndexExpr(inner) => inner.syntax(),
1008 Expr::MethodCallExpr(inner) => inner.syntax(), 997 Expr::MethodCallExpr(inner) => inner.syntax(),
@@ -3880,6 +3869,10 @@ impl<'a> StructLit<'a> {
3880 pub fn named_field_list(self) -> Option<NamedFieldList<'a>> { 3869 pub fn named_field_list(self) -> Option<NamedFieldList<'a>> {
3881 super::child_opt(self) 3870 super::child_opt(self)
3882 } 3871 }
3872
3873 pub fn spread(self) -> Option<Expr<'a>> {
3874 super::child_opt(self)
3875 }
3883} 3876}
3884 3877
3885// StructPat 3878// StructPat
@@ -4147,7 +4140,15 @@ impl<R: TreeRoot<RaTypes>> TupleStructPatNode<R> {
4147} 4140}
4148 4141
4149 4142
4150impl<'a> TupleStructPat<'a> {} 4143impl<'a> TupleStructPat<'a> {
4144 pub fn args(self) -> impl Iterator<Item = Pat<'a>> + 'a {
4145 super::children(self)
4146 }
4147
4148 pub fn path(self) -> Option<Path<'a>> {
4149 super::child_opt(self)
4150 }
4151}
4151 4152
4152// TupleType 4153// TupleType
4153#[derive(Debug, Clone, Copy,)] 4154#[derive(Debug, Clone, Copy,)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index c55e9e07a..3c640ed47 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -384,7 +384,7 @@ Grammar(
384 options: [ "Condition" ] 384 options: [ "Condition" ]
385 ), 385 ),
386 "ContinueExpr": (), 386 "ContinueExpr": (),
387 "BreakExpr": (), 387 "BreakExpr": (options: ["Expr"]),
388 "Label": (), 388 "Label": (),
389 "BlockExpr": ( 389 "BlockExpr": (
390 options: [ "Block" ] 390 options: [ "Block" ]
@@ -404,7 +404,7 @@ Grammar(
404 collections: [ [ "pats", "Pat" ] ] 404 collections: [ [ "pats", "Pat" ] ]
405 ), 405 ),
406 "MatchGuard": (), 406 "MatchGuard": (),
407 "StructLit": (options: ["Path", "NamedFieldList"]), 407 "StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]),
408 "NamedFieldList": (collections: [ ["fields", "NamedField"] ]), 408 "NamedFieldList": (collections: [ ["fields", "NamedField"] ]),
409 "NamedField": (options: ["NameRef", "Expr"]), 409 "NamedField": (options: ["NameRef", "Expr"]),
410 "CallExpr": ( 410 "CallExpr": (
@@ -446,12 +446,7 @@ Grammar(
446 "BlockExpr", 446 "BlockExpr",
447 "ReturnExpr", 447 "ReturnExpr",
448 "MatchExpr", 448 "MatchExpr",
449 "MatchArmList",
450 "MatchArm",
451 "MatchGuard",
452 "StructLit", 449 "StructLit",
453 "NamedFieldList",
454 "NamedField",
455 "CallExpr", 450 "CallExpr",
456 "IndexExpr", 451 "IndexExpr",
457 "MethodCallExpr", 452 "MethodCallExpr",
@@ -472,7 +467,10 @@ Grammar(
472 "PathPat": (), 467 "PathPat": (),
473 "StructPat": (), 468 "StructPat": (),
474 "FieldPatList": (), 469 "FieldPatList": (),
475 "TupleStructPat": (), 470 "TupleStructPat": (
471 options: ["Path"],
472 collections: [["args", "Pat"]],
473 ),
476 "TuplePat": (), 474 "TuplePat": (),
477 "SlicePat": (), 475 "SlicePat": (),
478 "RangePat": (), 476 "RangePat": (),