aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/completion/complete_dot.rs10
-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/hover.rs28
-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_arena/src/lib.rs2
-rw-r--r--crates/ra_arena/src/map.rs70
-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.rs770
-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.rs556
-rw-r--r--crates/ra_hir/src/ty/tests.rs103
-rw-r--r--crates/ra_hir/src/ty/tests/data/backwards.txt (renamed from crates/ra_hir/src/ty/tests/data/0006_backwards.txt)30
-rw-r--r--crates/ra_hir/src/ty/tests/data/basics.txt (renamed from crates/ra_hir/src/ty/tests/data/0001_basics.txt)16
-rw-r--r--crates/ra_hir/src/ty/tests/data/boolean_op.txt31
-rw-r--r--crates/ra_hir/src/ty/tests/data/let.txt (renamed from crates/ra_hir/src/ty/tests/data/0002_let.txt)6
-rw-r--r--crates/ra_hir/src/ty/tests/data/paths.txt (renamed from crates/ra_hir/src/ty/tests/data/0003_paths.txt)4
-rw-r--r--crates/ra_hir/src/ty/tests/data/refs_and_ptrs.txt (renamed from crates/ra_hir/src/ty/tests/data/0005_refs.txt)32
-rw-r--r--crates/ra_hir/src/ty/tests/data/self.txt (renamed from crates/ra_hir/src/ty/tests/data/0007_self.txt)4
-rw-r--r--crates/ra_hir/src/ty/tests/data/struct.txt (renamed from crates/ra_hir/src/ty/tests/data/0004_struct.txt)22
-rw-r--r--crates/ra_hir/src/type_ref.rs4
-rw-r--r--crates/ra_syntax/src/ast.rs52
-rw-r--r--crates/ra_syntax/src/ast/generated.rs35
-rw-r--r--crates/ra_syntax/src/grammar.ron14
49 files changed, 2525 insertions, 1392 deletions
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs
index 031d8b98f..54ce1b638 100644
--- a/crates/ra_analysis/src/completion/complete_dot.rs
+++ b/crates/ra_analysis/src/completion/complete_dot.rs
@@ -1,4 +1,3 @@
1use ra_syntax::ast::AstNode;
2use hir::{Ty, Def}; 1use hir::{Ty, Def};
3 2
4use crate::Cancelable; 3use crate::Cancelable;
@@ -11,11 +10,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Ca
11 _ => return Ok(()), 10 _ => return Ok(()),
12 }; 11 };
13 let infer_result = function.infer(ctx.db)?; 12 let infer_result = function.infer(ctx.db)?;
14 let receiver_ty = if let Some(ty) = infer_result.type_of_node(receiver.syntax()) { 13 let syntax_mapping = function.body_syntax_mapping(ctx.db)?;
15 ty 14 let expr = match syntax_mapping.node_expr(receiver) {
16 } else { 15 Some(expr) => expr,
17 return Ok(()); 16 None => return Ok(()),
18 }; 17 };
18 let receiver_ty = infer_result[expr].clone();
19 if !ctx.is_method_call { 19 if !ctx.is_method_call {
20 complete_fields(acc, ctx, receiver_ty)?; 20 complete_fields(acc, ctx, receiver_ty)?;
21 } 21 }
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/hover.rs b/crates/ra_analysis/src/hover.rs
index 2cf79eebf..06632df4f 100644
--- a/crates/ra_analysis/src/hover.rs
+++ b/crates/ra_analysis/src/hover.rs
@@ -3,7 +3,7 @@ use ra_editor::find_node_at_offset;
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SyntaxNode, 4 AstNode, SyntaxNode,
5 ast::{self, NameOwner}, 5 ast::{self, NameOwner},
6 algo::{find_covering_node, visit::{visitor, Visitor}}, 6 algo::{find_covering_node, find_leaf_at_offset, visit::{visitor, Visitor}},
7}; 7};
8 8
9use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; 9use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget};
@@ -26,13 +26,17 @@ pub(crate) fn hover(
26 } 26 }
27 } 27 }
28 if range.is_none() { 28 if range.is_none() {
29 let expr: ast::Expr = ctry!(find_node_at_offset(file.syntax(), position.offset)); 29 let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| {
30 leaf.ancestors()
31 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
32 });
33 let node = ctry!(node);
30 let frange = FileRange { 34 let frange = FileRange {
31 file_id: position.file_id, 35 file_id: position.file_id,
32 range: expr.syntax().range(), 36 range: node.range(),
33 }; 37 };
34 res.extend(type_of(db, frange)?); 38 res.extend(type_of(db, frange)?);
35 range = Some(expr.syntax().range()); 39 range = Some(node.range());
36 }; 40 };
37 41
38 let range = ctry!(range); 42 let range = ctry!(range);
@@ -60,7 +64,14 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Cancelable<Option
60 parent_fn 64 parent_fn
61 )?); 65 )?);
62 let infer = function.infer(db)?; 66 let infer = function.infer(db)?;
63 Ok(infer.type_of_node(node).map(|t| t.to_string())) 67 let syntax_mapping = function.body_syntax_mapping(db)?;
68 if let Some(expr) = ast::Expr::cast(node).and_then(|e| syntax_mapping.node_expr(e)) {
69 Ok(Some(infer[expr].to_string()))
70 } else if let Some(pat) = ast::Pat::cast(node).and_then(|p| syntax_mapping.node_pat(p)) {
71 Ok(Some(infer[pat].to_string()))
72 } else {
73 Ok(None)
74 }
64} 75}
65 76
66// FIXME: this should not really use navigation target. Rather, approximatelly 77// FIXME: this should not really use navigation target. Rather, approximatelly
@@ -193,6 +204,13 @@ mod tests {
193 } 204 }
194 205
195 #[test] 206 #[test]
207 fn hover_for_local_variable_pat() {
208 let (analysis, position) = single_file_with_position("fn func(fo<|>o: i32) {}");
209 let hover = analysis.hover(position).unwrap().unwrap();
210 assert_eq!(hover.info, "i32");
211 }
212
213 #[test]
196 fn test_type_of_for_function() { 214 fn test_type_of_for_function() {
197 let (analysis, range) = single_file_with_range( 215 let (analysis, range) = single_file_with_range(
198 " 216 "
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 feed44b2d..c8f846c56 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -401,7 +401,7 @@ impl Analysis {
401 } 401 }
402 /// Returns the root file of the given crate. 402 /// Returns the root file of the given crate.
403 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { 403 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
404 Ok(self.db.crate_root(crate_id)) 404 Ok(self.db.crate_graph().crate_root(crate_id))
405 } 405 }
406 /// Returns the set of possible targets to run for the current file. 406 /// Returns the set of possible targets to run for the current file.
407 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { 407 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_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index a5eeb4118..040977dc4 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -6,6 +6,8 @@ use std::{
6 ops::{Index, IndexMut}, 6 ops::{Index, IndexMut},
7}; 7};
8 8
9pub mod map;
10
9#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 11#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct RawId(u32); 12pub struct RawId(u32);
11 13
diff --git a/crates/ra_arena/src/map.rs b/crates/ra_arena/src/map.rs
new file mode 100644
index 000000000..2f09d677f
--- /dev/null
+++ b/crates/ra_arena/src/map.rs
@@ -0,0 +1,70 @@
1//! A map from arena IDs to some other type. Space requirement is O(highest ID).
2
3use std::marker::PhantomData;
4
5use super::ArenaId;
6
7/// A map from arena IDs to some other type. Space requirement is O(highest ID).
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct ArenaMap<ID, T> {
10 v: Vec<Option<T>>,
11 _ty: PhantomData<ID>,
12}
13
14impl<ID: ArenaId, T> ArenaMap<ID, T> {
15 pub fn insert(&mut self, id: ID, t: T) {
16 let idx = Self::to_idx(id);
17 if self.v.capacity() <= idx {
18 self.v.reserve(idx + 1 - self.v.capacity());
19 }
20 if self.v.len() <= idx {
21 while self.v.len() <= idx {
22 self.v.push(None);
23 }
24 }
25 self.v[idx] = Some(t);
26 }
27
28 pub fn get(&self, id: ID) -> Option<&T> {
29 self.v.get(Self::to_idx(id)).and_then(|it| it.as_ref())
30 }
31
32 pub fn values(&self) -> impl Iterator<Item = &T> {
33 self.v.iter().filter_map(|o| o.as_ref())
34 }
35
36 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> {
37 self.v.iter_mut().filter_map(|o| o.as_mut())
38 }
39
40 pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> {
41 self.v
42 .iter()
43 .enumerate()
44 .filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
45 }
46
47 fn to_idx(id: ID) -> usize {
48 u32::from(id.into_raw()) as usize
49 }
50
51 fn from_idx(idx: usize) -> ID {
52 ID::from_raw((idx as u32).into())
53 }
54}
55
56impl<ID: ArenaId, T> std::ops::Index<ID> for ArenaMap<ID, T> {
57 type Output = T;
58 fn index(&self, id: ID) -> &T {
59 self.v[Self::to_idx(id)].as_ref().unwrap()
60 }
61}
62
63impl<ID, T> Default for ArenaMap<ID, T> {
64 fn default() -> Self {
65 ArenaMap {
66 v: Vec::new(),
67 _ty: PhantomData,
68 }
69 }
70}
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..b0063cad2
--- /dev/null
+++ b/crates/ra_hir/src/expr.rs
@@ -0,0 +1,770 @@
1use std::ops::Index;
2use std::sync::Arc;
3
4use rustc_hash::FxHashMap;
5
6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
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: ArenaMap<ExprId, LocalSyntaxPtr>,
43 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
44 pat_syntax_mapping_back: ArenaMap<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 node_expr(&self, node: ast::Expr) -> Option<ExprId> {
81 self.expr_syntax_mapping
82 .get(&LocalSyntaxPtr::new(node.syntax()))
83 .cloned()
84 }
85 pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> {
86 self.pat_syntax_mapping_back.get(pat).cloned()
87 }
88 pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> {
89 self.pat_syntax_mapping.get(&ptr).cloned()
90 }
91 pub fn node_pat(&self, node: ast::Pat) -> Option<PatId> {
92 self.pat_syntax_mapping
93 .get(&LocalSyntaxPtr::new(node.syntax()))
94 .cloned()
95 }
96
97 pub fn body(&self) -> &Arc<Body> {
98 &self.body
99 }
100}
101
102#[derive(Debug, Clone, Eq, PartialEq)]
103pub enum Expr {
104 /// This is produced if syntax tree does not have a required expression piece.
105 Missing,
106 Path(Path),
107 If {
108 condition: ExprId,
109 then_branch: ExprId,
110 else_branch: Option<ExprId>,
111 },
112 Block {
113 statements: Vec<Statement>,
114 tail: Option<ExprId>,
115 },
116 Loop {
117 body: ExprId,
118 },
119 While {
120 condition: ExprId,
121 body: ExprId,
122 },
123 For {
124 iterable: ExprId,
125 pat: PatId,
126 body: ExprId,
127 },
128 Call {
129 callee: ExprId,
130 args: Vec<ExprId>,
131 },
132 MethodCall {
133 receiver: ExprId,
134 method_name: Name,
135 args: Vec<ExprId>,
136 },
137 Match {
138 expr: ExprId,
139 arms: Vec<MatchArm>,
140 },
141 Continue,
142 Break {
143 expr: Option<ExprId>,
144 },
145 Return {
146 expr: Option<ExprId>,
147 },
148 StructLit {
149 path: Option<Path>,
150 fields: Vec<StructLitField>,
151 spread: Option<ExprId>,
152 },
153 Field {
154 expr: ExprId,
155 name: Name,
156 },
157 Try {
158 expr: ExprId,
159 },
160 Cast {
161 expr: ExprId,
162 type_ref: TypeRef,
163 },
164 Ref {
165 expr: ExprId,
166 mutability: Mutability,
167 },
168 UnaryOp {
169 expr: ExprId,
170 op: Option<UnaryOp>,
171 },
172 BinaryOp {
173 lhs: ExprId,
174 rhs: ExprId,
175 op: Option<BinaryOp>,
176 },
177 Lambda {
178 args: Vec<PatId>,
179 arg_types: Vec<Option<TypeRef>>,
180 body: ExprId,
181 },
182}
183
184pub use ra_syntax::ast::PrefixOp as UnaryOp;
185pub use ra_syntax::ast::BinOp as BinaryOp;
186
187#[derive(Debug, Clone, Eq, PartialEq)]
188pub struct MatchArm {
189 pub pats: Vec<PatId>,
190 // guard: Option<ExprId>, // TODO
191 pub expr: ExprId,
192}
193
194#[derive(Debug, Clone, Eq, PartialEq)]
195pub struct StructLitField {
196 pub name: Name,
197 pub expr: ExprId,
198}
199
200#[derive(Debug, Clone, Eq, PartialEq)]
201pub enum Statement {
202 Let {
203 pat: PatId,
204 type_ref: Option<TypeRef>,
205 initializer: Option<ExprId>,
206 },
207 Expr(ExprId),
208}
209
210impl Expr {
211 pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
212 match self {
213 Expr::Missing => {}
214 Expr::Path(_) => {}
215 Expr::If {
216 condition,
217 then_branch,
218 else_branch,
219 } => {
220 f(*condition);
221 f(*then_branch);
222 if let Some(else_branch) = else_branch {
223 f(*else_branch);
224 }
225 }
226 Expr::Block { statements, tail } => {
227 for stmt in statements {
228 match stmt {
229 Statement::Let { initializer, .. } => {
230 if let Some(expr) = initializer {
231 f(*expr);
232 }
233 }
234 Statement::Expr(e) => f(*e),
235 }
236 }
237 if let Some(expr) = tail {
238 f(*expr);
239 }
240 }
241 Expr::Loop { body } => f(*body),
242 Expr::While { condition, body } => {
243 f(*condition);
244 f(*body);
245 }
246 Expr::For { iterable, body, .. } => {
247 f(*iterable);
248 f(*body);
249 }
250 Expr::Call { callee, args } => {
251 f(*callee);
252 for arg in args {
253 f(*arg);
254 }
255 }
256 Expr::MethodCall { receiver, args, .. } => {
257 f(*receiver);
258 for arg in args {
259 f(*arg);
260 }
261 }
262 Expr::Match { expr, arms } => {
263 f(*expr);
264 for arm in arms {
265 f(arm.expr);
266 }
267 }
268 Expr::Continue => {}
269 Expr::Break { expr } | Expr::Return { expr } => {
270 if let Some(expr) = expr {
271 f(*expr);
272 }
273 }
274 Expr::StructLit { fields, spread, .. } => {
275 for field in fields {
276 f(field.expr);
277 }
278 if let Some(expr) = spread {
279 f(*expr);
280 }
281 }
282 Expr::Lambda { body, .. } => {
283 f(*body);
284 }
285 Expr::BinaryOp { lhs, rhs, .. } => {
286 f(*lhs);
287 f(*rhs);
288 }
289 Expr::Field { expr, .. }
290 | Expr::Try { expr }
291 | Expr::Cast { expr, .. }
292 | Expr::Ref { expr, .. }
293 | Expr::UnaryOp { expr, .. } => {
294 f(*expr);
295 }
296 }
297 }
298}
299
300#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
301pub struct PatId(RawId);
302impl_arena_id!(PatId);
303
304#[derive(Debug, Clone, Eq, PartialEq)]
305pub enum Pat {
306 Missing,
307 Bind {
308 name: Name,
309 },
310 TupleStruct {
311 path: Option<Path>,
312 args: Vec<PatId>,
313 },
314}
315
316impl Pat {
317 pub fn walk_child_pats(&self, f: impl FnMut(PatId)) {
318 match self {
319 Pat::Missing | Pat::Bind { .. } => {}
320 Pat::TupleStruct { args, .. } => {
321 args.iter().map(|pat| *pat).for_each(f);
322 }
323 }
324 }
325}
326
327// Queries
328
329pub(crate) fn body_hir(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<Body>> {
330 Ok(Arc::clone(&body_syntax_mapping(db, def_id)?.body))
331}
332
333struct ExprCollector {
334 exprs: Arena<ExprId, Expr>,
335 pats: Arena<PatId, Pat>,
336 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>,
337 expr_syntax_mapping_back: ArenaMap<ExprId, LocalSyntaxPtr>,
338 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
339 pat_syntax_mapping_back: ArenaMap<PatId, LocalSyntaxPtr>,
340}
341
342impl ExprCollector {
343 fn new() -> Self {
344 ExprCollector {
345 exprs: Arena::default(),
346 pats: Arena::default(),
347 expr_syntax_mapping: FxHashMap::default(),
348 expr_syntax_mapping_back: ArenaMap::default(),
349 pat_syntax_mapping: FxHashMap::default(),
350 pat_syntax_mapping_back: ArenaMap::default(),
351 }
352 }
353
354 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId {
355 let id = self.exprs.alloc(expr);
356 self.expr_syntax_mapping.insert(syntax_ptr, id);
357 self.expr_syntax_mapping_back.insert(id, syntax_ptr);
358 id
359 }
360
361 fn alloc_pat(&mut self, pat: Pat, syntax_ptr: LocalSyntaxPtr) -> PatId {
362 let id = self.pats.alloc(pat);
363 self.pat_syntax_mapping.insert(syntax_ptr, id);
364 self.pat_syntax_mapping_back.insert(id, syntax_ptr);
365 id
366 }
367
368 fn empty_block(&mut self) -> ExprId {
369 let block = Expr::Block {
370 statements: Vec::new(),
371 tail: None,
372 };
373 self.exprs.alloc(block)
374 }
375
376 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
377 let syntax_ptr = LocalSyntaxPtr::new(expr.syntax());
378 match expr {
379 ast::Expr::IfExpr(e) => {
380 if let Some(pat) = e.condition().and_then(|c| c.pat()) {
381 // if let -- desugar to match
382 let pat = self.collect_pat(pat);
383 let match_expr =
384 self.collect_expr_opt(e.condition().expect("checked above").expr());
385 let then_branch = self.collect_block_opt(e.then_branch());
386 let else_branch = e
387 .else_branch()
388 .map(|e| self.collect_block(e))
389 .unwrap_or_else(|| self.empty_block());
390 let placeholder_pat = self.pats.alloc(Pat::Missing);
391 let arms = vec![
392 MatchArm {
393 pats: vec![pat],
394 expr: then_branch,
395 },
396 MatchArm {
397 pats: vec![placeholder_pat],
398 expr: else_branch,
399 },
400 ];
401 self.alloc_expr(
402 Expr::Match {
403 expr: match_expr,
404 arms,
405 },
406 syntax_ptr,
407 )
408 } else {
409 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
410 let then_branch = self.collect_block_opt(e.then_branch());
411 let else_branch = e.else_branch().map(|e| self.collect_block(e));
412 self.alloc_expr(
413 Expr::If {
414 condition,
415 then_branch,
416 else_branch,
417 },
418 syntax_ptr,
419 )
420 }
421 }
422 ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
423 ast::Expr::LoopExpr(e) => {
424 let body = self.collect_block_opt(e.loop_body());
425 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
426 }
427 ast::Expr::WhileExpr(e) => {
428 let condition = if let Some(condition) = e.condition() {
429 if condition.pat().is_none() {
430 self.collect_expr_opt(condition.expr())
431 } else {
432 // TODO handle while let
433 return self.alloc_expr(Expr::Missing, syntax_ptr);
434 }
435 } else {
436 self.exprs.alloc(Expr::Missing)
437 };
438 let body = self.collect_block_opt(e.loop_body());
439 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
440 }
441 ast::Expr::ForExpr(e) => {
442 let iterable = self.collect_expr_opt(e.iterable());
443 let pat = self.collect_pat_opt(e.pat());
444 let body = self.collect_block_opt(e.loop_body());
445 self.alloc_expr(
446 Expr::For {
447 iterable,
448 pat,
449 body,
450 },
451 syntax_ptr,
452 )
453 }
454 ast::Expr::CallExpr(e) => {
455 let callee = self.collect_expr_opt(e.expr());
456 let args = if let Some(arg_list) = e.arg_list() {
457 arg_list.args().map(|e| self.collect_expr(e)).collect()
458 } else {
459 Vec::new()
460 };
461 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
462 }
463 ast::Expr::MethodCallExpr(e) => {
464 let receiver = self.collect_expr_opt(e.expr());
465 let args = if let Some(arg_list) = e.arg_list() {
466 arg_list.args().map(|e| self.collect_expr(e)).collect()
467 } else {
468 Vec::new()
469 };
470 let method_name = e
471 .name_ref()
472 .map(|nr| nr.as_name())
473 .unwrap_or_else(Name::missing);
474 self.alloc_expr(
475 Expr::MethodCall {
476 receiver,
477 method_name,
478 args,
479 },
480 syntax_ptr,
481 )
482 }
483 ast::Expr::MatchExpr(e) => {
484 let expr = self.collect_expr_opt(e.expr());
485 let arms = if let Some(match_arm_list) = e.match_arm_list() {
486 match_arm_list
487 .arms()
488 .map(|arm| MatchArm {
489 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
490 expr: self.collect_expr_opt(arm.expr()),
491 })
492 .collect()
493 } else {
494 Vec::new()
495 };
496 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
497 }
498 ast::Expr::PathExpr(e) => {
499 let path = e
500 .path()
501 .and_then(Path::from_ast)
502 .map(Expr::Path)
503 .unwrap_or(Expr::Missing);
504 self.alloc_expr(path, syntax_ptr)
505 }
506 ast::Expr::ContinueExpr(_e) => {
507 // TODO: labels
508 self.alloc_expr(Expr::Continue, syntax_ptr)
509 }
510 ast::Expr::BreakExpr(e) => {
511 let expr = e.expr().map(|e| self.collect_expr(e));
512 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
513 }
514 ast::Expr::ParenExpr(e) => {
515 let inner = self.collect_expr_opt(e.expr());
516 // make the paren expr point to the inner expression as well
517 self.expr_syntax_mapping.insert(syntax_ptr, inner);
518 inner
519 }
520 ast::Expr::ReturnExpr(e) => {
521 let expr = e.expr().map(|e| self.collect_expr(e));
522 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
523 }
524 ast::Expr::StructLit(e) => {
525 let path = e.path().and_then(Path::from_ast);
526 let fields = if let Some(nfl) = e.named_field_list() {
527 nfl.fields()
528 .map(|field| StructLitField {
529 name: field
530 .name_ref()
531 .map(|nr| nr.as_name())
532 .unwrap_or_else(Name::missing),
533 expr: if let Some(e) = field.expr() {
534 self.collect_expr(e)
535 } else if let Some(nr) = field.name_ref() {
536 // field shorthand
537 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(nr)));
538 self.expr_syntax_mapping
539 .insert(LocalSyntaxPtr::new(nr.syntax()), id);
540 self.expr_syntax_mapping_back
541 .insert(id, LocalSyntaxPtr::new(nr.syntax()));
542 id
543 } else {
544 self.exprs.alloc(Expr::Missing)
545 },
546 })
547 .collect()
548 } else {
549 Vec::new()
550 };
551 let spread = e.spread().map(|s| self.collect_expr(s));
552 self.alloc_expr(
553 Expr::StructLit {
554 path,
555 fields,
556 spread,
557 },
558 syntax_ptr,
559 )
560 }
561 ast::Expr::FieldExpr(e) => {
562 let expr = self.collect_expr_opt(e.expr());
563 let name = e
564 .name_ref()
565 .map(|nr| nr.as_name())
566 .unwrap_or_else(Name::missing);
567 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
568 }
569 ast::Expr::TryExpr(e) => {
570 let expr = self.collect_expr_opt(e.expr());
571 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
572 }
573 ast::Expr::CastExpr(e) => {
574 let expr = self.collect_expr_opt(e.expr());
575 let type_ref = TypeRef::from_ast_opt(e.type_ref());
576 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
577 }
578 ast::Expr::RefExpr(e) => {
579 let expr = self.collect_expr_opt(e.expr());
580 let mutability = Mutability::from_mutable(e.is_mut());
581 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
582 }
583 ast::Expr::PrefixExpr(e) => {
584 let expr = self.collect_expr_opt(e.expr());
585 let op = e.op();
586 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
587 }
588 ast::Expr::LambdaExpr(e) => {
589 let mut args = Vec::new();
590 let mut arg_types = Vec::new();
591 if let Some(pl) = e.param_list() {
592 for param in pl.params() {
593 let pat = self.collect_pat_opt(param.pat());
594 let type_ref = param.type_ref().map(TypeRef::from_ast);
595 args.push(pat);
596 arg_types.push(type_ref);
597 }
598 }
599 let body = self.collect_expr_opt(e.body());
600 self.alloc_expr(
601 Expr::Lambda {
602 args,
603 arg_types,
604 body,
605 },
606 syntax_ptr,
607 )
608 }
609 ast::Expr::BinExpr(e) => {
610 let lhs = self.collect_expr_opt(e.lhs());
611 let rhs = self.collect_expr_opt(e.rhs());
612 let op = e.op();
613 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
614 }
615
616 // TODO implement HIR for these:
617 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
618 ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
619 ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
620 ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
621 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
622 ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
623 }
624 }
625
626 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
627 if let Some(expr) = expr {
628 self.collect_expr(expr)
629 } else {
630 self.exprs.alloc(Expr::Missing)
631 }
632 }
633
634 fn collect_block(&mut self, block: ast::Block) -> ExprId {
635 let statements = block
636 .statements()
637 .map(|s| match s {
638 ast::Stmt::LetStmt(stmt) => {
639 let pat = self.collect_pat_opt(stmt.pat());
640 let type_ref = stmt.type_ref().map(TypeRef::from_ast);
641 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
642 Statement::Let {
643 pat,
644 type_ref,
645 initializer,
646 }
647 }
648 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
649 })
650 .collect();
651 let tail = block.expr().map(|e| self.collect_expr(e));
652 self.alloc_expr(
653 Expr::Block { statements, tail },
654 LocalSyntaxPtr::new(block.syntax()),
655 )
656 }
657
658 fn collect_block_opt(&mut self, block: Option<ast::Block>) -> ExprId {
659 if let Some(block) = block {
660 self.collect_block(block)
661 } else {
662 self.exprs.alloc(Expr::Missing)
663 }
664 }
665
666 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
667 let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
668 match pat {
669 ast::Pat::BindPat(bp) => {
670 let name = bp
671 .name()
672 .map(|nr| nr.as_name())
673 .unwrap_or_else(Name::missing);
674 self.alloc_pat(Pat::Bind { name }, syntax_ptr)
675 }
676 ast::Pat::TupleStructPat(p) => {
677 let path = p.path().and_then(Path::from_ast);
678 let args = p.args().map(|p| self.collect_pat(p)).collect();
679 self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr)
680 }
681 _ => {
682 // TODO
683 self.alloc_pat(Pat::Missing, syntax_ptr)
684 }
685 }
686 }
687
688 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
689 if let Some(pat) = pat {
690 self.collect_pat(pat)
691 } else {
692 self.pats.alloc(Pat::Missing)
693 }
694 }
695
696 fn into_body_syntax_mapping(self, args: Vec<PatId>, body_expr: ExprId) -> BodySyntaxMapping {
697 let body = Body {
698 exprs: self.exprs,
699 pats: self.pats,
700 args,
701 body_expr,
702 };
703 BodySyntaxMapping {
704 body: Arc::new(body),
705 expr_syntax_mapping: self.expr_syntax_mapping,
706 expr_syntax_mapping_back: self.expr_syntax_mapping_back,
707 pat_syntax_mapping: self.pat_syntax_mapping,
708 pat_syntax_mapping_back: self.pat_syntax_mapping_back,
709 }
710 }
711}
712
713pub(crate) fn collect_fn_body_syntax(node: ast::FnDef) -> BodySyntaxMapping {
714 let mut collector = ExprCollector::new();
715
716 let args = if let Some(param_list) = node.param_list() {
717 let mut args = Vec::new();
718
719 if let Some(self_param) = param_list.self_param() {
720 let self_param = LocalSyntaxPtr::new(
721 self_param
722 .self_kw()
723 .expect("self param without self keyword")
724 .syntax(),
725 );
726 let arg = collector.alloc_pat(
727 Pat::Bind {
728 name: Name::self_param(),
729 },
730 self_param,
731 );
732 args.push(arg);
733 }
734
735 for param in param_list.params() {
736 let pat = if let Some(pat) = param.pat() {
737 pat
738 } else {
739 continue;
740 };
741 args.push(collector.collect_pat(pat));
742 }
743 args
744 } else {
745 Vec::new()
746 };
747
748 let body = collector.collect_block_opt(node.body());
749 collector.into_body_syntax_mapping(args, body)
750}
751
752pub(crate) fn body_syntax_mapping(
753 db: &impl HirDatabase,
754 def_id: DefId,
755) -> Cancelable<Arc<BodySyntaxMapping>> {
756 let def = def_id.resolve(db)?;
757
758 let body_syntax_mapping = match def {
759 Def::Function(f) => {
760 let node = f.syntax(db);
761 let node = node.borrowed();
762
763 collect_fn_body_syntax(node)
764 }
765 // TODO: consts, etc.
766 _ => panic!("Trying to get body for item type without body"),
767 };
768
769 Ok(Arc::new(body_syntax_mapping))
770}
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 e33762e0d..d57990cd2 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -17,24 +17,23 @@ mod primitive;
17#[cfg(test)] 17#[cfg(test)]
18mod tests; 18mod tests;
19 19
20use std::ops::Index;
20use std::sync::Arc; 21use std::sync::Arc;
21use std::{fmt, mem}; 22use std::{fmt, mem};
22 23
23use log; 24use log;
24use rustc_hash::FxHashMap;
25use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; 25use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError};
26use ra_arena::map::ArenaMap;
26 27
27use ra_db::{LocalSyntaxPtr, Cancelable}; 28use ra_db::Cancelable;
28use ra_syntax::{
29 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp},
30 SyntaxNodeRef
31};
32 29
33use crate::{ 30use crate::{
34 Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock, 31 Def, DefId, Module, Function, Struct, Enum, Path, Name, ImplBlock,
32 FnSignature, FnScopes,
35 db::HirDatabase, 33 db::HirDatabase,
36 type_ref::{TypeRef, Mutability}, 34 type_ref::{TypeRef, Mutability},
37 name::KnownName, 35 name::KnownName,
36 expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement},
38}; 37};
39 38
40/// The ID of a type variable. 39/// The ID of a type variable.
@@ -81,9 +80,10 @@ impl UnifyValue for TypeVarValue {
81 match (value1, value2) { 80 match (value1, value2) {
82 // We should never equate two type variables, both of which have 81 // We should never equate two type variables, both of which have
83 // known types. Instead, we recursively equate those types. 82 // known types. Instead, we recursively equate those types.
84 (TypeVarValue::Known(..), TypeVarValue::Known(..)) => { 83 (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!(
85 panic!("equating two type variables, both of which have known types") 84 "equating two type variables, both of which have known types: {:?} and {:?}",
86 } 85 t1, t2
86 ),
87 87
88 // If one side is known, prefer that one. 88 // If one side is known, prefer that one.
89 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), 89 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()),
@@ -305,7 +305,7 @@ impl Ty {
305 return Ok(Ty::Uint(uint_ty)); 305 return Ok(Ty::Uint(uint_ty));
306 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { 306 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
307 return Ok(Ty::Float(float_ty)); 307 return Ok(Ty::Float(float_ty));
308 } else if name.as_known_name() == Some(KnownName::Self_) { 308 } 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())); 309 return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
310 } 310 }
311 } 311 }
@@ -320,26 +320,6 @@ impl Ty {
320 Ok(ty) 320 Ok(ty)
321 } 321 }
322 322
323 // TODO: These should not be necessary long-term, since everything will work on HIR
324 pub(crate) fn from_ast_opt(
325 db: &impl HirDatabase,
326 module: &Module,
327 impl_block: Option<&ImplBlock>,
328 node: Option<ast::TypeRef>,
329 ) -> Cancelable<Self> {
330 node.map(|n| Ty::from_ast(db, module, impl_block, n))
331 .unwrap_or(Ok(Ty::Unknown))
332 }
333
334 pub(crate) fn from_ast(
335 db: &impl HirDatabase,
336 module: &Module,
337 impl_block: Option<&ImplBlock>,
338 node: ast::TypeRef,
339 ) -> Cancelable<Self> {
340 Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node))
341 }
342
343 pub fn unit() -> Self { 323 pub fn unit() -> Self {
344 Ty::Tuple(Arc::new([])) 324 Ty::Tuple(Arc::new([]))
345 } 325 }
@@ -416,26 +396,18 @@ impl fmt::Display for Ty {
416// Functions returning declared types for items 396// Functions returning declared types for items
417 397
418/// Compute the declared type of a function. This should not need to look at the 398/// Compute the declared type of a function. This should not need to look at the
419/// function body (but currently uses the function AST, so does anyway - TODO). 399/// function body.
420fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { 400fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
421 let syntax = f.syntax(db); 401 let signature = f.signature(db);
422 let module = f.module(db)?; 402 let module = f.module(db)?;
423 let impl_block = f.impl_block(db)?; 403 let impl_block = f.impl_block(db)?;
424 let node = syntax.borrowed();
425 // TODO we ignore type parameters for now 404 // TODO we ignore type parameters for now
426 let input = node 405 let input = signature
427 .param_list() 406 .args()
428 .map(|pl| { 407 .iter()
429 pl.params() 408 .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), tr))
430 .map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref())) 409 .collect::<Cancelable<Vec<_>>>()?;
431 .collect() 410 let output = Ty::from_hir(db, &module, impl_block.as_ref(), signature.ret_type())?;
432 })
433 .unwrap_or_else(|| Ok(Vec::new()))?;
434 let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
435 Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)?
436 } else {
437 Ty::unit()
438 };
439 let sig = FnSig { input, output }; 411 let sig = FnSig { input, output };
440 Ok(Ty::FnPtr(Arc::new(sig))) 412 Ok(Ty::FnPtr(Arc::new(sig)))
441} 413}
@@ -498,16 +470,23 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
498/// The result of type inference: A mapping from expressions and patterns to types. 470/// The result of type inference: A mapping from expressions and patterns to types.
499#[derive(Clone, PartialEq, Eq, Debug)] 471#[derive(Clone, PartialEq, Eq, Debug)]
500pub struct InferenceResult { 472pub struct InferenceResult {
501 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 473 type_of_expr: ArenaMap<ExprId, Ty>,
474 type_of_pat: ArenaMap<PatId, Ty>,
502} 475}
503 476
504impl InferenceResult { 477impl Index<ExprId> for InferenceResult {
505 /// Returns the type of the given syntax node, if it was inferred. Will 478 type Output = Ty;
506 /// return `None` for syntax nodes not in the inferred function or not 479
507 /// pointing to an expression/pattern, `Some(Ty::Unknown)` for 480 fn index(&self, expr: ExprId) -> &Ty {
508 /// expressions/patterns that could not be inferred. 481 self.type_of_expr.get(expr).unwrap_or(&Ty::Unknown)
509 pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> { 482 }
510 self.type_of.get(&LocalSyntaxPtr::new(node)).cloned() 483}
484
485impl Index<PatId> for InferenceResult {
486 type Output = Ty;
487
488 fn index(&self, pat: PatId) -> &Ty {
489 self.type_of_pat.get(pat).unwrap_or(&Ty::Unknown)
511 } 490 }
512} 491}
513 492
@@ -515,30 +494,46 @@ impl InferenceResult {
515#[derive(Clone, Debug)] 494#[derive(Clone, Debug)]
516struct InferenceContext<'a, D: HirDatabase> { 495struct InferenceContext<'a, D: HirDatabase> {
517 db: &'a D, 496 db: &'a D,
497 body: Arc<Body>,
518 scopes: Arc<FnScopes>, 498 scopes: Arc<FnScopes>,
519 /// The self param for the current method, if it exists.
520 self_param: Option<LocalSyntaxPtr>,
521 module: Module, 499 module: Module,
522 impl_block: Option<ImplBlock>, 500 impl_block: Option<ImplBlock>,
523 var_unification_table: InPlaceUnificationTable<TypeVarId>, 501 var_unification_table: InPlaceUnificationTable<TypeVarId>,
524 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 502 type_of_expr: ArenaMap<ExprId, Ty>,
503 type_of_pat: ArenaMap<PatId, Ty>,
525 /// The return type of the function being inferred. 504 /// The return type of the function being inferred.
526 return_ty: Ty, 505 return_ty: Ty,
527} 506}
528 507
508// helper function that determines whether a binary operator
509// always returns a boolean
510fn is_boolean_operator(op: BinaryOp) -> bool {
511 match op {
512 BinaryOp::BooleanOr
513 | BinaryOp::BooleanAnd
514 | BinaryOp::EqualityTest
515 | BinaryOp::LesserEqualTest
516 | BinaryOp::GreaterEqualTest
517 | BinaryOp::LesserTest
518 | BinaryOp::GreaterTest => true,
519 }
520}
521
529impl<'a, D: HirDatabase> InferenceContext<'a, D> { 522impl<'a, D: HirDatabase> InferenceContext<'a, D> {
530 fn new( 523 fn new(
531 db: &'a D, 524 db: &'a D,
525 body: Arc<Body>,
532 scopes: Arc<FnScopes>, 526 scopes: Arc<FnScopes>,
533 module: Module, 527 module: Module,
534 impl_block: Option<ImplBlock>, 528 impl_block: Option<ImplBlock>,
535 ) -> Self { 529 ) -> Self {
536 InferenceContext { 530 InferenceContext {
537 type_of: FxHashMap::default(), 531 type_of_expr: ArenaMap::default(),
532 type_of_pat: ArenaMap::default(),
538 var_unification_table: InPlaceUnificationTable::new(), 533 var_unification_table: InPlaceUnificationTable::new(),
539 self_param: None, // set during parameter typing
540 return_ty: Ty::Unknown, // set in collect_fn_signature 534 return_ty: Ty::Unknown, // set in collect_fn_signature
541 db, 535 db,
536 body,
542 scopes, 537 scopes,
543 module, 538 module,
544 impl_block, 539 impl_block,
@@ -546,24 +541,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
546 } 541 }
547 542
548 fn resolve_all(mut self) -> InferenceResult { 543 fn resolve_all(mut self) -> InferenceResult {
549 let mut types = mem::replace(&mut self.type_of, FxHashMap::default()); 544 let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default());
550 for ty in types.values_mut() { 545 for ty in expr_types.values_mut() {
546 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
547 *ty = resolved;
548 }
549 let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default());
550 for ty in pat_types.values_mut() {
551 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); 551 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
552 *ty = resolved; 552 *ty = resolved;
553 } 553 }
554 InferenceResult { type_of: types } 554 InferenceResult {
555 type_of_expr: expr_types,
556 type_of_pat: pat_types,
557 }
555 } 558 }
556 559
557 fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) { 560 fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
558 self.type_of.insert(LocalSyntaxPtr::new(node), ty); 561 self.type_of_expr.insert(expr, ty);
559 } 562 }
560 563
561 fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> { 564 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
562 Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) 565 self.type_of_pat.insert(pat, ty);
563 } 566 }
564 567
565 fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> { 568 fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> {
566 Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref) 569 Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)
567 } 570 }
568 571
569 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 572 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
@@ -658,23 +661,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
658 }) 661 })
659 } 662 }
660 663
661 fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> { 664 fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Cancelable<Option<Ty>> {
662 let ast_path = ctry!(expr.path()); 665 if path.is_ident() || path.is_self() {
663 let path = ctry!(Path::from_ast(ast_path));
664 if path.is_ident() {
665 // resolve locally 666 // resolve locally
666 let name = ctry!(ast_path.segment().and_then(|s| s.name_ref())); 667 let name = path.as_ident().cloned().unwrap_or_else(Name::self_param);
667 if let Some(scope_entry) = self.scopes.resolve_local_name(name) { 668 if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) {
668 let ty = ctry!(self.type_of.get(&scope_entry.ptr())); 669 let ty = ctry!(self.type_of_pat.get(scope_entry.pat()));
669 let ty = self.resolve_ty_as_possible(ty.clone()); 670 let ty = self.resolve_ty_as_possible(ty.clone());
670 return Ok(Some(ty)); 671 return Ok(Some(ty));
671 }; 672 };
672 } else if path.is_self() {
673 // resolve `self` param
674 let self_param = ctry!(self.self_param);
675 let ty = ctry!(self.type_of.get(&self_param));
676 let ty = self.resolve_ty_as_possible(ty.clone());
677 return Ok(Some(ty));
678 }; 673 };
679 674
680 // resolve in module 675 // resolve in module
@@ -684,8 +679,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
684 Ok(Some(ty)) 679 Ok(Some(ty))
685 } 680 }
686 681
687 fn resolve_variant(&self, path: Option<ast::Path>) -> Cancelable<(Ty, Option<DefId>)> { 682 fn resolve_variant(&self, path: Option<&Path>) -> Cancelable<(Ty, Option<DefId>)> {
688 let path = if let Some(path) = path.and_then(Path::from_ast) { 683 let path = if let Some(path) = path {
689 path 684 path
690 } else { 685 } else {
691 return Ok((Ty::Unknown, None)); 686 return Ok((Ty::Unknown, None));
@@ -704,74 +699,51 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
704 }) 699 })
705 } 700 }
706 701
707 fn infer_expr_opt( 702 fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Cancelable<Ty> {
708 &mut self, 703 let body = Arc::clone(&self.body); // avoid borrow checker problem
709 expr: Option<ast::Expr>, 704 let ty = match &body[expr] {
710 expected: &Expectation, 705 Expr::Missing => Ty::Unknown,
711 ) -> Cancelable<Ty> { 706 Expr::If {
712 if let Some(e) = expr { 707 condition,
713 self.infer_expr(e, expected) 708 then_branch,
714 } else { 709 else_branch,
715 Ok(Ty::Unknown) 710 } => {
716 } 711 // if let is desugared to match, so this is always simple if
717 } 712 self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?;
718 713 let then_ty = self.infer_expr(*then_branch, expected)?;
719 fn infer_expr(&mut self, expr: ast::Expr, expected: &Expectation) -> Cancelable<Ty> { 714 if let Some(else_branch) = else_branch {
720 let ty = match expr { 715 self.infer_expr(*else_branch, expected)?;
721 ast::Expr::IfExpr(e) => {
722 if let Some(condition) = e.condition() {
723 let expected = if condition.pat().is_none() {
724 Expectation::has_type(Ty::Bool)
725 } else {
726 Expectation::none()
727 };
728 self.infer_expr_opt(condition.expr(), &expected)?;
729 // TODO write type for pat
730 };
731 let if_ty = self.infer_block_opt(e.then_branch(), expected)?;
732 if let Some(else_branch) = e.else_branch() {
733 self.infer_block(else_branch, expected)?;
734 } else { 716 } else {
735 // no else branch -> unit 717 // no else branch -> unit
736 self.unify(&expected.ty, &Ty::unit()); // actually coerce 718 self.unify(&expected.ty, &Ty::unit()); // actually coerce
737 } 719 }
738 if_ty 720 then_ty
739 } 721 }
740 ast::Expr::BlockExpr(e) => self.infer_block_opt(e.block(), expected)?, 722 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected)?,
741 ast::Expr::LoopExpr(e) => { 723 Expr::Loop { body } => {
742 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?; 724 self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?;
743 // TODO never, or the type of the break param 725 // TODO handle break with value
744 Ty::Unknown 726 Ty::Never
745 } 727 }
746 ast::Expr::WhileExpr(e) => { 728 Expr::While { condition, body } => {
747 if let Some(condition) = e.condition() { 729 // while let is desugared to a match loop, so this is always simple while
748 let expected = if condition.pat().is_none() { 730 self.infer_expr(*condition, &Expectation::has_type(Ty::Bool))?;
749 Expectation::has_type(Ty::Bool) 731 self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?;
750 } else {
751 Expectation::none()
752 };
753 self.infer_expr_opt(condition.expr(), &expected)?;
754 // TODO write type for pat
755 };
756 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?;
757 // TODO always unit?
758 Ty::unit() 732 Ty::unit()
759 } 733 }
760 ast::Expr::ForExpr(e) => { 734 Expr::For { iterable, body, .. } => {
761 let _iterable_ty = self.infer_expr_opt(e.iterable(), &Expectation::none()); 735 let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
762 if let Some(_pat) = e.pat() { 736 // TODO write type for pat
763 // TODO write type for pat 737 self.infer_expr(*body, &Expectation::has_type(Ty::unit()))?;
764 }
765 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?;
766 // TODO always unit?
767 Ty::unit() 738 Ty::unit()
768 } 739 }
769 ast::Expr::LambdaExpr(e) => { 740 Expr::Lambda { body, .. } => {
770 let _body_ty = self.infer_expr_opt(e.body(), &Expectation::none())?; 741 // TODO write types for args, infer lambda type etc.
742 let _body_ty = self.infer_expr(*body, &Expectation::none())?;
771 Ty::Unknown 743 Ty::Unknown
772 } 744 }
773 ast::Expr::CallExpr(e) => { 745 Expr::Call { callee, args } => {
774 let callee_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 746 let callee_ty = self.infer_expr(*callee, &Expectation::none())?;
775 let (arg_tys, ret_ty) = match &callee_ty { 747 let (arg_tys, ret_ty) = match &callee_ty {
776 Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()), 748 Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()),
777 _ => { 749 _ => {
@@ -780,120 +752,102 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
780 (&[][..], Ty::Unknown) 752 (&[][..], Ty::Unknown)
781 } 753 }
782 }; 754 };
783 if let Some(arg_list) = e.arg_list() { 755 for (i, arg) in args.iter().enumerate() {
784 for (i, arg) in arg_list.args().enumerate() { 756 self.infer_expr(
785 self.infer_expr( 757 *arg,
786 arg, 758 &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)),
787 &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)), 759 )?;
788 )?;
789 }
790 } 760 }
791 ret_ty 761 ret_ty
792 } 762 }
793 ast::Expr::MethodCallExpr(e) => { 763 Expr::MethodCall { receiver, args, .. } => {
794 let _receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 764 let _receiver_ty = self.infer_expr(*receiver, &Expectation::none())?;
795 if let Some(arg_list) = e.arg_list() { 765 // TODO resolve method...
796 for arg in arg_list.args() { 766 for (_i, arg) in args.iter().enumerate() {
797 // TODO unify / expect argument type 767 // TODO unify / expect argument type
798 self.infer_expr(arg, &Expectation::none())?; 768 self.infer_expr(*arg, &Expectation::none())?;
799 }
800 } 769 }
801 Ty::Unknown 770 Ty::Unknown
802 } 771 }
803 ast::Expr::MatchExpr(e) => { 772 Expr::Match { expr, arms } => {
804 let _ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 773 let _ty = self.infer_expr(*expr, &Expectation::none())?;
805 if let Some(match_arm_list) = e.match_arm_list() { 774 for arm in arms {
806 for arm in match_arm_list.arms() { 775 // TODO type the bindings in pats
807 // TODO type the bindings in pat 776 // TODO type the guard
808 // TODO type the guard 777 let _ty = self.infer_expr(arm.expr, &Expectation::none())?;
809 let _ty = self.infer_expr_opt(arm.expr(), &Expectation::none())?;
810 }
811 // TODO unify all the match arm types
812 Ty::Unknown
813 } else {
814 Ty::Unknown
815 } 778 }
816 } 779 // TODO unify all the match arm types
817 ast::Expr::TupleExpr(_e) => Ty::Unknown,
818 ast::Expr::ArrayExpr(_e) => Ty::Unknown,
819 ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown),
820 ast::Expr::ContinueExpr(_e) => Ty::Never,
821 ast::Expr::BreakExpr(_e) => Ty::Never,
822 ast::Expr::ParenExpr(e) => self.infer_expr_opt(e.expr(), expected)?,
823 ast::Expr::Label(_e) => Ty::Unknown,
824 ast::Expr::ReturnExpr(e) => {
825 // TODO expect return type of function
826 self.infer_expr_opt(e.expr(), &Expectation::none())?;
827 Ty::Never
828 }
829 ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
830 // Can this even occur outside of a match expression?
831 Ty::Unknown 780 Ty::Unknown
832 } 781 }
833 ast::Expr::StructLit(e) => { 782 Expr::Path(p) => self.infer_path_expr(expr, p)?.unwrap_or(Ty::Unknown),
834 let (ty, def_id) = self.resolve_variant(e.path())?; 783 Expr::Continue => Ty::Never,
835 if let Some(nfl) = e.named_field_list() { 784 Expr::Break { expr } => {
836 for field in nfl.fields() { 785 if let Some(expr) = expr {
837 let field_ty = if let (Some(def_id), Some(nr)) = (def_id, field.name_ref()) 786 // TODO handle break with value
838 { 787 self.infer_expr(*expr, &Expectation::none())?;
839 self.db.type_for_field(def_id, nr.as_name())?
840 } else {
841 Ty::Unknown
842 };
843 self.infer_expr_opt(field.expr(), &Expectation::has_type(field_ty))?;
844 }
845 } 788 }
846 ty 789 Ty::Never
847 } 790 }
848 ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => { 791 Expr::Return { expr } => {
849 // Can this even occur outside of a struct literal? 792 if let Some(expr) = expr {
850 Ty::Unknown 793 self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()))?;
794 }
795 Ty::Never
851 } 796 }
852 ast::Expr::IndexExpr(_e) => Ty::Unknown, 797 Expr::StructLit {
853 ast::Expr::FieldExpr(e) => { 798 path,
854 let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 799 fields,
855 if let Some(nr) = e.name_ref() { 800 spread,
856 let ty = match receiver_ty { 801 } => {
857 Ty::Tuple(fields) => { 802 let (ty, def_id) = self.resolve_variant(path.as_ref())?;
858 let i = nr.text().parse::<usize>().ok(); 803 for field in fields {
859 i.and_then(|i| fields.get(i).cloned()) 804 let field_ty = if let Some(def_id) = def_id {
860 .unwrap_or(Ty::Unknown) 805 self.db.type_for_field(def_id, field.name.clone())?
861 } 806 } else {
862 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, nr.as_name())?, 807 Ty::Unknown
863 _ => Ty::Unknown,
864 }; 808 };
865 self.insert_type_vars(ty) 809 self.infer_expr(field.expr, &Expectation::has_type(field_ty))?;
866 } else { 810 }
867 Ty::Unknown 811 if let Some(expr) = spread {
812 self.infer_expr(*expr, &Expectation::has_type(ty.clone()))?;
868 } 813 }
814 ty
869 } 815 }
870 ast::Expr::TryExpr(e) => { 816 Expr::Field { expr, name } => {
871 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 817 let receiver_ty = self.infer_expr(*expr, &Expectation::none())?;
818 let ty = match receiver_ty {
819 Ty::Tuple(fields) => {
820 let i = name.to_string().parse::<usize>().ok();
821 i.and_then(|i| fields.get(i).cloned())
822 .unwrap_or(Ty::Unknown)
823 }
824 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, name.clone())?,
825 _ => Ty::Unknown,
826 };
827 self.insert_type_vars(ty)
828 }
829 Expr::Try { expr } => {
830 let _inner_ty = self.infer_expr(*expr, &Expectation::none())?;
872 Ty::Unknown 831 Ty::Unknown
873 } 832 }
874 ast::Expr::CastExpr(e) => { 833 Expr::Cast { expr, type_ref } => {
875 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 834 let _inner_ty = self.infer_expr(*expr, &Expectation::none())?;
876 let cast_ty = Ty::from_ast_opt( 835 let cast_ty =
877 self.db, 836 Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)?;
878 &self.module,
879 self.impl_block.as_ref(),
880 e.type_ref(),
881 )?;
882 let cast_ty = self.insert_type_vars(cast_ty); 837 let cast_ty = self.insert_type_vars(cast_ty);
883 // TODO do the coercion... 838 // TODO check the cast...
884 cast_ty 839 cast_ty
885 } 840 }
886 ast::Expr::RefExpr(e) => { 841 Expr::Ref { expr, mutability } => {
887 // TODO pass the expectation down 842 // TODO pass the expectation down
888 let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 843 let inner_ty = self.infer_expr(*expr, &Expectation::none())?;
889 let m = Mutability::from_mutable(e.is_mut());
890 // TODO reference coercions etc. 844 // TODO reference coercions etc.
891 Ty::Ref(Arc::new(inner_ty), m) 845 Ty::Ref(Arc::new(inner_ty), *mutability)
892 } 846 }
893 ast::Expr::PrefixExpr(e) => { 847 Expr::UnaryOp { expr, op } => {
894 let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 848 let inner_ty = self.infer_expr(*expr, &Expectation::none())?;
895 match e.op() { 849 match op {
896 Some(PrefixOp::Deref) => { 850 Some(UnaryOp::Deref) => {
897 match inner_ty { 851 match inner_ty {
898 // builtin deref: 852 // builtin deref:
899 Ty::Ref(ref_inner, _) => (*ref_inner).clone(), 853 Ty::Ref(ref_inner, _) => (*ref_inner).clone(),
@@ -905,130 +859,112 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
905 _ => Ty::Unknown, 859 _ => Ty::Unknown,
906 } 860 }
907 } 861 }
908 ast::Expr::RangeExpr(_e) => Ty::Unknown, 862 Expr::BinaryOp { lhs, rhs, op } => match op {
909 ast::Expr::BinExpr(_e) => Ty::Unknown, 863 Some(op) => {
910 ast::Expr::Literal(_e) => Ty::Unknown, 864 let subtype_expectation = match op {
865 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => {
866 Expectation::has_type(Ty::Bool)
867 }
868 _ => Expectation::none(),
869 };
870 let _lhs_ty = self.infer_expr(*lhs, &subtype_expectation)?;
871 let _rhs_ty = self.infer_expr(*rhs, &subtype_expectation)?;
872
873 if is_boolean_operator(*op) {
874 Ty::Bool
875 } else {
876 Ty::Unknown
877 }
878 }
879 _ => Ty::Unknown,
880 },
911 }; 881 };
912 // use a new type variable if we got Ty::Unknown here 882 // use a new type variable if we got Ty::Unknown here
913 let ty = self.insert_type_vars_shallow(ty); 883 let ty = self.insert_type_vars_shallow(ty);
914 self.unify(&ty, &expected.ty); 884 self.unify(&ty, &expected.ty);
915 self.write_ty(expr.syntax(), ty.clone()); 885 let ty = self.resolve_ty_as_possible(ty);
886 self.write_expr_ty(expr, ty.clone());
916 Ok(ty) 887 Ok(ty)
917 } 888 }
918 889
919 fn infer_block_opt( 890 fn infer_block(
920 &mut self, 891 &mut self,
921 node: Option<ast::Block>, 892 statements: &[Statement],
893 tail: Option<ExprId>,
922 expected: &Expectation, 894 expected: &Expectation,
923 ) -> Cancelable<Ty> { 895 ) -> Cancelable<Ty> {
924 if let Some(b) = node { 896 for stmt in statements {
925 self.infer_block(b, expected)
926 } else {
927 Ok(Ty::Unknown)
928 }
929 }
930
931 fn infer_block(&mut self, node: ast::Block, expected: &Expectation) -> Cancelable<Ty> {
932 for stmt in node.statements() {
933 match stmt { 897 match stmt {
934 ast::Stmt::LetStmt(stmt) => { 898 Statement::Let {
935 let decl_ty = Ty::from_ast_opt( 899 pat,
900 type_ref,
901 initializer,
902 } => {
903 let decl_ty = Ty::from_hir_opt(
936 self.db, 904 self.db,
937 &self.module, 905 &self.module,
938 self.impl_block.as_ref(), 906 self.impl_block.as_ref(),
939 stmt.type_ref(), 907 type_ref.as_ref(),
940 )?; 908 )?;
941 let decl_ty = self.insert_type_vars(decl_ty); 909 let decl_ty = self.insert_type_vars(decl_ty);
942 let ty = if let Some(expr) = stmt.initializer() { 910 let ty = if let Some(expr) = initializer {
943 let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; 911 let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty))?;
944 expr_ty 912 expr_ty
945 } else { 913 } else {
946 decl_ty 914 decl_ty
947 }; 915 };
948 916
949 if let Some(pat) = stmt.pat() { 917 self.write_pat_ty(*pat, ty);
950 self.write_ty(pat.syntax(), ty);
951 };
952 } 918 }
953 ast::Stmt::ExprStmt(expr_stmt) => { 919 Statement::Expr(expr) => {
954 self.infer_expr_opt(expr_stmt.expr(), &Expectation::none())?; 920 self.infer_expr(*expr, &Expectation::none())?;
955 } 921 }
956 } 922 }
957 } 923 }
958 let ty = if let Some(expr) = node.expr() { 924 let ty = if let Some(expr) = tail {
959 self.infer_expr(expr, expected)? 925 self.infer_expr(expr, expected)?
960 } else { 926 } else {
961 Ty::unit() 927 Ty::unit()
962 }; 928 };
963 self.write_ty(node.syntax(), ty.clone());
964 Ok(ty) 929 Ok(ty)
965 } 930 }
966 931
967 fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> { 932 fn collect_fn_signature(&mut self, signature: &FnSignature) -> Cancelable<()> {
968 if let Some(param_list) = node.param_list() { 933 let body = Arc::clone(&self.body); // avoid borrow checker problem
969 if let Some(self_param) = param_list.self_param() { 934 for (type_ref, pat) in signature.args().iter().zip(body.args()) {
970 let self_type = if let Some(type_ref) = self_param.type_ref() { 935 let ty = self.make_ty(type_ref)?;
971 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; 936 let ty = self.insert_type_vars(ty);
972 self.insert_type_vars(ty) 937 self.write_pat_ty(*pat, ty);
973 } else {
974 // TODO this should be handled by desugaring during HIR conversion
975 let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target_type()))?;
976 let ty = match self_param.flavor() {
977 ast::SelfParamFlavor::Owned => ty,
978 ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared),
979 ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut),
980 };
981 self.insert_type_vars(ty)
982 };
983 if let Some(self_kw) = self_param.self_kw() {
984 let self_param = LocalSyntaxPtr::new(self_kw.syntax());
985 self.self_param = Some(self_param);
986 self.type_of.insert(self_param, self_type);
987 }
988 }
989 for param in param_list.params() {
990 let pat = if let Some(pat) = param.pat() {
991 pat
992 } else {
993 continue;
994 };
995 let ty = if let Some(type_ref) = param.type_ref() {
996 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
997 self.insert_type_vars(ty)
998 } else {
999 // missing type annotation
1000 self.new_type_var()
1001 };
1002 self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
1003 }
1004 } 938 }
1005 939 self.return_ty = {
1006 self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { 940 let ty = self.make_ty(signature.ret_type())?;
1007 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; 941 let ty = self.insert_type_vars(ty);
1008 self.insert_type_vars(ty) 942 ty
1009 } else {
1010 Ty::unit()
1011 }; 943 };
944 Ok(())
945 }
1012 946
947 fn infer_body(&mut self) -> Cancelable<()> {
948 self.infer_expr(
949 self.body.body_expr(),
950 &Expectation::has_type(self.return_ty.clone()),
951 )?;
1013 Ok(()) 952 Ok(())
1014 } 953 }
1015} 954}
1016 955
1017pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 956pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
1018 let function = Function::new(def_id); // TODO: consts also need inference 957 let function = Function::new(def_id); // TODO: consts also need inference
1019 let scopes = function.scopes(db); 958 let body = function.body(db)?;
959 let scopes = db.fn_scopes(def_id)?;
1020 let module = function.module(db)?; 960 let module = function.module(db)?;
1021 let impl_block = function.impl_block(db)?; 961 let impl_block = function.impl_block(db)?;
1022 let mut ctx = InferenceContext::new(db, scopes, module, impl_block); 962 let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block);
1023
1024 let syntax = function.syntax(db);
1025 let node = syntax.borrowed();
1026 963
1027 ctx.collect_fn_signature(node)?; 964 let signature = function.signature(db);
965 ctx.collect_fn_signature(&signature)?;
1028 966
1029 if let Some(block) = node.body() { 967 ctx.infer_body()?;
1030 ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?;
1031 }
1032 968
1033 Ok(Arc::new(ctx.resolve_all())) 969 Ok(Arc::new(ctx.resolve_all()))
1034} 970}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index fb53fcf0b..83aedaa00 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1,8 +1,11 @@
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
5use ra_db::{SyntaxDatabase}; 6use salsa::Database;
7
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};
8 11
@@ -31,7 +34,7 @@ fn test(a: u32, b: isize, c: !, d: &str) {
31 "test"; 34 "test";
32 1.0f32; 35 1.0f32;
33}"#, 36}"#,
34 "0001_basics.txt", 37 "basics.txt",
35 ); 38 );
36} 39}
37 40
@@ -45,7 +48,7 @@ fn test() {
45 let c = b; 48 let c = b;
46} 49}
47}"#, 50}"#,
48 "0002_let.txt", 51 "let.txt",
49 ); 52 );
50} 53}
51 54
@@ -64,7 +67,7 @@ fn test() {
64 b::c(); 67 b::c();
65} 68}
66}"#, 69}"#,
67 "0003_paths.txt", 70 "paths.txt",
68 ); 71 );
69} 72}
70 73
@@ -87,7 +90,7 @@ fn test() {
87 a.c; 90 a.c;
88} 91}
89"#, 92"#,
90 "0004_struct.txt", 93 "struct.txt",
91 ); 94 );
92} 95}
93 96
@@ -109,7 +112,7 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
109 *d; 112 *d;
110} 113}
111"#, 114"#,
112 "0005_refs.txt", 115 "refs_and_ptrs.txt",
113 ); 116 );
114} 117}
115 118
@@ -130,7 +133,7 @@ fn test() -> &mut &f64 {
130 &mut &c 133 &mut &c
131} 134}
132"#, 135"#,
133 "0006_backwards.txt", 136 "backwards.txt",
134 ); 137 );
135} 138}
136 139
@@ -149,7 +152,31 @@ impl S {
149 } 152 }
150} 153}
151"#, 154"#,
152 "0007_self.txt", 155 "self.txt",
156 );
157}
158
159#[test]
160fn infer_boolean_op() {
161 check_inference(
162 r#"
163fn f(x: bool) -> i32 {
164 0i32
165}
166
167fn test() {
168 let x = a && b;
169 let y = true || false;
170 let z = x == y;
171 let h = CONST_1 <= CONST_2;
172 let c = f(z || y) + 5;
173 let d = b;
174 let e = 3i32 && "hello world";
175
176 10 < 3
177}
178"#,
179 "boolean_op.txt",
153 ); 180 );
154} 181}
155 182
@@ -166,7 +193,25 @@ fn infer(content: &str) -> String {
166 .unwrap() 193 .unwrap()
167 .unwrap(); 194 .unwrap();
168 let inference_result = func.infer(&db).unwrap(); 195 let inference_result = func.infer(&db).unwrap();
169 for (syntax_ptr, ty) in &inference_result.type_of { 196 let body_syntax_mapping = func.body_syntax_mapping(&db).unwrap();
197 let mut types = Vec::new();
198 for (pat, ty) in inference_result.type_of_pat.iter() {
199 let syntax_ptr = match body_syntax_mapping.pat_syntax(pat) {
200 Some(sp) => sp,
201 None => continue,
202 };
203 types.push((syntax_ptr, ty));
204 }
205 for (expr, ty) in inference_result.type_of_expr.iter() {
206 let syntax_ptr = match body_syntax_mapping.expr_syntax(expr) {
207 Some(sp) => sp,
208 None => continue,
209 };
210 types.push((syntax_ptr, ty));
211 }
212 // sort ranges for consistency
213 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end()));
214 for (syntax_ptr, ty) in &types {
170 let node = syntax_ptr.resolve(&source_file); 215 let node = syntax_ptr.resolve(&source_file);
171 write!( 216 write!(
172 acc, 217 acc,
@@ -217,3 +262,43 @@ fn ellipsize(mut text: String, max_len: usize) -> String {
217fn test_data_dir() -> PathBuf { 262fn test_data_dir() -> PathBuf {
218 project_dir().join("crates/ra_hir/src/ty/tests/data") 263 project_dir().join("crates/ra_hir/src/ty/tests/data")
219} 264}
265
266#[test]
267fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
268 let (mut db, pos) = MockDatabase::with_position(
269 "
270 //- /lib.rs
271 fn foo() -> i32 {
272 <|>1 + 1
273 }
274 ",
275 );
276 let func = source_binder::function_from_position(&db, pos)
277 .unwrap()
278 .unwrap();
279 {
280 let events = db.log_executed(|| {
281 func.infer(&db).unwrap();
282 });
283 assert!(format!("{:?}", events).contains("infer"))
284 }
285
286 let new_text = "
287 fn foo() -> i32 {
288 1
289 +
290 1
291 }
292 "
293 .to_string();
294
295 db.query_mut(ra_db::FileTextQuery)
296 .set(pos.file_id, Arc::new(new_text));
297
298 {
299 let events = db.log_executed(|| {
300 func.infer(&db).unwrap();
301 });
302 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events)
303 }
304}
diff --git a/crates/ra_hir/src/ty/tests/data/0006_backwards.txt b/crates/ra_hir/src/ty/tests/data/backwards.txt
index 120069401..b6807fb2a 100644
--- a/crates/ra_hir/src/ty/tests/data/0006_backwards.txt
+++ b/crates/ra_hir/src/ty/tests/data/backwards.txt
@@ -1,20 +1,20 @@
1[22; 24) '{}': ()
2[14; 15) 'x': u32 1[14; 15) 'x': u32
3[142; 158) 'unknow...nction': [unknown] 2[22; 24) '{}': ()
4[126; 127) 'a': u32
5[198; 216) 'unknow...tion()': f64
6[228; 229) 'c': f64
7[198; 214) 'unknow...nction': [unknown]
8[166; 184) 'S { i3...d: b }': S
9[222; 229) '&mut &c': &mut &f64
10[194; 195) 'c': f64
11[92; 110) 'unknow...tion()': u32
12[142; 160) 'unknow...tion()': i32
13[92; 108) 'unknow...nction': [unknown]
14[116; 128) 'takes_u32(a)': ()
15[78; 231) '{ ...t &c }': &mut &f64 3[78; 231) '{ ...t &c }': &mut &f64
16[227; 229) '&c': &f64
17[88; 89) 'a': u32 4[88; 89) 'a': u32
18[181; 182) 'b': i32 5[92; 108) 'unknow...nction': [unknown]
6[92; 110) 'unknow...tion()': u32
19[116; 125) 'takes_u32': fn(u32,) -> () 7[116; 125) 'takes_u32': fn(u32,) -> ()
8[116; 128) 'takes_u32(a)': ()
9[126; 127) 'a': u32
20[138; 139) 'b': i32 10[138; 139) 'b': i32
11[142; 158) 'unknow...nction': [unknown]
12[142; 160) 'unknow...tion()': i32
13[166; 184) 'S { i3...d: b }': S
14[181; 182) 'b': i32
15[194; 195) 'c': f64
16[198; 214) 'unknow...nction': [unknown]
17[198; 216) 'unknow...tion()': f64
18[222; 229) '&mut &c': &mut &f64
19[227; 229) '&c': &f64
20[228; 229) 'c': f64
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.txt b/crates/ra_hir/src/ty/tests/data/basics.txt
index 212e92e00..8ea244ba8 100644
--- a/crates/ra_hir/src/ty/tests/data/0001_basics.txt
+++ b/crates/ra_hir/src/ty/tests/data/basics.txt
@@ -1,13 +1,13 @@
1[9; 10) 'a': u32
2[17; 18) 'b': isize
3[27; 28) 'c': !
1[33; 34) 'd': &[unknown] 4[33; 34) 'd': &[unknown]
2[88; 94) '1isize': [unknown] 5[42; 121) '{ ...f32; }': ()
3[48; 49) 'a': u32 6[48; 49) 'a': u32
4[55; 56) 'b': isize 7[55; 56) 'b': isize
5[112; 118) '1.0f32': [unknown]
6[76; 82) '1usize': [unknown]
7[9; 10) 'a': u32
8[27; 28) 'c': !
9[62; 63) 'c': ! 8[62; 63) 'c': !
10[17; 18) 'b': isize
11[100; 106) '"test"': [unknown]
12[42; 121) '{ ...f32; }': ()
13[69; 70) 'd': &[unknown] 9[69; 70) 'd': &[unknown]
10[76; 82) '1usize': [unknown]
11[88; 94) '1isize': [unknown]
12[100; 106) '"test"': [unknown]
13[112; 118) '1.0f32': [unknown]
diff --git a/crates/ra_hir/src/ty/tests/data/boolean_op.txt b/crates/ra_hir/src/ty/tests/data/boolean_op.txt
new file mode 100644
index 000000000..cce8d68fb
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/boolean_op.txt
@@ -0,0 +1,31 @@
1[6; 7) 'x': [unknown]
2[22; 34) '{ 0i32 }': i32
3[28; 32) '0i32': i32
4[46; 237) '{ ... < 3 }': bool
5[56; 57) 'x': bool
6[60; 61) 'a': bool
7[60; 66) 'a && b': bool
8[65; 66) 'b': bool
9[76; 77) 'y': bool
10[80; 84) 'true': bool
11[80; 93) 'true || false': bool
12[88; 93) 'false': bool
13[103; 104) 'z': bool
14[107; 108) 'x': bool
15[107; 113) 'x == y': bool
16[112; 113) 'y': bool
17[123; 124) 'h': bool
18[127; 134) 'CONST_1': [unknown]
19[127; 145) 'CONST_...ONST_2': bool
20[138; 145) 'CONST_2': [unknown]
21[155; 156) 'c': [unknown]
22[159; 172) 'f(z || y) + 5': [unknown]
23[182; 183) 'd': [unknown]
24[186; 187) 'b': [unknown]
25[197; 198) 'e': bool
26[201; 205) '3i32': bool
27[201; 222) '3i32 &...world"': bool
28[209; 222) '"hello world"': bool
29[229; 231) '10': [unknown]
30[229; 235) '10 < 3': bool
31[234; 235) '3': [unknown]
diff --git a/crates/ra_hir/src/ty/tests/data/0002_let.txt b/crates/ra_hir/src/ty/tests/data/let.txt
index 916ca25a1..30f4a2cf5 100644
--- a/crates/ra_hir/src/ty/tests/data/0002_let.txt
+++ b/crates/ra_hir/src/ty/tests/data/let.txt
@@ -1,7 +1,7 @@
1[21; 22) 'a': [unknown]
2[52; 53) '1': usize
3[11; 71) '{ ...= b; }': () 1[11; 71) '{ ...= b; }': ()
4[63; 64) 'c': usize 2[21; 22) 'a': [unknown]
5[25; 31) '1isize': [unknown] 3[25; 31) '1isize': [unknown]
6[41; 42) 'b': usize 4[41; 42) 'b': usize
5[52; 53) '1': usize
6[63; 64) 'c': usize
7[67; 68) 'b': usize 7[67; 68) 'b': usize
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.txt b/crates/ra_hir/src/ty/tests/data/paths.txt
index 2a12d264f..b22f4d4a5 100644
--- a/crates/ra_hir/src/ty/tests/data/0003_paths.txt
+++ b/crates/ra_hir/src/ty/tests/data/paths.txt
@@ -1,9 +1,9 @@
1[15; 20) '{ 1 }': u32 1[15; 20) '{ 1 }': u32
2[17; 18) '1': u32 2[17; 18) '1': u32
3[50; 51) '1': u32
4[48; 53) '{ 1 }': u32 3[48; 53) '{ 1 }': u32
5[82; 88) 'b::c()': u32 4[50; 51) '1': u32
6[67; 91) '{ ...c(); }': () 5[67; 91) '{ ...c(); }': ()
7[73; 74) 'a': fn() -> u32 6[73; 74) 'a': fn() -> u32
8[73; 76) 'a()': u32 7[73; 76) 'a()': u32
9[82; 86) 'b::c': fn() -> u32 8[82; 86) 'b::c': fn() -> u32
9[82; 88) 'b::c()': u32
diff --git a/crates/ra_hir/src/ty/tests/data/0005_refs.txt b/crates/ra_hir/src/ty/tests/data/refs_and_ptrs.txt
index 296e955c1..afab343ea 100644
--- a/crates/ra_hir/src/ty/tests/data/0005_refs.txt
+++ b/crates/ra_hir/src/ty/tests/data/refs_and_ptrs.txt
@@ -1,23 +1,23 @@
1[115; 117) '&b': &&mut u32 1[9; 10) 'a': &u32
2[88; 94) '&mut a': &mut &u32 2[18; 19) 'b': &mut u32
3[146; 147) 'd': *mut u32 3[31; 32) 'c': *const u32
4[145; 147) '*d': u32
5[65; 66) 'a': &u32
6[46; 47) 'd': *mut u32 4[46; 47) 'd': *mut u32
7[59; 150) '{ ... *d; }': () 5[59; 150) '{ ... *d; }': ()
8[116; 117) 'b': &mut u32 6[65; 66) 'a': &u32
9[131; 132) 'c': *const u32
10[130; 132) '*c': u32
11[72; 74) '*a': u32 7[72; 74) '*a': u32
12[107; 109) '*b': u32 8[73; 74) 'a': &u32
13[108; 109) 'b': &mut u32 9[80; 82) '&a': &&u32
14[9; 10) 'a': &u32 10[81; 82) 'a': &u32
15[18; 19) 'b': &mut u32 11[88; 94) '&mut a': &mut &u32
16[93; 94) 'a': &u32 12[93; 94) 'a': &u32
17[100; 101) 'b': &mut u32 13[100; 101) 'b': &mut u32
18[81; 82) 'a': &u32 14[107; 109) '*b': u32
19[80; 82) '&a': &&u32 15[108; 109) 'b': &mut u32
20[73; 74) 'a': &u32 16[115; 117) '&b': &&mut u32
17[116; 117) 'b': &mut u32
21[123; 124) 'c': *const u32 18[123; 124) 'c': *const u32
22[31; 32) 'c': *const u32 19[130; 132) '*c': u32
20[131; 132) 'c': *const u32
23[138; 139) 'd': *mut u32 21[138; 139) 'd': *mut u32
22[145; 147) '*d': u32
23[146; 147) 'd': *mut u32
diff --git a/crates/ra_hir/src/ty/tests/data/0007_self.txt b/crates/ra_hir/src/ty/tests/data/self.txt
index db4ba17d0..c38029f97 100644
--- a/crates/ra_hir/src/ty/tests/data/0007_self.txt
+++ b/crates/ra_hir/src/ty/tests/data/self.txt
@@ -1,6 +1,6 @@
1[50; 54) 'self': &S
2[34; 38) 'self': &S 1[34; 38) 'self': &S
3[40; 61) '{ ... }': () 2[40; 61) '{ ... }': ()
3[50; 54) 'self': &S
4[75; 79) 'self': &S
4[88; 109) '{ ... }': () 5[88; 109) '{ ... }': ()
5[98; 102) 'self': &S 6[98; 102) 'self': &S
6[75; 79) 'self': &S
diff --git a/crates/ra_hir/src/ty/tests/data/0004_struct.txt b/crates/ra_hir/src/ty/tests/data/struct.txt
index b4af18b87..7b324c82f 100644
--- a/crates/ra_hir/src/ty/tests/data/0004_struct.txt
+++ b/crates/ra_hir/src/ty/tests/data/struct.txt
@@ -1,16 +1,16 @@
1[86; 90) 'C(1)': [unknown] 1[72; 154) '{ ...a.c; }': ()
2[121; 122) 'B': B 2[82; 83) 'c': [unknown]
3[86; 87) 'C': [unknown] 3[86; 87) 'C': [unknown]
4[129; 130) '1': [unknown] 4[86; 90) 'C(1)': [unknown]
5[88; 89) '1': [unknown]
6[96; 97) 'B': [unknown]
5[107; 108) 'a': A 7[107; 108) 'a': A
8[114; 133) 'A { b:...C(1) }': A
9[121; 122) 'B': B
6[127; 128) 'C': [unknown] 10[127; 128) 'C': [unknown]
11[127; 131) 'C(1)': C
12[129; 130) '1': [unknown]
13[139; 140) 'a': A
7[139; 142) 'a.b': B 14[139; 142) 'a.b': B
8[114; 133) 'A { b:...C(1) }': A
9[148; 151) 'a.c': C
10[148; 149) 'a': A 15[148; 149) 'a': A
11[139; 140) 'a': A 16[148; 151) 'a.c': C
12[72; 154) '{ ...a.c; }': ()
13[96; 97) 'B': [unknown]
14[88; 89) '1': [unknown]
15[82; 83) 'c': [unknown]
16[127; 131) 'C(1)': C
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.rs b/crates/ra_syntax/src/ast.rs
index c10169d90..9df8ec663 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -489,6 +489,58 @@ impl<'a> PrefixExpr<'a> {
489} 489}
490 490
491#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 491#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
492pub enum BinOp {
493 /// The `||` operator for boolean OR
494 BooleanOr,
495 /// The `&&` operator for boolean AND
496 BooleanAnd,
497 /// The `==` operator for equality testing
498 EqualityTest,
499 /// The `<=` operator for lesser-equal testing
500 LesserEqualTest,
501 /// The `>=` operator for greater-equal testing
502 GreaterEqualTest,
503 /// The `<` operator for comparison
504 LesserTest,
505 /// The `>` operator for comparison
506 GreaterTest,
507 // TODO: lots of others
508}
509
510impl<'a> BinExpr<'a> {
511 pub fn op(&self) -> Option<BinOp> {
512 self.syntax()
513 .children()
514 .filter_map(|c| match c.kind() {
515 PIPEPIPE => Some(BinOp::BooleanOr),
516 AMPAMP => Some(BinOp::BooleanAnd),
517 EQEQ => Some(BinOp::EqualityTest),
518 LTEQ => Some(BinOp::LesserEqualTest),
519 GTEQ => Some(BinOp::GreaterEqualTest),
520 L_ANGLE => Some(BinOp::LesserTest),
521 R_ANGLE => Some(BinOp::GreaterTest),
522 _ => None,
523 })
524 .next()
525 }
526
527 pub fn lhs(self) -> Option<Expr<'a>> {
528 children(self).nth(0)
529 }
530
531 pub fn rhs(self) -> Option<Expr<'a>> {
532 children(self).nth(1)
533 }
534
535 pub fn sub_exprs(self) -> (Option<Expr<'a>>, Option<Expr<'a>>) {
536 let mut children = children(self);
537 let first = children.next();
538 let second = children.next();
539 (first, second)
540 }
541}
542
543#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
492pub enum SelfParamFlavor { 544pub enum SelfParamFlavor {
493 /// self 545 /// self
494 Owned, 546 Owned,
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": (),