From e1a6e38767c1e47e5e88a97a9ef5b4547390803c Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Wed, 20 Nov 2019 12:25:02 +0300
Subject: [PATCH] Move Generics to hir_def

---
 crates/ra_hir/src/db.rs           |   2 +-
 crates/ra_hir/src/from_id.rs      |  44 +++++++-
 crates/ra_hir/src/generics.rs     | 182 +++---------------------------
 crates/ra_hir/src/resolve.rs      |   2 +-
 crates/ra_hir_def/src/generics.rs | 163 ++++++++++++++++++++++++++
 crates/ra_hir_def/src/lib.rs      |  24 ++++
 6 files changed, 247 insertions(+), 170 deletions(-)
 create mode 100644 crates/ra_hir_def/src/generics.rs

diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index d75d71d6659..0d35014a0f9 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -43,7 +43,7 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
     #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)]
     fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex;
 
-    #[salsa::invoke(crate::generics::GenericParams::generic_params_query)]
+    #[salsa::invoke(crate::generics::generic_params_query)]
     fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>;
 
     #[salsa::invoke(FnData::fn_data_query)]
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
index f2203e99532..b7692d40733 100644
--- a/crates/ra_hir/src/from_id.rs
+++ b/crates/ra_hir/src/from_id.rs
@@ -3,9 +3,9 @@
 //! It's unclear if we need this long-term, but it's definitelly useful while we
 //! are splitting the hir.
 
-use hir_def::{AdtId, AssocItemId, DefWithBodyId, EnumVariantId, ModuleDefId};
+use hir_def::{AdtId, AssocItemId, DefWithBodyId, EnumVariantId, GenericDefId, ModuleDefId};
 
-use crate::{Adt, AssocItem, DefWithBody, EnumVariant, ModuleDef};
+use crate::{Adt, AssocItem, DefWithBody, EnumVariant, GenericDef, ModuleDef};
 
 macro_rules! from_id {
     ($(($id:path, $ty:path)),*) => {$(
@@ -41,6 +41,16 @@ impl From<AdtId> for Adt {
     }
 }
 
+impl From<Adt> for AdtId {
+    fn from(id: Adt) -> Self {
+        match id {
+            Adt::Struct(it) => AdtId::StructId(it.id),
+            Adt::Union(it) => AdtId::UnionId(it.id),
+            Adt::Enum(it) => AdtId::EnumId(it.id),
+        }
+    }
+}
+
 impl From<EnumVariantId> for EnumVariant {
     fn from(id: EnumVariantId) -> Self {
         EnumVariant { parent: id.parent.into(), id: id.local_id }
@@ -82,3 +92,33 @@ impl From<AssocItemId> for AssocItem {
         }
     }
 }
+
+impl From<GenericDef> for GenericDefId {
+    fn from(def: GenericDef) -> Self {
+        match def {
+            GenericDef::Function(it) => GenericDefId::FunctionId(it.id),
+            GenericDef::Adt(it) => GenericDefId::AdtId(it.into()),
+            GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
+            GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
+            GenericDef::ImplBlock(it) => GenericDefId::ImplId(it.id),
+            GenericDef::EnumVariant(it) => {
+                GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id })
+            }
+            GenericDef::Const(it) => GenericDefId::ConstId(it.id),
+        }
+    }
+}
+
+impl From<GenericDefId> for GenericDef {
+    fn from(def: GenericDefId) -> Self {
+        match def {
+            GenericDefId::FunctionId(it) => GenericDef::Function(it.into()),
+            GenericDefId::AdtId(it) => GenericDef::Adt(it.into()),
+            GenericDefId::TraitId(it) => GenericDef::Trait(it.into()),
+            GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
+            GenericDefId::ImplId(it) => GenericDef::ImplBlock(it.into()),
+            GenericDefId::EnumVariantId(it) => GenericDef::EnumVariant(it.into()),
+            GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
+        }
+    }
+}
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 78fab1a13a7..caedb90e6ab 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -1,47 +1,12 @@
-//! Many kinds of items or constructs can have generic parameters: functions,
-//! structs, impls, traits, etc. This module provides a common HIR for these
-//! generic parameters. See also the `Generics` type and the `generics_of` query
-//! in rustc.
-
+//! Temp module to wrap hir_def::generics
 use std::sync::Arc;
 
-use hir_def::type_ref::{TypeBound, TypeRef};
-use hir_expand::name::{self, AsName};
-use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
-
 use crate::{
     db::{AstDatabase, DefDatabase, HirDatabase},
-    Adt, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait,
-    TypeAlias, Union,
+    Adt, Const, Container, Enum, EnumVariant, Function, ImplBlock, Struct, Trait, TypeAlias, Union,
 };
 
-/// Data about a generic parameter (to a function, struct, impl, ...).
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct GenericParam {
-    // FIXME: give generic params proper IDs
-    pub idx: u32,
-    pub name: Name,
-    pub default: Option<TypeRef>,
-}
-
-/// Data about the generic parameters of a function, struct, impl, etc.
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct GenericParams {
-    pub(crate) def: GenericDef,
-    pub(crate) parent_params: Option<Arc<GenericParams>>,
-    pub(crate) params: Vec<GenericParam>,
-    pub(crate) where_predicates: Vec<WherePredicate>,
-}
-
-/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
-/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
-/// It might still result in multiple actual predicates though, because of
-/// associated type bindings like `Iterator<Item = u32>`.
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct WherePredicate {
-    pub(crate) type_ref: TypeRef,
-    pub(crate) bound: TypeBound,
-}
+pub use hir_def::generics::{GenericParam, GenericParams, WherePredicate};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 pub enum GenericDef {
@@ -66,134 +31,19 @@ impl_froms!(
     Const
 );
 
-impl GenericParams {
-    pub(crate) fn generic_params_query(
-        db: &(impl DefDatabase + AstDatabase),
-        def: GenericDef,
-    ) -> Arc<GenericParams> {
-        let parent = match def {
-            GenericDef::Function(it) => it.container(db).map(GenericDef::from),
-            GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
-            GenericDef::Const(it) => it.container(db).map(GenericDef::from),
-            GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()),
-            GenericDef::Adt(_) | GenericDef::Trait(_) => None,
-            GenericDef::ImplBlock(_) => None,
-        };
-        let mut generics = GenericParams {
-            def,
-            params: Vec::new(),
-            parent_params: parent.map(|p| db.generic_params(p)),
-            where_predicates: Vec::new(),
-        };
-        let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
-        // FIXME: add `: Sized` bound for everything except for `Self` in traits
-        match def {
-            GenericDef::Function(it) => generics.fill(&it.source(db).value, start),
-            GenericDef::Adt(Adt::Struct(it)) => generics.fill(&it.source(db).value, start),
-            GenericDef::Adt(Adt::Union(it)) => generics.fill(&it.source(db).value, start),
-            GenericDef::Adt(Adt::Enum(it)) => generics.fill(&it.source(db).value, start),
-            GenericDef::Trait(it) => {
-                // traits get the Self type as an implicit first type parameter
-                generics.params.push(GenericParam {
-                    idx: start,
-                    name: name::SELF_TYPE,
-                    default: None,
-                });
-                generics.fill(&it.source(db).value, start + 1);
-                // add super traits as bounds on Self
-                // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
-                let self_param = TypeRef::Path(name::SELF_TYPE.into());
-                generics.fill_bounds(&it.source(db).value, self_param);
-            }
-            GenericDef::TypeAlias(it) => generics.fill(&it.source(db).value, start),
-            // Note that we don't add `Self` here: in `impl`s, `Self` is not a
-            // type-parameter, but rather is a type-alias for impl's target
-            // type, so this is handled by the resolver.
-            GenericDef::ImplBlock(it) => generics.fill(&it.source(db).value, start),
-            GenericDef::EnumVariant(_) | GenericDef::Const(_) => {}
-        }
-
-        Arc::new(generics)
-    }
-
-    fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
-        if let Some(params) = node.type_param_list() {
-            self.fill_params(params, start)
-        }
-        if let Some(where_clause) = node.where_clause() {
-            self.fill_where_predicates(where_clause);
-        }
-    }
-
-    fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) {
-        for bound in
-            node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
-        {
-            self.add_where_predicate_from_bound(bound, type_ref.clone());
-        }
-    }
-
-    fn fill_params(&mut self, params: ast::TypeParamList, start: u32) {
-        for (idx, type_param) in params.type_params().enumerate() {
-            let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
-            // FIXME: Use `Path::from_src`
-            let default = type_param.default_type().map(TypeRef::from_ast);
-
-            let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default };
-            self.params.push(param);
-
-            let type_ref = TypeRef::Path(name.into());
-            self.fill_bounds(&type_param, type_ref);
-        }
-    }
-
-    fn fill_where_predicates(&mut self, where_clause: ast::WhereClause) {
-        for pred in where_clause.predicates() {
-            let type_ref = match pred.type_ref() {
-                Some(type_ref) => type_ref,
-                None => continue,
-            };
-            let type_ref = TypeRef::from_ast(type_ref);
-            for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
-                self.add_where_predicate_from_bound(bound, type_ref.clone());
-            }
-        }
-    }
-
-    fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) {
-        if bound.has_question_mark() {
-            // FIXME: remove this bound
-            return;
-        }
-        let bound = TypeBound::from_ast(bound);
-        self.where_predicates.push(WherePredicate { type_ref, bound });
-    }
-
-    pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
-        self.params.iter().find(|p| &p.name == name)
-    }
-
-    pub fn count_parent_params(&self) -> usize {
-        self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
-    }
-
-    pub fn count_params_including_parent(&self) -> usize {
-        let parent_count = self.count_parent_params();
-        parent_count + self.params.len()
-    }
-
-    fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
-        if let Some(parent) = &self.parent_params {
-            parent.for_each_param(f);
-        }
-        self.params.iter().for_each(f);
-    }
-
-    pub fn params_including_parent(&self) -> Vec<&GenericParam> {
-        let mut vec = Vec::with_capacity(self.count_params_including_parent());
-        self.for_each_param(&mut |p| vec.push(p));
-        vec
-    }
+pub(crate) fn generic_params_query(
+    db: &(impl DefDatabase + AstDatabase),
+    def: GenericDef,
+) -> Arc<GenericParams> {
+    let parent = match def {
+        GenericDef::Function(it) => it.container(db).map(GenericDef::from),
+        GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
+        GenericDef::Const(it) => it.container(db).map(GenericDef::from),
+        GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()),
+        GenericDef::Adt(_) | GenericDef::Trait(_) => None,
+        GenericDef::ImplBlock(_) => None,
+    };
+    Arc::new(GenericParams::new(db, def.into(), parent.map(|it| db.generic_params(it))))
 }
 
 impl GenericDef {
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 79b92180a69..a2fa0bb79e1 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -369,7 +369,7 @@ impl Resolver {
 
     pub(crate) fn generic_def(&self) -> Option<crate::generics::GenericDef> {
         self.scopes.iter().find_map(|scope| match scope {
-            Scope::GenericParams(params) => Some(params.def),
+            Scope::GenericParams(params) => Some(params.def.into()),
             _ => None,
         })
     }
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
new file mode 100644
index 00000000000..4adfc16bbb2
--- /dev/null
+++ b/crates/ra_hir_def/src/generics.rs
@@ -0,0 +1,163 @@
+//! Many kinds of items or constructs can have generic parameters: functions,
+//! structs, impls, traits, etc. This module provides a common HIR for these
+//! generic parameters. See also the `Generics` type and the `generics_of` query
+//! in rustc.
+use std::sync::Arc;
+
+use hir_expand::name::{self, AsName, Name};
+
+use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
+
+use crate::{
+    db::DefDatabase2,
+    type_ref::{TypeBound, TypeRef},
+    AdtId, AstItemDef, GenericDefId,
+};
+
+/// Data about a generic parameter (to a function, struct, impl, ...).
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct GenericParam {
+    // FIXME: give generic params proper IDs
+    pub idx: u32,
+    pub name: Name,
+    pub default: Option<TypeRef>,
+}
+
+/// Data about the generic parameters of a function, struct, impl, etc.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct GenericParams {
+    pub def: GenericDefId,
+    pub parent_params: Option<Arc<GenericParams>>,
+    pub params: Vec<GenericParam>,
+    pub where_predicates: Vec<WherePredicate>,
+}
+
+/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
+/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
+/// It might still result in multiple actual predicates though, because of
+/// associated type bindings like `Iterator<Item = u32>`.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct WherePredicate {
+    pub type_ref: TypeRef,
+    pub bound: TypeBound,
+}
+
+impl GenericParams {
+    pub fn new(
+        db: &impl DefDatabase2,
+        def: GenericDefId,
+        parent_params: Option<Arc<GenericParams>>,
+    ) -> GenericParams {
+        let mut generics =
+            GenericParams { def, params: Vec::new(), parent_params, where_predicates: Vec::new() };
+        let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
+        // FIXME: add `: Sized` bound for everything except for `Self` in traits
+        match def {
+            GenericDefId::FunctionId(it) => generics.fill(&it.source(db).value, start),
+            GenericDefId::AdtId(AdtId::StructId(it)) => {
+                generics.fill(&it.0.source(db).value, start)
+            }
+            GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.0.source(db).value, start),
+            GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start),
+            GenericDefId::TraitId(it) => {
+                // traits get the Self type as an implicit first type parameter
+                generics.params.push(GenericParam {
+                    idx: start,
+                    name: name::SELF_TYPE,
+                    default: None,
+                });
+                generics.fill(&it.source(db).value, start + 1);
+                // add super traits as bounds on Self
+                // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
+                let self_param = TypeRef::Path(name::SELF_TYPE.into());
+                generics.fill_bounds(&it.source(db).value, self_param);
+            }
+            GenericDefId::TypeAliasId(it) => generics.fill(&it.source(db).value, start),
+            // Note that we don't add `Self` here: in `impl`s, `Self` is not a
+            // type-parameter, but rather is a type-alias for impl's target
+            // type, so this is handled by the resolver.
+            GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start),
+            GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {}
+        }
+
+        generics
+    }
+
+    fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
+        if let Some(params) = node.type_param_list() {
+            self.fill_params(params, start)
+        }
+        if let Some(where_clause) = node.where_clause() {
+            self.fill_where_predicates(where_clause);
+        }
+    }
+
+    fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) {
+        for bound in
+            node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
+        {
+            self.add_where_predicate_from_bound(bound, type_ref.clone());
+        }
+    }
+
+    fn fill_params(&mut self, params: ast::TypeParamList, start: u32) {
+        for (idx, type_param) in params.type_params().enumerate() {
+            let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
+            // FIXME: Use `Path::from_src`
+            let default = type_param.default_type().map(TypeRef::from_ast);
+            let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default };
+            self.params.push(param);
+
+            let type_ref = TypeRef::Path(name.into());
+            self.fill_bounds(&type_param, type_ref);
+        }
+    }
+
+    fn fill_where_predicates(&mut self, where_clause: ast::WhereClause) {
+        for pred in where_clause.predicates() {
+            let type_ref = match pred.type_ref() {
+                Some(type_ref) => type_ref,
+                None => continue,
+            };
+            let type_ref = TypeRef::from_ast(type_ref);
+            for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
+                self.add_where_predicate_from_bound(bound, type_ref.clone());
+            }
+        }
+    }
+
+    fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) {
+        if bound.has_question_mark() {
+            // FIXME: remove this bound
+            return;
+        }
+        let bound = TypeBound::from_ast(bound);
+        self.where_predicates.push(WherePredicate { type_ref, bound });
+    }
+
+    pub fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
+        self.params.iter().find(|p| &p.name == name)
+    }
+
+    pub fn count_parent_params(&self) -> usize {
+        self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
+    }
+
+    pub fn count_params_including_parent(&self) -> usize {
+        let parent_count = self.count_parent_params();
+        parent_count + self.params.len()
+    }
+
+    fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
+        if let Some(parent) = &self.parent_params {
+            parent.for_each_param(f);
+        }
+        self.params.iter().for_each(f);
+    }
+
+    pub fn params_including_parent(&self) -> Vec<&GenericParam> {
+        let mut vec = Vec::with_capacity(self.count_params_including_parent());
+        self.for_each_param(&mut |p| vec.push(p));
+        vec
+    }
+}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 50caf4f836d..dffc82ff8c8 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -17,6 +17,7 @@ pub mod imp;
 pub mod diagnostics;
 pub mod expr;
 pub mod body;
+pub mod generics;
 
 #[cfg(test)]
 mod test_db;
@@ -408,3 +409,26 @@ pub enum AssocItemId {
 // require not implementing From, and instead having some checked way of
 // casting them, and somehow making the constructors private, which would be annoying.
 impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId);
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+pub enum GenericDefId {
+    FunctionId(FunctionId),
+    AdtId(AdtId),
+    TraitId(TraitId),
+    TypeAliasId(TypeAliasId),
+    ImplId(ImplId),
+    // enum variants cannot have generics themselves, but their parent enums
+    // can, and this makes some code easier to write
+    EnumVariantId(EnumVariantId),
+    // consts can have type parameters from their parents (i.e. associated consts of traits)
+    ConstId(ConstId),
+}
+impl_froms!(
+    GenericDefId: FunctionId,
+    AdtId(StructId, EnumId, UnionId),
+    TraitId,
+    TypeAliasId,
+    ImplId,
+    EnumVariantId,
+    ConstId
+);