From e1a6e38767c1e47e5e88a97a9ef5b4547390803c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 Nov 2019 12:25:02 +0300 Subject: 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 d75d71d66..0d35014a0 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; #[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 f2203e995..b7692d407 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 for Adt { } } +impl From 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 for EnumVariant { fn from(id: EnumVariantId) -> Self { EnumVariant { parent: id.parent.into(), id: id.local_id } @@ -82,3 +92,33 @@ impl From for AssocItem { } } } + +impl From 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 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 78fab1a13..caedb90e6 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, -} - -/// 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>, - pub(crate) params: Vec, - pub(crate) where_predicates: Vec, -} - -/// 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`. -#[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 { - 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 { + 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 79b92180a..a2fa0bb79 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 { 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 000000000..4adfc16bb --- /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, +} + +/// 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>, + pub params: Vec, + pub where_predicates: Vec, +} + +/// 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`. +#[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>, + ) -> 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 50caf4f83..dffc82ff8 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 +); -- cgit v1.2.3