Merge #2389
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:
commit
a58db5712f
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user