2389: Don't redo field resolution in the IDE r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2019-11-24 17:08:16 +00:00 committed by GitHub
commit a58db5712f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 30 additions and 22 deletions

View File

@ -510,7 +510,7 @@ pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
}
}
pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
match self {
VariantDef::Struct(it) => it.field(db, name),
VariantDef::EnumVariant(it) => it.field(db, name),

View File

@ -216,6 +216,11 @@ pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField
self.infer.as_ref()?.field_resolution(expr_id)
}
pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> {
let expr_id = self.expr_id(&field.expr()?)?;
self.infer.as_ref()?.record_field_resolution(expr_id)
}
pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
let expr_id = self.expr_id(&record_lit.clone().into())?;
self.infer.as_ref()?.variant_resolution_for_expr(expr_id)

View File

@ -126,6 +126,8 @@ pub struct InferenceResult {
method_resolutions: FxHashMap<ExprId, Function>,
/// For each field access expr, records the field it resolves to.
field_resolutions: FxHashMap<ExprId, StructField>,
/// For each field in record literal, records the field it resolves to.
record_field_resolutions: FxHashMap<ExprId, StructField>,
/// For each struct literal, records the variant it resolves to.
variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
/// For each associated item record what it resolves to
@ -143,6 +145,9 @@ pub fn method_resolution(&self, expr: ExprId) -> Option<Function> {
pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
self.field_resolutions.get(&expr).copied()
}
pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructField> {
self.record_field_resolutions.get(&expr).copied()
}
pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> {
self.variant_resolutions.get(&id.into()).copied()
}

View File

@ -215,19 +215,21 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
let substs = ty.substs().unwrap_or_else(Substs::empty);
for (field_idx, field) in fields.iter().enumerate() {
let field_ty = def_id
.and_then(|it| match it.field(self.db, &field.name) {
Some(field) => Some(field),
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
expr: tgt_expr,
field: field_idx,
});
None
}
})
.map_or(Ty::Unknown, |field| field.ty(self.db))
.subst(&substs);
let field_def = def_id.and_then(|it| match it.field(self.db, &field.name) {
Some(field) => Some(field),
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
expr: tgt_expr,
field: field_idx,
});
None
}
});
if let Some(field_def) = field_def {
self.result.record_field_resolutions.insert(field.expr, field_def);
}
let field_ty =
field_def.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
}
if let Some(expr) = spread {

View File

@ -195,7 +195,7 @@ fn qualifier(path: &ast::Path) -> Option<ast::Path> {
}
/// Converts an `ast::NameRef` into a single-identifier `Path`.
pub fn from_name_ref(name_ref: &ast::NameRef) -> Path {
pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
name_ref.as_name().into()
}

View File

@ -1,6 +1,6 @@
//! Functions that are used to classify an element from its definition or reference.
use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer};
use hir::{FromSource, Module, ModuleSource, PathResolution, Source, SourceAnalyzer};
use ra_prof::profile;
use ra_syntax::{ast, match_ast, AstNode};
use test_utils::tested_by;
@ -140,12 +140,8 @@ pub(crate) fn classify_name_ref(
if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
tested_by!(goto_definition_works_for_record_fields);
if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) {
let variant_def = analyzer.resolve_record_literal(&record_lit)?;
let hir_path = Path::from_name_ref(name_ref.value);
let hir_name = hir_path.as_ident()?;
let field = variant_def.field(db, hir_name)?;
return Some(from_struct_field(db, field));
if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
return Some(from_struct_field(db, field_def));
}
}