aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/semantics.rs4
-rw-r--r--crates/ra_hir/src/source_analyzer.rs11
-rw-r--r--crates/ra_hir_def/src/body/scope.rs4
-rw-r--r--crates/ra_hir_ty/src/infer.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs6
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs26
-rw-r--r--crates/ra_ide/src/goto_definition.rs28
-rw-r--r--crates/ra_ide_db/src/defs.rs9
-rw-r--r--crates/ra_ide_db/src/marks.rs1
9 files changed, 87 insertions, 6 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 0b477f0e9..5d6edc45c 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -195,6 +195,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
195 self.analyze(field.syntax()).resolve_record_field(self.db, field) 195 self.analyze(field.syntax()).resolve_record_field(self.db, field)
196 } 196 }
197 197
198 pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<StructField> {
199 self.analyze(field.syntax()).resolve_record_field_pat(self.db, field)
200 }
201
198 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { 202 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
199 let sa = self.analyze(macro_call.syntax()); 203 let sa = self.analyze(macro_call.syntax());
200 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); 204 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 23af400b8..0ed6d0958 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -95,6 +95,7 @@ impl SourceAnalyzer {
95 } 95 }
96 96
97 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { 97 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
98 // FIXME: macros, see `expr_id`
98 let src = InFile { file_id: self.file_id, value: pat }; 99 let src = InFile { file_id: self.file_id, value: pat };
99 self.body_source_map.as_ref()?.node_pat(src) 100 self.body_source_map.as_ref()?.node_pat(src)
100 } 101 }
@@ -167,6 +168,16 @@ impl SourceAnalyzer {
167 Some((struct_field.into(), local)) 168 Some((struct_field.into(), local))
168 } 169 }
169 170
171 pub(crate) fn resolve_record_field_pat(
172 &self,
173 _db: &dyn HirDatabase,
174 field: &ast::RecordFieldPat,
175 ) -> Option<StructField> {
176 let pat_id = self.pat_id(&field.pat()?)?;
177 let struct_field = self.infer.as_ref()?.record_field_pat_resolution(pat_id)?;
178 Some(struct_field.into())
179 }
180
170 pub(crate) fn resolve_macro_call( 181 pub(crate) fn resolve_macro_call(
171 &self, 182 &self,
172 db: &dyn HirDatabase, 183 db: &dyn HirDatabase,
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 4d489f692..fe4137176 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -157,6 +157,10 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
157 for arm in arms { 157 for arm in arms {
158 let scope = scopes.new_scope(scope); 158 let scope = scopes.new_scope(scope);
159 scopes.add_bindings(body, scope, arm.pat); 159 scopes.add_bindings(body, scope, arm.pat);
160 if let Some(guard) = arm.guard {
161 scopes.set_scope(guard, scope);
162 compute_expr_scopes(guard, body, scopes, scope);
163 }
160 scopes.set_scope(arm.expr, scope); 164 scopes.set_scope(arm.expr, scope);
161 compute_expr_scopes(arm.expr, body, scopes, scope); 165 compute_expr_scopes(arm.expr, body, scopes, scope);
162 } 166 }
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index b6d9b3438..dfb6a435f 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -127,6 +127,7 @@ pub struct InferenceResult {
127 field_resolutions: FxHashMap<ExprId, StructFieldId>, 127 field_resolutions: FxHashMap<ExprId, StructFieldId>,
128 /// For each field in record literal, records the field it resolves to. 128 /// For each field in record literal, records the field it resolves to.
129 record_field_resolutions: FxHashMap<ExprId, StructFieldId>, 129 record_field_resolutions: FxHashMap<ExprId, StructFieldId>,
130 record_field_pat_resolutions: FxHashMap<PatId, StructFieldId>,
130 /// For each struct literal, records the variant it resolves to. 131 /// For each struct literal, records the variant it resolves to.
131 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, 132 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
132 /// For each associated item record what it resolves to 133 /// For each associated item record what it resolves to
@@ -147,6 +148,9 @@ impl InferenceResult {
147 pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructFieldId> { 148 pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructFieldId> {
148 self.record_field_resolutions.get(&expr).copied() 149 self.record_field_resolutions.get(&expr).copied()
149 } 150 }
151 pub fn record_field_pat_resolution(&self, pat: PatId) -> Option<StructFieldId> {
152 self.record_field_pat_resolutions.get(&pat).copied()
153 }
150 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { 154 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
151 self.variant_resolutions.get(&id.into()).copied() 155 self.variant_resolutions.get(&id.into()).copied()
152 } 156 }
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 8ec4d4ace..7c2ad4384 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -7,6 +7,7 @@ use hir_def::{
7 expr::{BindingAnnotation, Pat, PatId, RecordFieldPat}, 7 expr::{BindingAnnotation, Pat, PatId, RecordFieldPat},
8 path::Path, 8 path::Path,
9 type_ref::Mutability, 9 type_ref::Mutability,
10 StructFieldId,
10}; 11};
11use hir_expand::name::Name; 12use hir_expand::name::Name;
12use test_utils::tested_by; 13use test_utils::tested_by;
@@ -67,6 +68,11 @@ impl<'a> InferenceContext<'a> {
67 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); 68 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
68 for subpat in subpats { 69 for subpat in subpats {
69 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); 70 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
71 if let Some(local_id) = matching_field {
72 let field_def = StructFieldId { parent: def.unwrap(), local_id };
73 self.result.record_field_pat_resolutions.insert(subpat.pat, field_def);
74 }
75
70 let expected_ty = 76 let expected_ty =
71 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs)); 77 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
72 let expected_ty = self.normalize_associated_types_in(expected_ty); 78 let expected_ty = self.normalize_associated_types_in(expected_ty);
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index 07cbc521a..6ea51d5d3 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -455,3 +455,29 @@ fn test() {
455 "### 455 "###
456 ); 456 );
457} 457}
458
459#[test]
460fn infer_guard() {
461 assert_snapshot!(
462 infer(r#"
463struct S;
464impl S { fn foo(&self) -> bool { false } }
465
466fn main() {
467 match S {
468 s if s.foo() => (),
469 }
470}
471 "#), @"
472 [28; 32) 'self': &S
473 [42; 51) '{ false }': bool
474 [44; 49) 'false': bool
475 [65; 116) '{ ... } }': ()
476 [71; 114) 'match ... }': ()
477 [77; 78) 'S': S
478 [89; 90) 's': S
479 [94; 95) 's': S
480 [94; 101) 's.foo()': bool
481 [105; 107) '()': ()
482 ")
483}
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 8aed94d16..9998ca5a3 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -62,10 +62,9 @@ pub(crate) enum ReferenceResult {
62 62
63impl ReferenceResult { 63impl ReferenceResult {
64 fn to_vec(self) -> Vec<NavigationTarget> { 64 fn to_vec(self) -> Vec<NavigationTarget> {
65 use self::ReferenceResult::*;
66 match self { 65 match self {
67 Exact(target) => vec![target], 66 ReferenceResult::Exact(target) => vec![target],
68 Approximate(vec) => vec, 67 ReferenceResult::Approximate(vec) => vec,
69 } 68 }
70 } 69 }
71} 70}
@@ -74,8 +73,6 @@ pub(crate) fn reference_definition(
74 sema: &Semantics<RootDatabase>, 73 sema: &Semantics<RootDatabase>,
75 name_ref: &ast::NameRef, 74 name_ref: &ast::NameRef,
76) -> ReferenceResult { 75) -> ReferenceResult {
77 use self::ReferenceResult::*;
78
79 let name_kind = classify_name_ref(sema, name_ref); 76 let name_kind = classify_name_ref(sema, name_ref);
80 if let Some(def) = name_kind { 77 if let Some(def) = name_kind {
81 let def = def.definition(); 78 let def = def.definition();
@@ -91,7 +88,7 @@ pub(crate) fn reference_definition(
91 .into_iter() 88 .into_iter()
92 .map(|s| s.to_nav(sema.db)) 89 .map(|s| s.to_nav(sema.db))
93 .collect(); 90 .collect();
94 Approximate(navs) 91 ReferenceResult::Approximate(navs)
95} 92}
96 93
97#[cfg(test)] 94#[cfg(test)]
@@ -399,6 +396,25 @@ mod tests {
399 } 396 }
400 397
401 #[test] 398 #[test]
399 fn goto_def_for_record_pat_fields() {
400 covers!(ra_ide_db::goto_def_for_record_field_pats);
401 check_goto(
402 r"
403 //- /lib.rs
404 struct Foo {
405 spam: u32,
406 }
407
408 fn bar(foo: Foo) -> Foo {
409 let Foo { spam<|>: _, } = foo
410 }
411 ",
412 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
413 "spam: u32|spam",
414 );
415 }
416
417 #[test]
402 fn goto_def_for_record_fields_macros() { 418 fn goto_def_for_record_fields_macros() {
403 check_goto( 419 check_goto(
404 r" 420 r"
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index 49a8c74fb..785613b82 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -180,6 +180,7 @@ fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Opti
180 } 180 }
181} 181}
182 182
183#[derive(Debug)]
183pub enum NameRefClass { 184pub enum NameRefClass {
184 Definition(Definition), 185 Definition(Definition),
185 FieldShorthand { local: Local, field: Definition }, 186 FieldShorthand { local: Local, field: Definition },
@@ -229,6 +230,14 @@ pub fn classify_name_ref(
229 } 230 }
230 } 231 }
231 232
233 if let Some(record_field_pat) = ast::RecordFieldPat::cast(parent.clone()) {
234 tested_by!(goto_def_for_record_field_pats; force);
235 if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
236 let field = Definition::StructField(field);
237 return Some(NameRefClass::Definition(field));
238 }
239 }
240
232 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { 241 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
233 tested_by!(goto_def_for_macros; force); 242 tested_by!(goto_def_for_macros; force);
234 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) { 243 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
diff --git a/crates/ra_ide_db/src/marks.rs b/crates/ra_ide_db/src/marks.rs
index 4f0a22af0..03b4be21c 100644
--- a/crates/ra_ide_db/src/marks.rs
+++ b/crates/ra_ide_db/src/marks.rs
@@ -6,5 +6,6 @@ test_utils::marks![
6 goto_def_for_fields 6 goto_def_for_fields
7 goto_def_for_record_fields 7 goto_def_for_record_fields
8 goto_def_for_field_init_shorthand 8 goto_def_for_field_init_shorthand
9 goto_def_for_record_field_pats
9 search_filters_by_range 10 search_filters_by_range
10]; 11];