aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model_impl/function/scope.rs11
-rw-r--r--crates/ra_hir/src/expr.rs67
-rw-r--r--crates/ra_hir/src/ty.rs5
-rw-r--r--crates/ra_hir/src/ty/tests.rs15
4 files changed, 85 insertions, 13 deletions
diff --git a/crates/ra_hir/src/code_model_impl/function/scope.rs b/crates/ra_hir/src/code_model_impl/function/scope.rs
index afca1e9f8..c551e445a 100644
--- a/crates/ra_hir/src/code_model_impl/function/scope.rs
+++ b/crates/ra_hir/src/code_model_impl/function/scope.rs
@@ -47,9 +47,11 @@ impl FnScopes {
47 compute_expr_scopes(body.body_expr(), &body, &mut scopes, root); 47 compute_expr_scopes(body.body_expr(), &body, &mut scopes, root);
48 scopes 48 scopes
49 } 49 }
50
50 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { 51 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
51 &self.scopes[scope].entries 52 &self.scopes[scope].entries
52 } 53 }
54
53 pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + 'a { 55 pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + 'a {
54 generate(self.scope_for(expr), move |&scope| { 56 generate(self.scope_for(expr), move |&scope| {
55 self.scopes[scope].parent 57 self.scopes[scope].parent
@@ -76,12 +78,14 @@ impl FnScopes {
76 entries: vec![], 78 entries: vec![],
77 }) 79 })
78 } 80 }
81
79 fn new_scope(&mut self, parent: ScopeId) -> ScopeId { 82 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
80 self.scopes.alloc(ScopeData { 83 self.scopes.alloc(ScopeData {
81 parent: Some(parent), 84 parent: Some(parent),
82 entries: vec![], 85 entries: vec![],
83 }) 86 })
84 } 87 }
88
85 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { 89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
86 match &body[pat] { 90 match &body[pat] {
87 Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry { 91 Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry {
@@ -91,15 +95,18 @@ impl FnScopes {
91 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), 95 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
92 } 96 }
93 } 97 }
98
94 fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) { 99 fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) {
95 let body = Arc::clone(&self.body); 100 let body = Arc::clone(&self.body);
96 params 101 params
97 .into_iter() 102 .into_iter()
98 .for_each(|pat| self.add_bindings(&body, scope, *pat)); 103 .for_each(|pat| self.add_bindings(&body, scope, *pat));
99 } 104 }
105
100 fn set_scope(&mut self, node: ExprId, scope: ScopeId) { 106 fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
101 self.scope_for.insert(node, scope); 107 self.scope_for.insert(node, scope);
102 } 108 }
109
103 fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { 110 fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
104 self.scope_for.get(&expr).map(|&scope| scope) 111 self.scope_for.get(&expr).map(|&scope| scope)
105 } 112 }
@@ -121,6 +128,7 @@ impl ScopeEntryWithSyntax {
121 pub fn name(&self) -> &Name { 128 pub fn name(&self) -> &Name {
122 &self.name 129 &self.name
123 } 130 }
131
124 pub fn ptr(&self) -> LocalSyntaxPtr { 132 pub fn ptr(&self) -> LocalSyntaxPtr {
125 self.ptr 133 self.ptr
126 } 134 }
@@ -132,6 +140,7 @@ impl ScopesWithSyntaxMapping {
132 self.scopes.scopes[scope].parent 140 self.scopes.scopes[scope].parent
133 }) 141 })
134 } 142 }
143
135 pub fn scope_chain_for_offset<'a>( 144 pub fn scope_chain_for_offset<'a>(
136 &'a self, 145 &'a self,
137 offset: TextUnit, 146 offset: TextUnit,
@@ -152,6 +161,7 @@ impl ScopesWithSyntaxMapping {
152 161
153 generate(scope, move |&scope| self.scopes.scopes[scope].parent) 162 generate(scope, move |&scope| self.scopes.scopes[scope].parent)
154 } 163 }
164
155 // XXX: during completion, cursor might be outside of any particular 165 // XXX: during completion, cursor might be outside of any particular
156 // expression. Try to figure out the correct scope... 166 // expression. Try to figure out the correct scope...
157 fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { 167 fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId {
@@ -225,6 +235,7 @@ impl ScopeEntry {
225 pub fn name(&self) -> &Name { 235 pub fn name(&self) -> &Name {
226 &self.name 236 &self.name
227 } 237 }
238
228 pub fn pat(&self) -> PatId { 239 pub fn pat(&self) -> PatId {
229 self.pat 240 self.pat
230 } 241 }
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 6e98ebc69..8f7e75309 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -329,9 +329,25 @@ impl Expr {
329pub struct PatId(RawId); 329pub struct PatId(RawId);
330impl_arena_id!(PatId); 330impl_arena_id!(PatId);
331 331
332/// Close relative to rustc's hir::PatKind
332#[derive(Debug, Clone, Eq, PartialEq)] 333#[derive(Debug, Clone, Eq, PartialEq)]
333pub enum Pat { 334pub enum Pat {
334 Missing, 335 Missing, // do we need this?
336 Wild,
337 Tuple(Vec<PatId>),
338 Struct, // TODO
339 Range {
340 start: ExprId,
341 end: ExprId,
342 },
343 Box(PatId),
344 Slice {
345 prefix: Vec<PatId>,
346 rest: Option<PatId>,
347 suffix: Vec<PatId>,
348 },
349 Path(Path),
350 Lit(ExprId),
335 Bind { 351 Bind {
336 name: Name, 352 name: Name,
337 }, 353 },
@@ -348,11 +364,25 @@ pub enum Pat {
348impl Pat { 364impl Pat {
349 pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { 365 pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
350 match self { 366 match self {
351 Pat::Missing | Pat::Bind { .. } => {} 367 Pat::Range { .. }
352 Pat::TupleStruct { args, .. } => { 368 | Pat::Lit(..)
369 | Pat::Path(..)
370 | Pat::Wild
371 | Pat::Missing
372 | Pat::Bind { .. } => {}
373 Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
353 args.iter().map(|pat| *pat).for_each(f); 374 args.iter().map(|pat| *pat).for_each(f);
354 } 375 }
355 Pat::Ref { pat, .. } => f(*pat), 376 Pat::Ref { pat, .. } | Pat::Box(pat) => f(*pat),
377 Pat::Slice {
378 prefix,
379 rest,
380 suffix,
381 } => {
382 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
383 total_iter.map(|pat| *pat).for_each(f);
384 }
385 Pat::Struct { .. } => {} // TODO
356 } 386 }
357 } 387 }
358} 388}
@@ -745,30 +775,41 @@ impl ExprCollector {
745 } 775 }
746 776
747 fn collect_pat(&mut self, pat: &ast::Pat) -> PatId { 777 fn collect_pat(&mut self, pat: &ast::Pat) -> PatId {
748 let syntax_ptr = LocalSyntaxPtr::new(pat.syntax()); 778 let pattern = match pat.kind() {
749 match pat.kind() {
750 ast::PatKind::BindPat(bp) => { 779 ast::PatKind::BindPat(bp) => {
751 let name = bp 780 let name = bp
752 .name() 781 .name()
753 .map(|nr| nr.as_name()) 782 .map(|nr| nr.as_name())
754 .unwrap_or_else(Name::missing); 783 .unwrap_or_else(Name::missing);
755 self.alloc_pat(Pat::Bind { name }, syntax_ptr) 784 Pat::Bind { name }
756 } 785 }
757 ast::PatKind::TupleStructPat(p) => { 786 ast::PatKind::TupleStructPat(p) => {
758 let path = p.path().and_then(Path::from_ast); 787 let path = p.path().and_then(Path::from_ast);
759 let args = p.args().map(|p| self.collect_pat(p)).collect(); 788 let args = p.args().map(|p| self.collect_pat(p)).collect();
760 self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr) 789 Pat::TupleStruct { path, args }
761 } 790 }
762 ast::PatKind::RefPat(p) => { 791 ast::PatKind::RefPat(p) => {
763 let pat = self.collect_pat_opt(p.pat()); 792 let pat = self.collect_pat_opt(p.pat());
764 let mutability = Mutability::from_mutable(p.is_mut()); 793 let mutability = Mutability::from_mutable(p.is_mut());
765 self.alloc_pat(Pat::Ref { pat, mutability }, syntax_ptr) 794 Pat::Ref { pat, mutability }
766 } 795 }
767 _ => { 796 ast::PatKind::PathPat(p) => {
768 // TODO 797 let path = p.path().and_then(Path::from_ast);
769 self.alloc_pat(Pat::Missing, syntax_ptr) 798 path.map(|path| Pat::Path(path)).unwrap_or(Pat::Missing)
770 } 799 }
771 } 800 ast::PatKind::TuplePat(p) => {
801 let args = p.args().map(|p| self.collect_pat(p)).collect();
802 Pat::Tuple(args)
803 }
804 ast::PatKind::PlaceholderPat(_) => Pat::Wild,
805 // TODO: implement
806 ast::PatKind::FieldPatList(_)
807 | ast::PatKind::SlicePat(_)
808 | ast::PatKind::StructPat(_)
809 | ast::PatKind::RangePat(_) => Pat::Missing,
810 };
811 let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
812 self.alloc_pat(pattern, syntax_ptr)
772 } 813 }
773 814
774 fn collect_pat_opt(&mut self, pat: Option<&ast::Pat>) -> PatId { 815 fn collect_pat_opt(&mut self, pat: Option<&ast::Pat>) -> PatId {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index c7c063601..854d3e3d9 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -1168,6 +1168,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1168 decl_ty 1168 decl_ty
1169 }; 1169 };
1170 1170
1171 // TODO: walk the pattern here?
1172
1171 self.write_pat_ty(*pat, ty); 1173 self.write_pat_ty(*pat, ty);
1172 } 1174 }
1173 Statement::Expr(expr) => { 1175 Statement::Expr(expr) => {
@@ -1188,6 +1190,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1188 for (type_ref, pat) in signature.params().iter().zip(body.params()) { 1190 for (type_ref, pat) in signature.params().iter().zip(body.params()) {
1189 let ty = self.make_ty(type_ref); 1191 let ty = self.make_ty(type_ref);
1190 let ty = self.insert_type_vars(ty); 1192 let ty = self.insert_type_vars(ty);
1193
1194 // TODO: walk pattern?
1195
1191 self.write_pat_ty(*pat, ty); 1196 self.write_pat_ty(*pat, ty);
1192 } 1197 }
1193 self.return_ty = { 1198 self.return_ty = {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index a430cbe88..fc1e5b09c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -358,6 +358,21 @@ fn test(x: &str, y: isize) {
358 ); 358 );
359} 359}
360 360
361#[test]
362fn infer_pattern() {
363 check_inference(
364 r#"
365fn test(x: &i32) {
366 let y = x;
367 let &z = x;
368 let a = z;
369 let (c, d) = (1, "hello");
370}
371"#,
372 "pattern.txt",
373 );
374}
375
361fn infer(content: &str) -> String { 376fn infer(content: &str) -> String {
362 let (db, _, file_id) = MockDatabase::with_single_file(content); 377 let (db, _, file_id) = MockDatabase::with_single_file(content);
363 let source_file = db.source_file(file_id); 378 let source_file = db.source_file(file_id);