From a443b5033c2e95ee58bf086f7093ddc610d4f78f Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Tue, 26 Nov 2019 14:29:12 +0300
Subject: [PATCH] Id-ify Ty::Adt

---
 crates/ra_hir/src/code_model.rs               | 54 +++++++++++++++----
 crates/ra_hir/src/expr.rs                     |  4 +-
 crates/ra_hir/src/from_id.rs                  | 17 ++++++
 crates/ra_hir/src/ty.rs                       | 12 ++---
 crates/ra_hir/src/ty/infer.rs                 |  4 +-
 crates/ra_hir/src/ty/infer/coerce.rs          | 12 ++---
 crates/ra_hir/src/ty/infer/expr.rs            | 21 ++++----
 crates/ra_hir/src/ty/lower.rs                 |  2 +-
 crates/ra_hir/src/ty/method_resolution.rs     |  6 ++-
 crates/ra_hir_def/src/adt.rs                  |  4 ++
 .../src/references/name_definition.rs         |  1 +
 11 files changed, 98 insertions(+), 39 deletions(-)

diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index a7bba85e14f..bb1596bed0a 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -11,9 +11,9 @@ use hir_def::{
     per_ns::PerNs,
     resolver::{HasResolver, TypeNs},
     type_ref::{Mutability, TypeRef},
-    AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
-    ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId,
-    StaticId, StructId, TraitId, TypeAliasId, UnionId,
+    AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId,
+    HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId,
+    Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
 };
 use hir_expand::{
     diagnostics::DiagnosticSink,
@@ -383,6 +383,28 @@ impl Union {
     pub fn ty(self, db: &impl HirDatabase) -> Ty {
         db.type_for_def(self.into(), Namespace::Types)
     }
+
+    pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
+        db.union_data(self.id)
+            .variant_data
+            .fields()
+            .iter()
+            .map(|(id, _)| StructField { parent: self.into(), id })
+            .collect()
+    }
+
+    pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
+        db.union_data(self.id)
+            .variant_data
+            .fields()
+            .iter()
+            .find(|(_id, data)| data.name == *name)
+            .map(|(id, _)| StructField { parent: self.into(), id })
+    }
+
+    fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
+        db.union_data(self.id).variant_data.clone()
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -501,14 +523,16 @@ impl Adt {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub enum VariantDef {
     Struct(Struct),
+    Union(Union),
     EnumVariant(EnumVariant),
 }
-impl_froms!(VariantDef: Struct, EnumVariant);
+impl_froms!(VariantDef: Struct, Union, EnumVariant);
 
 impl VariantDef {
     pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
         match self {
             VariantDef::Struct(it) => it.fields(db),
+            VariantDef::Union(it) => it.fields(db),
             VariantDef::EnumVariant(it) => it.fields(db),
         }
     }
@@ -516,6 +540,7 @@ impl VariantDef {
     pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
         match self {
             VariantDef::Struct(it) => it.field(db, name),
+            VariantDef::Union(it) => it.field(db, name),
             VariantDef::EnumVariant(it) => it.field(db, name),
         }
     }
@@ -523,6 +548,7 @@ impl VariantDef {
     pub fn module(self, db: &impl HirDatabase) -> Module {
         match self {
             VariantDef::Struct(it) => it.module(db),
+            VariantDef::Union(it) => it.module(db),
             VariantDef::EnumVariant(it) => it.module(db),
         }
     }
@@ -530,6 +556,7 @@ impl VariantDef {
     pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
         match self {
             VariantDef::Struct(it) => it.variant_data(db),
+            VariantDef::Union(it) => it.variant_data(db),
             VariantDef::EnumVariant(it) => it.variant_data(db),
         }
     }
@@ -1056,19 +1083,24 @@ impl Type {
     }
 
     pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> {
-        let mut res = Vec::new();
         if let Ty::Apply(a_ty) = &self.ty.value {
             match a_ty.ctor {
-                ty::TypeCtor::Adt(Adt::Struct(s)) => {
-                    for field in s.fields(db) {
-                        let ty = field.ty(db).subst(&a_ty.parameters);
-                        res.push((field, self.derived(ty)));
-                    }
+                ty::TypeCtor::Adt(AdtId::StructId(s)) => {
+                    let var_def = s.into();
+                    return db
+                        .field_types(var_def)
+                        .iter()
+                        .map(|(local_id, ty)| {
+                            let def = StructField { parent: var_def.into(), id: local_id };
+                            let ty = ty.clone().subst(&a_ty.parameters);
+                            (def, self.derived(ty))
+                        })
+                        .collect();
                 }
                 _ => {}
             }
         };
-        res
+        Vec::new()
     }
 
     pub fn tuple_fields(&self, _db: &impl HirDatabase) -> Vec<Type> {
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 43fedde7aa0..adb9805ab8f 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -2,7 +2,7 @@
 
 use std::sync::Arc;
 
-use hir_def::{path::known, resolver::HasResolver};
+use hir_def::{path::known, resolver::HasResolver, AdtId};
 use hir_expand::diagnostics::DiagnosticSink;
 use ra_syntax::ast;
 use ra_syntax::AstPtr;
@@ -127,7 +127,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
             _ => return,
         };
 
-        let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum.into()));
+        let std_result_ctor = TypeCtor::Adt(AdtId::EnumId(std_result_enum));
         let params = match &mismatch.expected {
             Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
             _ => return,
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
index 619f6055e1a..38daa5e59ff 100644
--- a/crates/ra_hir/src/from_id.rs
+++ b/crates/ra_hir/src/from_id.rs
@@ -199,11 +199,22 @@ impl From<Adt> for GenericDefId {
     }
 }
 
+impl From<VariantId> for VariantDef {
+    fn from(def: VariantId) -> Self {
+        match def {
+            VariantId::StructId(it) => VariantDef::Struct(it.into()),
+            VariantId::EnumVariantId(it) => VariantDef::EnumVariant(it.into()),
+            VariantId::UnionId(it) => VariantDef::Union(it.into()),
+        }
+    }
+}
+
 impl From<VariantDef> for VariantId {
     fn from(def: VariantDef) -> Self {
         match def {
             VariantDef::Struct(it) => VariantId::StructId(it.id),
             VariantDef::EnumVariant(it) => VariantId::EnumVariantId(it.into()),
+            VariantDef::Union(it) => VariantId::UnionId(it.id),
         }
     }
 }
@@ -214,6 +225,12 @@ impl From<StructField> for StructFieldId {
     }
 }
 
+impl From<StructFieldId> for StructField {
+    fn from(def: StructFieldId) -> Self {
+        StructField { parent: def.parent.into(), id: def.local_id }
+    }
+}
+
 impl From<AttrDef> for AttrDefId {
     fn from(def: AttrDef) -> Self {
         match def {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 388530f3106..bd03055b939 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -58,7 +58,7 @@ pub enum TypeCtor {
     Float(Uncertain<FloatTy>),
 
     /// Structures, enumerations and unions.
-    Adt(Adt),
+    Adt(AdtId),
 
     /// The pointee of a string slice. Written as `str`.
     Str,
@@ -174,7 +174,7 @@ impl TypeCtor {
             | TypeCtor::Tuple { .. } => None,
             // Closure's krate is irrelevant for coherence I would think?
             TypeCtor::Closure { .. } => None,
-            TypeCtor::Adt(adt) => adt.krate(db),
+            TypeCtor::Adt(adt) => Some(adt.module(db).krate.into()),
             TypeCtor::FnDef(callable) => Some(callable.krate(db).into()),
             TypeCtor::AssociatedType(type_alias) => {
                 Some(type_alias.lookup(db).module(db).krate.into())
@@ -598,7 +598,7 @@ impl Ty {
     pub fn as_adt(&self) -> Option<(Adt, &Substs)> {
         match self {
             Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => {
-                Some((*adt_def, parameters))
+                Some(((*adt_def).into(), parameters))
             }
             _ => None,
         }
@@ -889,9 +889,9 @@ impl HirDisplay for ApplicationTy {
             }
             TypeCtor::Adt(def_id) => {
                 let name = match def_id {
-                    Adt::Struct(s) => s.name(f.db),
-                    Adt::Union(u) => u.name(f.db),
-                    Adt::Enum(e) => e.name(f.db),
+                    AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
+                    AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
+                    AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
                 }
                 .unwrap_or_else(Name::missing);
                 write!(f, "{}", name)?;
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 6fd00d457f6..fce45321df3 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -598,10 +598,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         trait_.associated_type_by_name(self.db, &name::OUTPUT_TYPE)
     }
 
-    fn resolve_boxed_box(&self) -> Option<Adt> {
+    fn resolve_boxed_box(&self) -> Option<AdtId> {
         let path = known::std_boxed_box();
         let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
-        Some(Adt::Struct(struct_.into()))
+        Some(struct_.into())
     }
 }
 
diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs
index bb9a2e427ef..5ed4470afaf 100644
--- a/crates/ra_hir/src/ty/infer/coerce.rs
+++ b/crates/ra_hir/src/ty/infer/coerce.rs
@@ -4,14 +4,14 @@
 //!
 //! See: https://doc.rust-lang.org/nomicon/coercions.html
 
-use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
+use hir_def::{lang_item::LangItemTarget, resolver::Resolver, AdtId};
 use rustc_hash::FxHashMap;
 use test_utils::tested_by;
 
 use crate::{
     db::HirDatabase,
     ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
-    Adt, Mutability,
+    Mutability,
 };
 
 use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue};
@@ -242,11 +242,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             // - T is not part of the type of any other fields
             // - Bar<T>: Unsize<Bar<U>>, if the last field of Foo has type Bar<T>
             (
-                ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1),
-                ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2),
+                ty_app!(TypeCtor::Adt(AdtId::StructId(struct1)), st1),
+                ty_app!(TypeCtor::Adt(AdtId::StructId(struct2)), st2),
             ) if struct1 == struct2 => {
-                let field_tys = self.db.field_types(struct1.id.into());
-                let struct_data = self.db.struct_data(struct1.id);
+                let field_tys = self.db.field_types((*struct1).into());
+                let struct_data = self.db.struct_data(*struct1);
 
                 let mut fields = struct_data.variant_data.fields().iter();
                 let (last_field_id, _data) = fields.next_back()?;
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs
index 316cdc88009..3d0895dc612 100644
--- a/crates/ra_hir/src/ty/infer/expr.rs
+++ b/crates/ra_hir/src/ty/infer/expr.rs
@@ -8,7 +8,7 @@ use hir_def::{
     generics::GenericParams,
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
-    ContainerId, Lookup,
+    AdtId, ContainerId, Lookup, StructFieldId,
 };
 use hir_expand::name;
 
@@ -20,7 +20,7 @@ use crate::{
         Mutability, Namespace, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty,
         TypeCtor, TypeWalk, Uncertain,
     },
-    Adt, Name,
+    Name,
 };
 
 use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
@@ -259,14 +259,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                         TypeCtor::Tuple { .. } => name
                             .as_tuple_index()
                             .and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
-                        TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
-                            self.write_field_resolution(tgt_expr, field);
-                            self.db.field_types(s.id.into())[field.id]
-                                .clone()
-                                .subst(&a_ty.parameters)
-                        }),
+                        TypeCtor::Adt(AdtId::StructId(s)) => {
+                            self.db.struct_data(s).variant_data.field(name).map(|local_id| {
+                                let field = StructFieldId { parent: s.into(), local_id }.into();
+                                self.write_field_resolution(tgt_expr, field);
+                                self.db.field_types(s.into())[field.id]
+                                    .clone()
+                                    .subst(&a_ty.parameters)
+                            })
+                        }
                         // FIXME:
-                        TypeCtor::Adt(Adt::Union(_)) => None,
+                        TypeCtor::Adt(AdtId::UnionId(_)) => None,
                         _ => None,
                     },
                     _ => None,
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index d7d4bb0d662..485871e6904 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -762,7 +762,7 @@ fn type_for_adt(db: &impl HirDatabase, adt: impl Into<Adt>) -> Ty {
     let adt = adt.into();
     let adt_id: AdtId = adt.into();
     let generics = db.generic_params(adt_id.into());
-    Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics))
+    Ty::apply(TypeCtor::Adt(adt_id), Substs::identity(&generics))
 }
 
 fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index c5ab690eb9e..7f0ff2e8ca9 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -5,7 +5,7 @@
 use std::sync::Arc;
 
 use arrayvec::ArrayVec;
-use hir_def::{lang_item::LangItemTarget, resolver::Resolver, AstItemDef};
+use hir_def::{lang_item::LangItemTarget, resolver::Resolver, AstItemDef, HasModule};
 use rustc_hash::FxHashMap;
 
 use crate::{
@@ -102,7 +102,9 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV
 
     let lang_item_targets = match ty {
         Ty::Apply(a_ty) => match a_ty.ctor {
-            TypeCtor::Adt(def_id) => return Some(std::iter::once(def_id.krate(db)?).collect()),
+            TypeCtor::Adt(def_id) => {
+                return Some(std::iter::once(def_id.module(db).krate.into()).collect())
+            }
             TypeCtor::Bool => lang_item_crate!("bool"),
             TypeCtor::Char => lang_item_crate!("char"),
             TypeCtor::Float(Uncertain::Known(f)) => match f.bitness {
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 0091bfbc336..0cf418d301a 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -129,6 +129,10 @@ impl VariantData {
         }
     }
 
+    pub fn field(&self, name: &Name) -> Option<LocalStructFieldId> {
+        self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
+    }
+
     pub fn is_unit(&self) -> bool {
         match self {
             VariantData::Unit => true,
diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs
index aca23f79e24..cf12db066ae 100644
--- a/crates/ra_ide_api/src/references/name_definition.rs
+++ b/crates/ra_ide_api/src/references/name_definition.rs
@@ -46,6 +46,7 @@ pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDe
     let container = parent.module(db);
     let visibility = match parent {
         VariantDef::Struct(s) => s.source(db).value.visibility(),
+        VariantDef::Union(e) => e.source(db).value.visibility(),
         VariantDef::EnumVariant(e) => e.source(db).value.parent_enum().visibility(),
     };
     NameDefinition { kind, container, visibility }