]> git.lizzy.rs Git - rust.git/commitdiff
use positional ids for fields
authorAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 25 Jan 2019 11:21:14 +0000 (14:21 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 25 Jan 2019 11:21:14 +0000 (14:21 +0300)
crates/ra_arena/src/lib.rs
crates/ra_hir/src/adt.rs
crates/ra_hir/src/code_model_api.rs
crates/ra_hir/src/db.rs
crates/ra_hir/src/ty.rs
crates/ra_ide_api/src/completion/complete_dot.rs

index d7d5d5265c575dce3f9f7ec2cacf435d4b97d920..97f5548384176e99e510a355454df0c1ac3b185f 100644 (file)
@@ -4,6 +4,7 @@
     fmt,
     marker::PhantomData,
     ops::{Index, IndexMut},
+    iter::FromIterator,
 };
 
 pub mod map;
@@ -109,3 +110,15 @@ fn index_mut(&mut self, idx: ID) -> &mut T {
         &mut self.data[idx]
     }
 }
+
+impl<ID: ArenaId, T> FromIterator<T> for Arena<ID, T> {
+    fn from_iter<I>(iter: I) -> Self
+    where
+        I: IntoIterator<Item = T>,
+    {
+        Arena {
+            data: Vec::from_iter(iter),
+            _ty: PhantomData,
+        }
+    }
+}
index 2579ece199ce9a206f754ee3ae78b012b154d723..df609b8d73abb596cd9a6e931577ad041a97753b 100644 (file)
@@ -79,12 +79,13 @@ pub(crate) fn source_impl(
             .to_owned();
         (file_id, var)
     }
+    pub(crate) fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> {
+        db.enum_data(self.parent).variants[self.id]
+            .variant_data
+            .clone()
+    }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) struct EnumVariantId(RawId);
-impl_arena_id!(EnumVariantId);
-
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct EnumData {
     pub(crate) name: Option<Name>,
@@ -94,28 +95,31 @@ pub struct EnumData {
 impl EnumData {
     pub(crate) fn enum_data_query(db: &impl HirDatabase, e: Enum) -> Arc<EnumData> {
         let (_file_id, enum_def) = e.source(db);
-        let mut res = EnumData {
-            name: enum_def.name().map(|n| n.as_name()),
-            variants: Arena::default(),
-        };
-        for var in variants(&*enum_def) {
-            let data = EnumVariantData {
+        let name = enum_def.name().map(|n| n.as_name());
+        let variants = variants(&*enum_def)
+            .map(|var| EnumVariantData {
                 name: var.name().map(|it| it.as_name()),
                 variant_data: Arc::new(VariantData::new(var.flavor())),
-            };
-            res.variants.alloc(data);
-        }
-
-        Arc::new(res)
+            })
+            .collect();
+        Arc::new(EnumData { name, variants })
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct EnumVariantId(RawId);
+impl_arena_id!(EnumVariantId);
+
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct EnumVariantData {
     pub(crate) name: Option<Name>,
     pub(crate) variant_data: Arc<VariantData>,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct StructFieldId(RawId);
+impl_arena_id!(StructFieldId);
+
 /// A single field of an enum variant or struct
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct StructFieldData {
@@ -125,45 +129,27 @@ pub struct StructFieldData {
 
 /// Fields of an enum variant or struct
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub enum VariantData {
-    Struct(Vec<StructFieldData>),
-    Tuple(Vec<StructFieldData>),
+pub struct VariantData(VariantDataInner);
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum VariantDataInner {
+    Struct(Arena<StructFieldId, StructFieldData>),
+    Tuple(Arena<StructFieldId, StructFieldData>),
     Unit,
 }
 
 impl VariantData {
-    pub fn fields(&self) -> &[StructFieldData] {
-        match self {
-            VariantData::Struct(fields) | VariantData::Tuple(fields) => fields,
-            _ => &[],
-        }
-    }
-
-    pub fn is_struct(&self) -> bool {
-        match self {
-            VariantData::Struct(..) => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_tuple(&self) -> bool {
-        match self {
-            VariantData::Tuple(..) => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_unit(&self) -> bool {
-        match self {
-            VariantData::Unit => true,
-            _ => false,
+    pub(crate) fn fields(&self) -> Option<&Arena<StructFieldId, StructFieldData>> {
+        match &self.0 {
+            VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields),
+            _ => None,
         }
     }
 }
 
 impl VariantData {
     fn new(flavor: StructFlavor) -> Self {
-        match flavor {
+        let inner = match flavor {
             StructFlavor::Tuple(fl) => {
                 let fields = fl
                     .fields()
@@ -173,7 +159,7 @@ fn new(flavor: StructFlavor) -> Self {
                         type_ref: TypeRef::from_ast_opt(fd.type_ref()),
                     })
                     .collect();
-                VariantData::Tuple(fields)
+                VariantDataInner::Tuple(fields)
             }
             StructFlavor::Named(fl) => {
                 let fields = fl
@@ -183,16 +169,17 @@ fn new(flavor: StructFlavor) -> Self {
                         type_ref: TypeRef::from_ast_opt(fd.type_ref()),
                     })
                     .collect();
-                VariantData::Struct(fields)
+                VariantDataInner::Struct(fields)
             }
-            StructFlavor::Unit => VariantData::Unit,
-        }
+            StructFlavor::Unit => VariantDataInner::Unit,
+        };
+        VariantData(inner)
     }
 
-    pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
-        self.fields()
-            .iter()
-            .find(|f| f.name == *field_name)
-            .map(|f| &f.type_ref)
-    }
+    // pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
+    //     self.fields()
+    //         .iter()
+    //         .find(|f| f.name == *field_name)
+    //         .map(|f| &f.type_ref)
+    // }
 }
index 249a4aba993243fc43b62b4d1a3c77ed56eeacb5..118562984d37ec7ea422f5fdb70be248ef096c88 100644 (file)
@@ -11,7 +11,7 @@
     db::HirDatabase,
     expr::BodySyntaxMapping,
     ty::{InferenceResult, VariantDef},
-    adt::{VariantData, EnumVariantId},
+    adt::{EnumVariantId, StructFieldId},
     generics::GenericParams,
     docs::{Documentation, Docs, docs_from_ast},
     module_tree::ModuleId,
@@ -177,19 +177,25 @@ pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Probl
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct StructField {
     parent: VariantDef,
-    name: Name,
+    pub(crate) id: StructFieldId,
 }
 
 impl StructField {
-    pub fn name(&self) -> &Name {
-        &self.name
+    pub fn name(&self, db: &impl HirDatabase) -> Name {
+        self.parent.variant_data(db).fields().unwrap()[self.id]
+            .name
+            .clone()
     }
 
-    pub fn ty(&self, db: &impl HirDatabase) -> Option<Ty> {
-        db.type_for_field(self.parent, self.name.clone())
+    pub fn ty(&self, db: &impl HirDatabase) -> Ty {
+        db.type_for_field(*self)
+    }
+
+    pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
+        self.parent
     }
 }
 
@@ -215,14 +221,28 @@ pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> {
         db.struct_data(*self)
             .variant_data
             .fields()
-            .iter()
-            .map(|it| StructField {
+            .into_iter()
+            .flat_map(|it| it.iter())
+            .map(|(id, _)| StructField {
                 parent: (*self).into(),
-                name: it.name.clone(),
+                id,
             })
             .collect()
     }
 
+    pub fn field(&self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
+        db.struct_data(*self)
+            .variant_data
+            .fields()
+            .into_iter()
+            .flat_map(|it| it.iter())
+            .find(|(_id, data)| data.name == *name)
+            .map(|(id, _)| StructField {
+                parent: (*self).into(),
+                id,
+            })
+    }
+
     pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
         db.generic_params((*self).into())
     }
@@ -300,22 +320,29 @@ pub fn name(&self, db: &impl HirDatabase) -> Option<Name> {
         db.enum_data(self.parent).variants[self.id].name.clone()
     }
 
-    pub fn variant_data(&self, db: &impl HirDatabase) -> Arc<VariantData> {
-        db.enum_data(self.parent).variants[self.id]
-            .variant_data
-            .clone()
-    }
-
     pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> {
         self.variant_data(db)
             .fields()
-            .iter()
-            .map(|it| StructField {
+            .into_iter()
+            .flat_map(|it| it.iter())
+            .map(|(id, _)| StructField {
                 parent: (*self).into(),
-                name: it.name.clone(),
+                id,
             })
             .collect()
     }
+
+    pub fn field(&self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
+        self.variant_data(db)
+            .fields()
+            .into_iter()
+            .flat_map(|it| it.iter())
+            .find(|(_id, data)| data.name == *name)
+            .map(|(id, _)| StructField {
+                parent: (*self).into(),
+                id,
+            })
+    }
 }
 
 impl Docs for EnumVariant {
index 5a29e54d649f296c8002eb46915de5e2dcd2f498..3c82262a28b818bb4484ee919bf037646f64fbce 100644 (file)
@@ -4,15 +4,15 @@
 use ra_db::{SyntaxDatabase, CrateId, salsa};
 
 use crate::{
-    MacroCallId, Name, HirFileId,
+    MacroCallId, HirFileId,
     SourceFileItems, SourceItemId, Crate, Module, HirInterner,
     query_definitions,
     Function, FnSignature, FnScopes,
-    Struct, Enum,
+    Struct, Enum, StructField,
     macros::MacroExpansion,
     module_tree::ModuleTree,
     nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
-    ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, VariantDef},
+    ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
     adt::{StructData, EnumData},
     impl_block::ModuleImplBlocks,
     generics::{GenericParams, GenericDef},
@@ -42,7 +42,7 @@ pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> {
     fn type_for_def(&self, def: TypableDef) -> Ty;
 
     #[salsa::invoke(crate::ty::type_for_field)]
-    fn type_for_field(&self, def: VariantDef, field: Name) -> Option<Ty>;
+    fn type_for_field(&self, field: StructField) -> Ty;
 
     #[salsa::invoke(query_definitions::file_items)]
     fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;
index c7f77e7a3986ef83728cade3d89e05e9763ed476..c57e222ddddf7b6b4ed65ac601fd0a1b15133b19 100644 (file)
@@ -38,6 +38,7 @@
     expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
     generics::GenericParams,
     path::GenericArg,
+    adt::VariantData,
 };
 
 /// The ID of a type variable.
@@ -702,19 +703,30 @@ pub enum VariantDef {
 }
 impl_froms!(VariantDef: Struct, EnumVariant);
 
-pub(super) fn type_for_field(db: &impl HirDatabase, def: VariantDef, field: Name) -> Option<Ty> {
-    let (variant_data, generics, module) = match def {
-        VariantDef::Struct(s) => (s.variant_data(db), s.generic_params(db), s.module(db)),
-        VariantDef::EnumVariant(var) => (
-            var.variant_data(db),
-            var.parent_enum(db).generic_params(db),
-            var.module(db),
-        ),
+impl VariantDef {
+    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),
+        }
+    }
+    pub(crate) fn variant_data(self, db: &impl HirDatabase) -> Arc<VariantData> {
+        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 {
+        VariantDef::Struct(it) => (it.generic_params(db), it.module(db)),
+        VariantDef::EnumVariant(it) => (it.parent_enum(db).generic_params(db), it.module(db)),
     };
-    // We can't have an impl block ere, right?
-    // let impl_block = def_id.impl_block(db);
-    let type_ref = variant_data.get_field_type_ref(&field)?;
-    Some(Ty::from_hir(db, &module, None, &generics, &type_ref))
+    let var_data = parent_def.variant_data(db);
+    let type_ref = &var_data.fields().unwrap()[field.id].type_ref;
+    Ty::from_hir(db, &module, None, &generics, type_ref)
 }
 
 /// The result of type inference: A mapping from expressions and patterns to types.
@@ -1122,39 +1134,22 @@ fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) {
         }
     }
 
-    fn resolve_fields(&mut self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> {
-        let (ty, def) = self.resolve_variant(path);
-        match def? {
-            VariantDef::Struct(s) => {
-                let fields = s.fields(self.db);
-                Some((ty, fields))
-            }
-            VariantDef::EnumVariant(var) => {
-                let fields = var.fields(self.db);
-                Some((ty, fields))
-            }
-        }
-    }
-
     fn infer_tuple_struct_pat(
         &mut self,
         path: Option<&Path>,
         subpats: &[PatId],
         expected: &Ty,
     ) -> Ty {
-        let (ty, fields) = self
-            .resolve_fields(path)
-            .unwrap_or((Ty::Unknown, Vec::new()));
+        let (ty, def) = self.resolve_variant(path);
 
         self.unify(&ty, expected);
 
         let substs = ty.substs().unwrap_or_else(Substs::empty);
 
         for (i, &subpat) in subpats.iter().enumerate() {
-            let expected_ty = fields
-                .get(i)
-                .and_then(|field| field.ty(self.db))
-                .unwrap_or(Ty::Unknown)
+            let expected_ty = def
+                .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
+                .map_or(Ty::Unknown, |field| field.ty(self.db))
                 .subst(&substs);
             self.infer_pat(subpat, &expected_ty);
         }
@@ -1163,19 +1158,16 @@ fn infer_tuple_struct_pat(
     }
 
     fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty {
-        let (ty, fields) = self
-            .resolve_fields(path)
-            .unwrap_or((Ty::Unknown, Vec::new()));
+        let (ty, def) = self.resolve_variant(path);
 
         self.unify(&ty, expected);
 
         let substs = ty.substs().unwrap_or_else(Substs::empty);
 
         for subpat in subpats {
-            let matching_field = fields.iter().find(|field| field.name() == &subpat.name);
+            let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
             let expected_ty = matching_field
-                .and_then(|field| field.ty(self.db))
-                .unwrap_or(Ty::Unknown)
+                .map_or(Ty::Unknown, |field| field.ty(self.db))
                 .subst(&substs);
             self.infer_pat(subpat.pat, &expected_ty);
         }
@@ -1420,14 +1412,10 @@ fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
                 let (ty, def_id) = self.resolve_variant(path.as_ref());
                 let substs = ty.substs().unwrap_or_else(Substs::empty);
                 for field in fields {
-                    let field_ty = if let Some(def_id) = def_id {
-                        self.db
-                            .type_for_field(def_id.into(), field.name.clone())
-                            .unwrap_or(Ty::Unknown)
-                            .subst(&substs)
-                    } else {
-                        Ty::Unknown
-                    };
+                    let field_ty = def_id
+                        .and_then(|it| it.field(self.db, &field.name))
+                        .map_or(Ty::Unknown, |field| field.ty(self.db))
+                        .subst(&substs);
                     self.infer_expr(field.expr, &Expectation::has_type(field_ty));
                 }
                 if let Some(expr) = spread {
@@ -1440,7 +1428,6 @@ fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
                 let ty = receiver_ty
                     .autoderef(self.db)
                     .find_map(|derefed_ty| match derefed_ty {
-                        // this is more complicated than necessary because type_for_field is cancelable
                         Ty::Tuple(fields) => {
                             let i = name.to_string().parse::<usize>().ok();
                             i.and_then(|i| fields.get(i).cloned())
@@ -1449,10 +1436,9 @@ fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
                             def_id: AdtDef::Struct(s),
                             ref substs,
                             ..
-                        } => self
-                            .db
-                            .type_for_field(s.into(), name.clone())
-                            .map(|ty| ty.subst(substs)),
+                        } => s
+                            .field(self.db, name)
+                            .map(|field| field.ty(self.db).subst(substs)),
                         _ => None,
                     })
                     .unwrap_or(Ty::Unknown);
index 6a9358d333317bf1a5dccd7cb71d7fa08263d185..060a46c5e0b05a31d20efdbd7e18cb2042c75b5f 100644 (file)
@@ -34,10 +34,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
                             CompletionItem::new(
                                 CompletionKind::Reference,
                                 ctx.source_range(),
-                                field.name().to_string(),
+                                field.name(ctx.db).to_string(),
                             )
                             .kind(CompletionItemKind::Field)
-                            .set_detail(field.ty(ctx.db).map(|ty| ty.subst(substs).to_string()))
+                            .detail(field.ty(ctx.db).subst(substs).to_string())
                             .add_to(acc);
                         }
                     }