From 0044514a4e5fe2484071dc81ae59fc291626c05a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Jan 2019 20:02:53 +0300 Subject: remember where fields resolve to during inference --- crates/ra_hir/src/ty.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index c57e222dd..97a876da8 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -732,8 +732,10 @@ pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { /// The result of type inference: A mapping from expressions and patterns to types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceResult { - /// For each method call expr, record the function it resolved to. + /// For each method call expr, records the function it resolves to. method_resolutions: FxHashMap, + /// For each field access expr, records the field it resolves to. + field_resolutions: FxHashMap, type_of_expr: ArenaMap, type_of_pat: ArenaMap, } @@ -770,6 +772,7 @@ struct InferenceContext<'a, D: HirDatabase> { impl_block: Option, var_unification_table: InPlaceUnificationTable, method_resolutions: FxHashMap, + field_resolutions: FxHashMap, type_of_expr: ArenaMap, type_of_pat: ArenaMap, /// The return type of the function being inferred. @@ -861,6 +864,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ) -> Self { InferenceContext { method_resolutions: FxHashMap::default(), + field_resolutions: FxHashMap::default(), type_of_expr: ArenaMap::default(), type_of_pat: ArenaMap::default(), var_unification_table: InPlaceUnificationTable::new(), @@ -886,6 +890,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } InferenceResult { method_resolutions: mem::replace(&mut self.method_resolutions, Default::default()), + field_resolutions: mem::replace(&mut self.field_resolutions, Default::default()), type_of_expr: expr_types, type_of_pat: pat_types, } @@ -899,6 +904,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.method_resolutions.insert(expr, func); } + fn write_field_resolution(&mut self, expr: ExprId, field: StructField) { + self.field_resolutions.insert(expr, field); + } + fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { self.type_of_pat.insert(pat, ty); } @@ -1251,9 +1260,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } - fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty { + fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem - let ty = match &body[expr] { + let ty = match &body[tgt_expr] { Expr::Missing => Ty::Unknown, Expr::If { condition, @@ -1344,7 +1353,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let resolved = receiver_ty.clone().lookup_method(self.db, method_name); let method_ty = match resolved { Some(func) => { - self.write_method_resolution(expr, func); + self.write_method_resolution(tgt_expr, func); self.db.type_for_def(func.into()) } None => Ty::Unknown, @@ -1389,7 +1398,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { expected.ty } - Expr::Path(p) => self.infer_path_expr(expr, p).unwrap_or(Ty::Unknown), + Expr::Path(p) => self.infer_path_expr(tgt_expr, p).unwrap_or(Ty::Unknown), Expr::Continue => Ty::Never, Expr::Break { expr } => { if let Some(expr) = expr { @@ -1436,9 +1445,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { def_id: AdtDef::Struct(s), ref substs, .. - } => s - .field(self.db, name) - .map(|field| field.ty(self.db).subst(substs)), + } => s.field(self.db, name).map(|field| { + self.write_field_resolution(tgt_expr, field); + field.ty(self.db).subst(substs) + }), _ => None, }) .unwrap_or(Ty::Unknown); @@ -1545,7 +1555,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let ty = self.insert_type_vars_shallow(ty); self.unify(&ty, &expected.ty); let ty = self.resolve_ty_as_possible(ty); - self.write_expr_ty(expr, ty.clone()); + self.write_expr_ty(tgt_expr, ty.clone()); ty } -- cgit v1.2.3 From 9f2574c97e55e2af1d1b93f60307aa9d41f55f42 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Jan 2019 20:32:34 +0300 Subject: add ability to get strcut field source --- crates/ra_hir/src/adt.rs | 70 ++++++++++++++++++++++++++++++++++--- crates/ra_hir/src/code_model_api.rs | 16 +++++++-- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/ty.rs | 27 +++----------- 4 files changed, 84 insertions(+), 31 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index ec6a10353..22bbad964 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -11,7 +11,7 @@ use ra_syntax::{ use crate::{ Name, AsName, Struct, Enum, EnumVariant, Crate, - HirDatabase, HirFileId, + HirDatabase, HirFileId, StructField, FieldSource, type_ref::TypeRef, }; @@ -150,7 +150,7 @@ impl VariantData { impl VariantData { fn new(flavor: StructFlavor) -> Self { let inner = match flavor { - StructFlavor::Tuple(fl) => { + ast::StructFlavor::Tuple(fl) => { let fields = fl .fields() .enumerate() @@ -161,7 +161,7 @@ impl VariantData { .collect(); VariantDataInner::Tuple(fields) } - StructFlavor::Named(fl) => { + ast::StructFlavor::Named(fl) => { let fields = fl .fields() .map(|fd| StructFieldData { @@ -171,8 +171,70 @@ impl VariantData { .collect(); VariantDataInner::Struct(fields) } - StructFlavor::Unit => VariantDataInner::Unit, + ast::StructFlavor::Unit => VariantDataInner::Unit, }; VariantData(inner) } } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum VariantDef { + Struct(Struct), + EnumVariant(EnumVariant), +} +impl_froms!(VariantDef: Struct, EnumVariant); + +impl VariantDef { + pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option { + match self { + VariantDef::Struct(it) => it.field(db, name), + VariantDef::EnumVariant(it) => it.field(db, name), + } + } + pub(crate) fn variant_data(self, db: &impl HirDatabase) -> Arc { + match self { + VariantDef::Struct(it) => it.variant_data(db), + VariantDef::EnumVariant(it) => it.variant_data(db), + } + } +} + +impl StructField { + pub(crate) fn source_impl(&self, db: &impl HirDatabase) -> (HirFileId, FieldSource) { + let var_data = self.parent.variant_data(db); + let fields = var_data.fields().unwrap(); + let ss; + let es; + let (file_id, struct_flavor) = match self.parent { + VariantDef::Struct(s) => { + let (file_id, source) = s.source(db); + ss = source; + (file_id, ss.flavor()) + } + VariantDef::EnumVariant(e) => { + let (file_id, source) = e.source(db); + es = source; + (file_id, es.flavor()) + } + }; + + let field_sources = match struct_flavor { + ast::StructFlavor::Tuple(fl) => fl + .fields() + .map(|it| FieldSource::Pos(it.to_owned())) + .collect(), + ast::StructFlavor::Named(fl) => fl + .fields() + .map(|it| FieldSource::Named(it.to_owned())) + .collect(), + ast::StructFlavor::Unit => Vec::new(), + }; + let field = field_sources + .into_iter() + .zip(fields.iter()) + .find(|(_syntax, (id, _))| *id == self.id) + .unwrap() + .0; + (file_id, field) + } +} diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 118562984..fdea5be57 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -10,8 +10,8 @@ use crate::{ nameres::{ModuleScope, lower::ImportId}, db::HirDatabase, expr::BodySyntaxMapping, - ty::{InferenceResult, VariantDef}, - adt::{EnumVariantId, StructFieldId}, + ty::InferenceResult, + adt::{EnumVariantId, StructFieldId, VariantDef}, generics::GenericParams, docs::{Documentation, Docs, docs_from_ast}, module_tree::ModuleId, @@ -179,10 +179,16 @@ impl Module { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct StructField { - parent: VariantDef, + pub(crate) parent: VariantDef, pub(crate) id: StructFieldId, } +#[derive(Debug)] +pub enum FieldSource { + Named(TreeArc), + Pos(TreeArc), +} + impl StructField { pub fn name(&self, db: &impl HirDatabase) -> Name { self.parent.variant_data(db).fields().unwrap()[self.id] @@ -190,6 +196,10 @@ impl StructField { .clone() } + pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, FieldSource) { + self.source_impl(db) + } + pub fn ty(&self, db: &impl HirDatabase) -> Ty { db.type_for_field(*self) } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 596f9c38c..eaf8565ee 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -68,7 +68,7 @@ pub use self::code_model_api::{ Module, ModuleDef, ModuleSource, Problem, Struct, Enum, EnumVariant, Function, FnSignature, ScopeEntryWithSyntax, - StructField, + StructField, FieldSource, Static, Const, Trait, Type, }; diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 97a876da8..714eaaae5 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -38,7 +38,7 @@ use crate::{ expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, generics::GenericParams, path::GenericArg, - adt::VariantData, + adt::VariantDef, }; /// The ID of a type variable. @@ -696,28 +696,6 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum VariantDef { - Struct(Struct), - EnumVariant(EnumVariant), -} -impl_froms!(VariantDef: Struct, EnumVariant); - -impl VariantDef { - pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option { - match self { - VariantDef::Struct(it) => it.field(db, name), - VariantDef::EnumVariant(it) => it.field(db, name), - } - } - pub(crate) fn variant_data(self, db: &impl HirDatabase) -> Arc { - match self { - VariantDef::Struct(it) => it.variant_data(db), - VariantDef::EnumVariant(it) => it.variant_data(db), - } - } -} - pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { let parent_def = field.parent_def(db); let (generics, module) = match parent_def { @@ -744,6 +722,9 @@ impl InferenceResult { pub fn method_resolution(&self, expr: ExprId) -> Option { self.method_resolutions.get(&expr).map(|it| *it) } + pub fn field_resolution(&self, expr: ExprId) -> Option { + self.field_resolutions.get(&expr).map(|it| *it) + } } impl Index for InferenceResult { -- cgit v1.2.3