Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_def/src/generics.rs')
| -rw-r--r-- | crates/hir_def/src/generics.rs | 174 |
1 files changed, 99 insertions, 75 deletions
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 7febf1b5e8..341d444d61 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs @@ -9,9 +9,10 @@ use hir_expand::{ name::{AsName, Name}, ExpandResult, HirFileId, InFile, }; -use la_arena::{Arena, ArenaMap}; +use la_arena::{Arena, ArenaMap, Idx}; use once_cell::unsync::Lazy; use std::ops::DerefMut; +use stdx::impl_from; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; use crate::{ @@ -23,8 +24,8 @@ use crate::{ keys, src::{HasChildSource, HasSource}, type_ref::{LifetimeRef, TypeBound, TypeRef}, - AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalConstParamId, - LocalLifetimeParamId, LocalTypeParamId, Lookup, TypeParamId, + AdtId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, + Lookup, TypeOrConstParamId, }; /// Data about a generic type parameter (to a function, struct, impl, ...). @@ -55,12 +56,44 @@ pub enum TypeParamProvenance { ArgumentImplTrait, } +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum TypeOrConstParamData { + TypeParamData(TypeParamData), + ConstParamData(ConstParamData), +} + +impl TypeOrConstParamData { + pub fn name(&self) -> Option<&Name> { + match self { + TypeOrConstParamData::TypeParamData(x) => x.name.as_ref(), + TypeOrConstParamData::ConstParamData(x) => Some(&x.name), + } + } + + pub fn type_param(&self) -> Option<&TypeParamData> { + match self { + TypeOrConstParamData::TypeParamData(x) => Some(&x), + TypeOrConstParamData::ConstParamData(_) => None, + } + } + + pub fn is_trait_self(&self) -> bool { + match self { + TypeOrConstParamData::TypeParamData(x) => { + x.provenance == TypeParamProvenance::TraitSelf + } + TypeOrConstParamData::ConstParamData(_) => false, + } + } +} + +impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData); + /// Data about the generic parameters of a function, struct, impl, etc. #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] pub struct GenericParams { - pub types: Arena<TypeParamData>, + pub types: Arena<TypeOrConstParamData>, pub lifetimes: Arena<LifetimeParamData>, - pub consts: Arena<ConstParamData>, pub where_predicates: Vec<WherePredicate>, } @@ -89,10 +122,18 @@ pub enum WherePredicate { pub enum WherePredicateTypeTarget { TypeRef(Interned<TypeRef>), /// For desugared where predicates that can directly refer to a type param. - TypeParam(LocalTypeParamId), + TypeOrConstParam(LocalTypeOrConstParamId), } impl GenericParams { + // FIXME: almost every usecase of this function is wrong. every one should check + // const generics + pub fn type_iter<'a>( + &'a self, + ) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeParamData)> { + self.types.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y))) + } + pub(crate) fn generic_params_query( db: &dyn DefDatabase, def: GenericDefId, @@ -184,19 +225,32 @@ impl GenericParams { } fn fill_params(&mut self, lower_ctx: &LowerCtx, params: ast::GenericParamList) { - for type_param in params.type_params() { - 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(|it| Interned::new(TypeRef::from_ast(lower_ctx, it))); - let param = TypeParamData { - name: Some(name.clone()), - default, - provenance: TypeParamProvenance::TypeParamList, - }; - self.types.alloc(param); - let type_ref = TypeRef::Path(name.into()); - self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); + for type_or_const_param in params.type_or_const_params() { + match type_or_const_param { + ast::TypeOrConstParam::Type(type_param) => { + 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(|it| Interned::new(TypeRef::from_ast(lower_ctx, it))); + let param = TypeParamData { + name: Some(name.clone()), + default, + provenance: TypeParamProvenance::TypeParamList, + }; + self.types.alloc(param.into()); + let type_ref = TypeRef::Path(name.into()); + self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); + } + ast::TypeOrConstParam::Const(const_param) => { + let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); + let ty = const_param + .ty() + .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); + let param = ConstParamData { name, ty: Interned::new(ty) }; + self.types.alloc(param.into()); + } + } } for lifetime_param in params.lifetime_params() { let name = @@ -206,12 +260,6 @@ impl GenericParams { let lifetime_ref = LifetimeRef::new_name(name); self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); } - for const_param in params.const_params() { - let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); - let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); - let param = ConstParamData { name, ty: Interned::new(ty) }; - self.consts.alloc(param); - } } fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { @@ -287,10 +335,10 @@ impl GenericParams { default: None, provenance: TypeParamProvenance::ArgumentImplTrait, }; - let param_id = self.types.alloc(param); + let param_id = self.types.alloc(param.into()); for bound in bounds { self.where_predicates.push(WherePredicate::TypeBound { - target: WherePredicateTypeTarget::TypeParam(param_id), + target: WherePredicateTypeTarget::TypeOrConstParam(param_id), bound: bound.clone(), }); } @@ -311,27 +359,26 @@ impl GenericParams { } pub(crate) fn shrink_to_fit(&mut self) { - let Self { consts, lifetimes, types, where_predicates } = self; - consts.shrink_to_fit(); + let Self { lifetimes, types, where_predicates } = self; lifetimes.shrink_to_fit(); types.shrink_to_fit(); where_predicates.shrink_to_fit(); } - pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { + pub fn find_type_or_const_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> { self.types .iter() - .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) + .find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None }) } - pub fn find_const_by_name(&self, name: &Name) -> Option<LocalConstParamId> { - self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None }) - } - - pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { + pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> { self.types.iter().find_map(|(id, p)| { - if p.provenance == TypeParamProvenance::TraitSelf { - Some(id) + if let TypeOrConstParamData::TypeParamData(p) = p { + if p.provenance == TypeParamProvenance::TraitSelf { + Some(id) + } else { + None + } } else { None } @@ -377,12 +424,12 @@ fn file_id_and_params_of( } } -impl HasChildSource<LocalTypeParamId> for GenericDefId { - type Value = Either<ast::TypeParam, ast::Trait>; +impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId { + type Value = Either<ast::TypeOrConstParam, ast::Trait>; fn child_source( &self, db: &dyn DefDatabase, - ) -> InFile<ArenaMap<LocalTypeParamId, Self::Value>> { + ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> { let generic_params = db.generic_params(*self); let mut idx_iter = generic_params.types.iter().map(|(idx, _)| idx); @@ -398,7 +445,7 @@ impl HasChildSource<LocalTypeParamId> for GenericDefId { } if let Some(generic_params_list) = generic_params_list { - for (idx, ast_param) in idx_iter.zip(generic_params_list.type_params()) { + for (idx, ast_param) in idx_iter.zip(generic_params_list.type_or_const_params()) { params.insert(idx, Either::Left(ast_param)); } } @@ -430,29 +477,6 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId { } } -impl HasChildSource<LocalConstParamId> for GenericDefId { - type Value = ast::ConstParam; - fn child_source( - &self, - db: &dyn DefDatabase, - ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> { - let generic_params = db.generic_params(*self); - let idx_iter = generic_params.consts.iter().map(|(idx, _)| idx); - - let (file_id, generic_params_list) = file_id_and_params_of(*self, db); - - let mut params = ArenaMap::default(); - - if let Some(generic_params_list) = generic_params_list { - for (idx, ast_param) in idx_iter.zip(generic_params_list.const_params()) { - params.insert(idx, ast_param); - } - } - - InFile::new(file_id, params) - } -} - impl ChildBySource for GenericDefId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let (gfile_id, generic_params_list) = file_id_and_params_of(*self, db); @@ -461,28 +485,28 @@ impl ChildBySource for GenericDefId { } let generic_params = db.generic_params(*self); - let mut types_idx_iter = generic_params.types.iter().map(|(idx, _)| idx); + let mut toc_idx_iter = generic_params.types.iter().map(|(idx, _)| idx); let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx); - let consts_idx_iter = generic_params.consts.iter().map(|(idx, _)| idx); // For traits the first type index is `Self`, skip it. if let GenericDefId::TraitId(_) = *self { - types_idx_iter.next().unwrap(); // advance_by(1); + toc_idx_iter.next().unwrap(); // advance_by(1); } if let Some(generic_params_list) = generic_params_list { - for (local_id, ast_param) in types_idx_iter.zip(generic_params_list.type_params()) { - let id = TypeParamId { parent: *self, local_id }; - res[keys::TYPE_PARAM].insert(ast_param, id); + for (local_id, ast_param) in + toc_idx_iter.zip(generic_params_list.type_or_const_params()) + { + let id = TypeOrConstParamId { parent: *self, local_id }; + match ast_param { + ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id), + ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id), + } } for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) { let id = LifetimeParamId { parent: *self, local_id }; res[keys::LIFETIME_PARAM].insert(ast_param, id); } - for (local_id, ast_param) in consts_idx_iter.zip(generic_params_list.const_params()) { - let id = ConstParamId { parent: *self, local_id }; - res[keys::CONST_PARAM].insert(ast_param, id); - } } } } |