diff options
author | Aleksey Kladov <[email protected]> | 2019-11-24 17:06:55 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-11-24 17:06:55 +0000 |
commit | 63e3ea38d3ff7ab69b968e8962f33e82a4f978fb (patch) | |
tree | 8f4d416bad74f75e43924981b1d2c2099ea50edc /crates | |
parent | ac9ba5eb32073c16608acaa04324e7dc46d303d6 (diff) |
Don't redo field resolution in the IDE
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/expr.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references/classify.rs | 10 |
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 | ||
3 | use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; | 3 | use hir::{FromSource, Module, ModuleSource, PathResolution, Source, SourceAnalyzer}; |
4 | use ra_prof::profile; | 4 | use ra_prof::profile; |
5 | use ra_syntax::{ast, match_ast, AstNode}; | 5 | use ra_syntax::{ast, match_ast, AstNode}; |
6 | use test_utils::tested_by; | 6 | use 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 | ||