aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-11-24 17:06:55 +0000
committerAleksey Kladov <[email protected]>2019-11-24 17:06:55 +0000
commit63e3ea38d3ff7ab69b968e8962f33e82a4f978fb (patch)
tree8f4d416bad74f75e43924981b1d2c2099ea50edc
parentac9ba5eb32073c16608acaa04324e7dc46d303d6 (diff)
Don't redo field resolution in the IDE
-rw-r--r--crates/ra_hir/src/code_model.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs5
-rw-r--r--crates/ra_hir/src/ty/infer.rs5
-rw-r--r--crates/ra_hir/src/ty/infer/expr.rs28
-rw-r--r--crates/ra_hir_def/src/path.rs2
-rw-r--r--crates/ra_ide_api/src/references/classify.rs10
6 files changed, 30 insertions, 22 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 9f06b147c..a98f2f247 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -510,7 +510,7 @@ impl VariantDef {
510 } 510 }
511 } 511 }
512 512
513 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { 513 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
514 match self { 514 match self {
515 VariantDef::Struct(it) => it.field(db, name), 515 VariantDef::Struct(it) => it.field(db, name),
516 VariantDef::EnumVariant(it) => it.field(db, name), 516 VariantDef::EnumVariant(it) => it.field(db, name),
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index cfc4bd326..9e5ce5508 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -216,6 +216,11 @@ impl SourceAnalyzer {
216 self.infer.as_ref()?.field_resolution(expr_id) 216 self.infer.as_ref()?.field_resolution(expr_id)
217 } 217 }
218 218
219 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> {
220 let expr_id = self.expr_id(&field.expr()?)?;
221 self.infer.as_ref()?.record_field_resolution(expr_id)
222 }
223
219 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { 224 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
220 let expr_id = self.expr_id(&record_lit.clone().into())?; 225 let expr_id = self.expr_id(&record_lit.clone().into())?;
221 self.infer.as_ref()?.variant_resolution_for_expr(expr_id) 226 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 2e744e5ec..0a9a83800 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -126,6 +126,8 @@ pub struct InferenceResult {
126 method_resolutions: FxHashMap<ExprId, Function>, 126 method_resolutions: FxHashMap<ExprId, Function>,
127 /// For each field access expr, records the field it resolves to. 127 /// For each field access expr, records the field it resolves to.
128 field_resolutions: FxHashMap<ExprId, StructField>, 128 field_resolutions: FxHashMap<ExprId, StructField>,
129 /// For each field in record literal, records the field it resolves to.
130 record_field_resolutions: FxHashMap<ExprId, StructField>,
129 /// For each struct literal, records the variant it resolves to. 131 /// For each struct literal, records the variant it resolves to.
130 variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>, 132 variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
131 /// For each associated item record what it resolves to 133 /// For each associated item record what it resolves to
@@ -143,6 +145,9 @@ impl InferenceResult {
143 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { 145 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
144 self.field_resolutions.get(&expr).copied() 146 self.field_resolutions.get(&expr).copied()
145 } 147 }
148 pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructField> {
149 self.record_field_resolutions.get(&expr).copied()
150 }
146 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> { 151 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> {
147 self.variant_resolutions.get(&id.into()).copied() 152 self.variant_resolutions.get(&id.into()).copied()
148 } 153 }
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs
index 20a7e9352..2996920c6 100644
--- a/crates/ra_hir/src/ty/infer/expr.rs
+++ b/crates/ra_hir/src/ty/infer/expr.rs
@@ -215,19 +215,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
215 215
216 let substs = ty.substs().unwrap_or_else(Substs::empty); 216 let substs = ty.substs().unwrap_or_else(Substs::empty);
217 for (field_idx, field) in fields.iter().enumerate() { 217 for (field_idx, field) in fields.iter().enumerate() {
218 let field_ty = def_id 218 let field_def = def_id.and_then(|it| match it.field(self.db, &field.name) {
219 .and_then(|it| match it.field(self.db, &field.name) { 219 Some(field) => Some(field),
220 Some(field) => Some(field), 220 None => {
221 None => { 221 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
222 self.push_diagnostic(InferenceDiagnostic::NoSuchField { 222 expr: tgt_expr,
223 expr: tgt_expr, 223 field: field_idx,
224 field: field_idx, 224 });
225 }); 225 None
226 None 226 }
227 } 227 });
228 }) 228 if let Some(field_def) = field_def {
229 .map_or(Ty::Unknown, |field| field.ty(self.db)) 229 self.result.record_field_resolutions.insert(field.expr, field_def);
230 .subst(&substs); 230 }
231 let field_ty =
232 field_def.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
231 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); 233 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
232 } 234 }
233 if let Some(expr) = spread { 235 if let Some(expr) = spread {
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 7b2723d57..0e606fd0e 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -195,7 +195,7 @@ impl Path {
195 } 195 }
196 196
197 /// Converts an `ast::NameRef` into a single-identifier `Path`. 197 /// Converts an `ast::NameRef` into a single-identifier `Path`.
198 pub fn from_name_ref(name_ref: &ast::NameRef) -> Path { 198 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
199 name_ref.as_name().into() 199 name_ref.as_name().into()
200 } 200 }
201 201
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs
index 4a4b030f8..cab06dea9 100644
--- a/crates/ra_ide_api/src/references/classify.rs
+++ b/crates/ra_ide_api/src/references/classify.rs
@@ -1,6 +1,6 @@
1//! Functions that are used to classify an element from its definition or reference. 1//! Functions that are used to classify an element from its definition or reference.
2 2
3use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; 3use hir::{FromSource, Module, ModuleSource, PathResolution, Source, SourceAnalyzer};
4use ra_prof::profile; 4use ra_prof::profile;
5use ra_syntax::{ast, match_ast, AstNode}; 5use ra_syntax::{ast, match_ast, AstNode};
6use test_utils::tested_by; 6use test_utils::tested_by;
@@ -140,12 +140,8 @@ pub(crate) fn classify_name_ref(
140 140
141 if let Some(record_field) = ast::RecordField::cast(parent.clone()) { 141 if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
142 tested_by!(goto_definition_works_for_record_fields); 142 tested_by!(goto_definition_works_for_record_fields);
143 if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) { 143 if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
144 let variant_def = analyzer.resolve_record_literal(&record_lit)?; 144 return Some(from_struct_field(db, field_def));
145 let hir_path = Path::from_name_ref(name_ref.value);
146 let hir_name = hir_path.as_ident()?;
147 let field = variant_def.field(db, hir_name)?;
148 return Some(from_struct_field(db, field));
149 } 145 }
150 } 146 }
151 147