From bc745a139674f289386f3081458793f756cab5b9 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 25 Dec 2018 21:40:33 +0100 Subject: Resolve field types lazily I.e. not already when getting the HIR for the struct. --- crates/ra_analysis/src/db.rs | 1 + crates/ra_hir/src/adt.rs | 71 ++++++++++++++-------------------- crates/ra_hir/src/db.rs | 6 +++ crates/ra_hir/src/mock.rs | 1 + crates/ra_hir/src/query_definitions.rs | 18 +++++---- crates/ra_hir/src/ty.rs | 36 +++++++++++++---- crates/ra_hir/src/type_ref.rs | 2 +- 7 files changed, 76 insertions(+), 59 deletions(-) diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index 677745d57..036e284bf 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs @@ -95,6 +95,7 @@ salsa::database_storage! { fn submodules() for hir::db::SubmodulesQuery; fn infer() for hir::db::InferQuery; fn type_for_def() for hir::db::TypeForDefQuery; + fn type_for_field() for hir::db::TypeForFieldQuery; fn struct_data() for hir::db::StructDataQuery; fn enum_data() for hir::db::EnumDataQuery; } diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index dae04d258..65c461148 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -5,8 +5,7 @@ use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}}; use crate::{ DefId, Cancelable, db::{HirDatabase}, - module::Module, - ty::{Ty}, + type_ref::TypeRef, }; pub struct Struct { @@ -42,15 +41,11 @@ pub struct StructData { } impl StructData { - pub(crate) fn new( - db: &impl HirDatabase, - module: &Module, - struct_def: ast::StructDef, - ) -> Cancelable { + pub(crate) fn new(struct_def: ast::StructDef) -> StructData { let name = struct_def.name().map(|n| n.text()); - let variant_data = VariantData::new(db, module, struct_def.flavor())?; + let variant_data = VariantData::new(struct_def.flavor()); let variant_data = Arc::new(variant_data); - Ok(StructData { name, variant_data }) + StructData { name, variant_data } } pub fn name(&self) -> Option<&SmolStr> { @@ -87,27 +82,23 @@ pub struct EnumData { } impl EnumData { - pub(crate) fn new( - db: &impl HirDatabase, - module: &Module, - enum_def: ast::EnumDef, - ) -> Cancelable { + pub(crate) fn new(enum_def: ast::EnumDef) -> Self { let name = enum_def.name().map(|n| n.text()); let variants = if let Some(evl) = enum_def.variant_list() { evl.variants() .map(|v| { - Ok(( + ( v.name() .map(|n| n.text()) .unwrap_or_else(|| SmolStr::new("[error]")), - Arc::new(VariantData::new(db, module, v.flavor())?), - )) + Arc::new(VariantData::new(v.flavor())), + ) }) - .collect::>()? + .collect() } else { Vec::new() }; - Ok(EnumData { name, variants }) + EnumData { name, variants } } } @@ -115,15 +106,15 @@ impl EnumData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructField { name: SmolStr, - ty: Ty, + type_ref: TypeRef, } impl StructField { pub fn name(&self) -> SmolStr { self.name.clone() } - pub fn ty(&self) -> Ty { - self.ty.clone() + pub fn type_ref(&self) -> &TypeRef { + &self.type_ref } } @@ -136,45 +127,41 @@ pub enum VariantData { } impl VariantData { - pub fn new(db: &impl HirDatabase, module: &Module, flavor: StructFlavor) -> Cancelable { - Ok(match flavor { + pub fn new(flavor: StructFlavor) -> Self { + match flavor { StructFlavor::Tuple(fl) => { let fields = fl .fields() .enumerate() - .map(|(i, fd)| { - Ok(StructField { - name: SmolStr::new(i.to_string()), - ty: Ty::from_ast_opt(db, &module, fd.type_ref())?, - }) + .map(|(i, fd)| StructField { + name: SmolStr::new(i.to_string()), + type_ref: TypeRef::from_ast_opt(fd.type_ref()), }) - .collect::>()?; + .collect(); VariantData::Tuple(fields) } StructFlavor::Named(fl) => { let fields = fl .fields() - .map(|fd| { - Ok(StructField { - name: fd - .name() - .map(|n| n.text()) - .unwrap_or_else(|| SmolStr::new("[error]")), - ty: Ty::from_ast_opt(db, &module, fd.type_ref())?, - }) + .map(|fd| StructField { + name: fd + .name() + .map(|n| n.text()) + .unwrap_or_else(|| SmolStr::new("[error]")), + type_ref: TypeRef::from_ast_opt(fd.type_ref()), }) - .collect::>()?; + .collect(); VariantData::Struct(fields) } StructFlavor::Unit => VariantData::Unit, - }) + } } - pub(crate) fn get_field_ty(&self, field_name: &str) -> Option { + pub(crate) fn get_field_type_ref(&self, field_name: &str) -> Option<&TypeRef> { self.fields() .iter() .find(|f| f.name == field_name) - .map(|f| f.ty.clone()) + .map(|f| &f.type_ref) } pub fn fields(&self) -> &[StructField] { diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 113790ee9..e7f9afa77 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use ra_syntax::{ + SmolStr, SyntaxNode, ast::FnDefNode, }; @@ -52,6 +53,11 @@ pub trait HirDatabase: SyntaxDatabase use fn query_definitions::type_for_def; } + fn type_for_field(def_id: DefId, field: SmolStr) -> Cancelable { + type TypeForFieldQuery; + use fn query_definitions::type_for_field; + } + fn file_items(file_id: FileId) -> Arc { type SourceFileItemsQuery; use fn query_definitions::file_items; diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index ead2b8414..f6882cb77 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -193,6 +193,7 @@ salsa::database_storage! { fn submodules() for db::SubmodulesQuery; fn infer() for db::InferQuery; fn type_for_def() for db::TypeForDefQuery; + fn type_for_field() for db::TypeForFieldQuery; fn struct_data() for db::StructDataQuery; fn enum_data() for db::EnumDataQuery; } diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index 405e359f1..4a7958a12 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs @@ -46,18 +46,21 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable Cancelable { + ty::type_for_field(db, def_id, field) +} + pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable> { let def_loc = def_id.loc(db); assert!(def_loc.kind == DefKind::Struct); let syntax = db.file_item(def_loc.source_item_id); let struct_def = ast::StructDef::cast(syntax.borrowed()).expect("struct def should point to StructDef node"); - let module = def_id.module(db)?; - Ok(Arc::new(StructData::new( - db, - &module, - struct_def.borrowed(), - )?)) + Ok(Arc::new(StructData::new(struct_def.borrowed()))) } pub(super) fn enum_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable> { @@ -66,8 +69,7 @@ pub(super) fn enum_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable Arc { diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 11b4caa23..67b523c2c 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -309,6 +309,33 @@ pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable { } } +pub(super) fn type_for_field( + db: &impl HirDatabase, + def_id: DefId, + field: SmolStr, +) -> Cancelable { + let def = def_id.resolve(db)?; + let variant_data = match def { + Def::Struct(s) => { + let variant_data = s.variant_data(db)?; + variant_data + } + // TODO: unions + // TODO: enum variants + _ => panic!( + "trying to get type for field in non-struct/variant {:?}", + def_id + ), + }; + let module = def_id.module(db)?; + let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) { + tr + } else { + return Ok(Ty::Unknown); + }; + Ty::from_hir(db, &module, &type_ref) +} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceResult { type_of: FxHashMap, @@ -540,14 +567,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { i.and_then(|i| fields.get(i).cloned()) .unwrap_or(Ty::Unknown) } - Ty::Adt { def_id, .. } => { - let field_ty = match def_id.resolve(self.db)? { - Def::Struct(s) => s.variant_data(self.db)?.get_field_ty(&text), - // TODO unions - _ => None, - }; - field_ty.unwrap_or(Ty::Unknown) - } + Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, text)?, _ => Ty::Unknown, } } else { diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs index ae163313f..b36bb35d8 100644 --- a/crates/ra_hir/src/type_ref.rs +++ b/crates/ra_hir/src/type_ref.rs @@ -100,7 +100,7 @@ impl TypeRef { } } - fn from_ast_opt(node: Option) -> Self { + pub(crate) fn from_ast_opt(node: Option) -> Self { if let Some(node) = node { TypeRef::from_ast(node) } else { -- cgit v1.2.3