mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Don't redo field resolution in the IDE
This commit is contained in:
parent
ac9ba5eb32
commit
63e3ea38d3
6 changed files with 30 additions and 22 deletions
|
@ -510,7 +510,7 @@ impl VariantDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
match self {
|
||||||
VariantDef::Struct(it) => it.field(db, name),
|
VariantDef::Struct(it) => it.field(db, name),
|
||||||
VariantDef::EnumVariant(it) => it.field(db, name),
|
VariantDef::EnumVariant(it) => it.field(db, name),
|
||||||
|
|
|
@ -216,6 +216,11 @@ impl SourceAnalyzer {
|
||||||
self.infer.as_ref()?.field_resolution(expr_id)
|
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> {
|
pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
|
||||||
let expr_id = self.expr_id(&record_lit.clone().into())?;
|
let expr_id = self.expr_id(&record_lit.clone().into())?;
|
||||||
self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
|
self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
|
||||||
|
|
|
@ -126,6 +126,8 @@ pub struct InferenceResult {
|
||||||
method_resolutions: FxHashMap<ExprId, Function>,
|
method_resolutions: FxHashMap<ExprId, Function>,
|
||||||
/// For each field access expr, records the field it resolves to.
|
/// For each field access expr, records the field it resolves to.
|
||||||
field_resolutions: FxHashMap<ExprId, StructField>,
|
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.
|
/// For each struct literal, records the variant it resolves to.
|
||||||
variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
|
variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
|
||||||
/// For each associated item record what it resolves to
|
/// For each associated item record what it resolves to
|
||||||
|
@ -143,6 +145,9 @@ impl InferenceResult {
|
||||||
pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
|
pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
|
||||||
self.field_resolutions.get(&expr).copied()
|
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> {
|
pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> {
|
||||||
self.variant_resolutions.get(&id.into()).copied()
|
self.variant_resolutions.get(&id.into()).copied()
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,8 +215,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
||||||
for (field_idx, field) in fields.iter().enumerate() {
|
for (field_idx, field) in fields.iter().enumerate() {
|
||||||
let field_ty = def_id
|
let field_def = def_id.and_then(|it| match it.field(self.db, &field.name) {
|
||||||
.and_then(|it| match it.field(self.db, &field.name) {
|
|
||||||
Some(field) => Some(field),
|
Some(field) => Some(field),
|
||||||
None => {
|
None => {
|
||||||
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
|
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
|
||||||
|
@ -225,9 +224,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
});
|
});
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.map_or(Ty::Unknown, |field| field.ty(self.db))
|
if let Some(field_def) = field_def {
|
||||||
.subst(&substs);
|
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));
|
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
|
||||||
}
|
}
|
||||||
if let Some(expr) = spread {
|
if let Some(expr) = spread {
|
||||||
|
|
|
@ -195,7 +195,7 @@ impl Path {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an `ast::NameRef` into a single-identifier `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()
|
name_ref.as_name().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Functions that are used to classify an element from its definition or reference.
|
//! 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_prof::profile;
|
||||||
use ra_syntax::{ast, match_ast, AstNode};
|
use ra_syntax::{ast, match_ast, AstNode};
|
||||||
use test_utils::tested_by;
|
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()) {
|
if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
|
||||||
tested_by!(goto_definition_works_for_record_fields);
|
tested_by!(goto_definition_works_for_record_fields);
|
||||||
if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) {
|
if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
|
||||||
let variant_def = analyzer.resolve_record_literal(&record_lit)?;
|
return Some(from_struct_field(db, field_def));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue