]> git.lizzy.rs Git - rust.git/commitdiff
Resolve field types lazily
authorFlorian Diebold <flodiebold@gmail.com>
Tue, 25 Dec 2018 20:40:33 +0000 (21:40 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Tue, 25 Dec 2018 20:40:33 +0000 (21:40 +0100)
I.e. not already when getting the HIR for the struct.

crates/ra_analysis/src/db.rs
crates/ra_hir/src/adt.rs
crates/ra_hir/src/db.rs
crates/ra_hir/src/mock.rs
crates/ra_hir/src/query_definitions.rs
crates/ra_hir/src/ty.rs
crates/ra_hir/src/type_ref.rs

index 677745d57db73e424e43ffff5d009d3e7a3932f5..036e284bfbb0ff680ba1c5e5de6e7dd3f97b89c4 100644 (file)
@@ -95,6 +95,7 @@ impl hir::db::HirDatabase {
             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;
         }
index dae04d258db4efafc60777e9c8bcc767b3a3e1da..65c461148aa4cdbdad0cd3f1ed16e5acb79a398d 100644 (file)
@@ -5,8 +5,7 @@
 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<StructData> {
+    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<Self> {
+    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::<Cancelable<_>>()?
+                .collect()
         } else {
             Vec::new()
         };
-        Ok(EnumData { name, variants })
+        EnumData { name, variants }
     }
 }
 
@@ -115,15 +106,15 @@ pub(crate) fn new(
 #[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<Self> {
-        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::<Cancelable<_>>()?;
+                    .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::<Cancelable<_>>()?;
+                    .collect();
                 VariantData::Struct(fields)
             }
             StructFlavor::Unit => VariantData::Unit,
-        })
+        }
     }
 
-    pub(crate) fn get_field_ty(&self, field_name: &str) -> Option<Ty> {
+    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] {
index 113790ee9b7e65c51dc2132e20e2825e6391a2b3..e7f9afa77d5ce4a0c31c4603c21365fc335e4549 100644 (file)
@@ -1,6 +1,7 @@
 use std::sync::Arc;
 
 use ra_syntax::{
+    SmolStr,
     SyntaxNode,
     ast::FnDefNode,
 };
@@ -52,6 +53,11 @@ fn type_for_def(def_id: DefId) -> Cancelable<Ty> {
         use fn query_definitions::type_for_def;
     }
 
+    fn type_for_field(def_id: DefId, field: SmolStr) -> Cancelable<Ty> {
+        type TypeForFieldQuery;
+        use fn query_definitions::type_for_field;
+    }
+
     fn file_items(file_id: FileId) -> Arc<SourceFileItems> {
         type SourceFileItemsQuery;
         use fn query_definitions::file_items;
index ead2b8414b3ed084377f252c77282b967ade5d16..f6882cb77198581660b452505f4d64f23c8f1e38 100644 (file)
@@ -193,6 +193,7 @@ impl db::HirDatabase {
             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;
         }
index 405e359f1ce0be41f13a64bf3679c13ee302e9b3..4a7958a1224ef7c16e1b2362fd7ebe1ff42e082f 100644 (file)
@@ -46,18 +46,21 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<T
     ty::type_for_def(db, def_id)
 }
 
+pub(super) fn type_for_field(
+    db: &impl HirDatabase,
+    def_id: DefId,
+    field: SmolStr,
+) -> Cancelable<Ty> {
+    ty::type_for_field(db, def_id, field)
+}
+
 pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
     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<Arc<EnumData>> {
@@ -66,8 +69,7 @@ pub(super) fn enum_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<
     let syntax = db.file_item(def_loc.source_item_id);
     let enum_def =
         ast::EnumDef::cast(syntax.borrowed()).expect("enum def should point to EnumDef node");
-    let module = def_id.module(db)?;
-    Ok(Arc::new(EnumData::new(db, &module, enum_def.borrowed())?))
+    Ok(Arc::new(EnumData::new(enum_def.borrowed())))
 }
 
 pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
index 11b4caa23b44794c0a09677be022532e7c34766c..67b523c2cc507d9b8392790a7b87203515847711 100644 (file)
@@ -309,6 +309,33 @@ pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
     }
 }
 
+pub(super) fn type_for_field(
+    db: &impl HirDatabase,
+    def_id: DefId,
+    field: SmolStr,
+) -> Cancelable<Ty> {
+    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<LocalSyntaxPtr, Ty>,
@@ -540,14 +567,7 @@ fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> {
                             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 {
index ae163313fbe1cdc41c977ceb3c5e318550aca3a9..b36bb35d89414da38b2d83c051d6be82e570541f 100644 (file)
@@ -100,7 +100,7 @@ pub(crate) fn from_ast(node: ast::TypeRef) -> Self {
         }
     }
 
-    fn from_ast_opt(node: Option<ast::TypeRef>) -> Self {
+    pub(crate) fn from_ast_opt(node: Option<ast::TypeRef>) -> Self {
         if let Some(node) = node {
             TypeRef::from_ast(node)
         } else {