Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-def/src/generics.rs | 32 | ||||
| -rw-r--r-- | crates/hir-def/src/lib.rs | 1 | ||||
| -rw-r--r-- | crates/hir-ty/src/builder.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/chalk_db.rs | 7 | ||||
| -rw-r--r-- | crates/hir-ty/src/chalk_ext.rs | 10 | ||||
| -rw-r--r-- | crates/hir-ty/src/consteval.rs | 13 | ||||
| -rw-r--r-- | crates/hir-ty/src/display.rs | 13 | ||||
| -rw-r--r-- | crates/hir-ty/src/generics.rs | 263 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 18 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/closure.rs | 10 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 21 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/path.rs | 9 | ||||
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 94 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/lower.rs | 3 | ||||
| -rw-r--r-- | crates/hir-ty/src/mir/monomorphization.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/utils.rs | 292 |
17 files changed, 401 insertions, 403 deletions
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index acead9dc17..b9f8082391 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -11,7 +11,7 @@ use hir_expand::{ ExpandResult, }; use intern::Interned; -use la_arena::Arena; +use la_arena::{Arena, RawIdx}; use once_cell::unsync::Lazy; use stdx::impl_from; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; @@ -28,6 +28,9 @@ use crate::{ LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; +const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> = + LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); + /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeParamData { @@ -441,15 +444,18 @@ impl GenericParamsCollector { impl GenericParams { /// Number of Generic parameters (type_or_consts + lifetimes) + #[inline] pub fn len(&self) -> usize { self.type_or_consts.len() + self.lifetimes.len() } + #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Iterator of type_or_consts field + #[inline] pub fn iter_type_or_consts( &self, ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> { @@ -457,6 +463,7 @@ impl GenericParams { } /// Iterator of lifetimes field + #[inline] pub fn iter_lt( &self, ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> { @@ -605,17 +612,18 @@ impl GenericParams { }) } - pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> { - self.type_or_consts.iter().find_map(|(id, p)| { - matches!( - p, - TypeOrConstParamData::TypeParamData(TypeParamData { - provenance: TypeParamProvenance::TraitSelf, - .. - }) - ) - .then(|| id) - }) + pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> { + if self.type_or_consts.is_empty() { + return None; + } + matches!( + self.type_or_consts[SELF_PARAM_ID_IN_SELF], + TypeOrConstParamData::TypeParamData(TypeParamData { + provenance: TypeParamProvenance::TraitSelf, + .. + }) + ) + .then(|| SELF_PARAM_ID_IN_SELF) } pub fn find_lifetime_by_name( diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 0dcd9129d6..f6fe0c618a 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -923,6 +923,7 @@ pub enum GenericDefId { ImplId(ImplId), // enum variants cannot have generics themselves, but their parent enums // can, and this makes some code easier to write + // FIXME: Try to remove this as that will reduce the amount of query slots generated per enum? EnumVariantId(EnumVariantId), // consts can have type parameters from their parents (i.e. associated consts of traits) ConstId(ConstId), diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs index d6374658f1..52411f94ad 100644 --- a/crates/hir-ty/src/builder.rs +++ b/crates/hir-ty/src/builder.rs @@ -14,10 +14,10 @@ use hir_def::{ use smallvec::SmallVec; use crate::{ - consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, - infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, - Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, - Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, + consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, generics::generics, + infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, Binders, + BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, + TraitRef, Ty, TyDefId, TyExt, TyKind, }; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 149e4dbaa5..0d8ceb68b2 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -20,13 +20,14 @@ use hir_expand::name::name; use crate::{ db::{HirDatabase, InternedCoroutine}, display::HirDisplay, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders, - make_single_type_binders, + from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + generics::generics, + make_binders, make_single_type_binders, mapping::{from_chalk, ToChalk, TypeAliasAsValue}, method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, to_assoc_type_id, to_chalk_trait_id, traits::ChalkContext, - utils::{generics, ClosureSubst}, + utils::ClosureSubst, wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index d99ef6679e..4279c75651 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -12,12 +12,10 @@ use hir_def::{ }; use crate::{ - db::HirDatabase, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, - to_chalk_trait_id, - utils::{generics, ClosureSubst}, - AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, - ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, + db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, AdtId, + AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId, + DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, }; diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index f09277a92e..8b6cde975f 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -15,10 +15,9 @@ use stdx::never; use triomphe::Arc; use crate::{ - db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, - mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData, - ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, - TyBuilder, + db::HirDatabase, generics::Generics, infer::InferenceContext, lower::ParamLoweringMode, + mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData, ConstScalar, ConstValue, + GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, }; use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError}; @@ -72,12 +71,12 @@ impl From<MirEvalError> for ConstEvalError { } } -pub(crate) fn path_to_const( +pub(crate) fn path_to_const<'g>( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, mode: ParamLoweringMode, - args: impl FnOnce() -> Option<Generics>, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, expected_ty: Ty, ) -> Option<Const> { @@ -90,7 +89,7 @@ pub(crate) fn path_to_const( } ParamLoweringMode::Variable => { let args = args(); - match args.as_ref().and_then(|args| args.type_or_const_param_idx(p.into())) { + match args.and_then(|args| args.type_or_const_param_idx(p.into())) { Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), None => { never!( diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index cd31845a51..66b5398b88 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -36,12 +36,13 @@ use crate::{ consteval::try_const_usize, db::{HirDatabase, InternedClosure}, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, + generics::generics, layout::Layout, lt_from_placeholder_idx, mapping::from_chalk, mir::pad16, primitive, to_assoc_type_id, - utils::{self, detect_variant_from_bytes, generics, ClosureSubst}, + utils::{self, detect_variant_from_bytes, ClosureSubst}, AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, @@ -493,7 +494,7 @@ impl HirDisplay for Const { ConstValue::Placeholder(idx) => { let id = from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?; Ok(()) } @@ -988,7 +989,7 @@ impl HirDisplay for Ty { if parameters.len(Interner) > 0 { let generics = generics(db.upcast(), def.into()); - let (parent_len, self_, type_, const_, impl_, lifetime) = + let (parent_len, self_param, type_, const_, impl_, lifetime) = generics.provenance_split(); let parameters = parameters.as_slice(Interner); // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? @@ -996,7 +997,7 @@ impl HirDisplay for Ty { // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes // parent's params (those from enclosing impl or trait, if any). let (fn_params, other) = - parameters.split_at(self_ + type_ + const_ + lifetime); + parameters.split_at(self_param as usize + type_ + const_ + lifetime); let (_impl, parent_params) = other.split_at(impl_); debug_assert_eq!(parent_params.len(), parent_len); @@ -1215,7 +1216,7 @@ impl HirDisplay for Ty { TyKind::Placeholder(idx) => { let id = from_placeholder_idx(db, *idx); let generics = generics(db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { @@ -1797,7 +1798,7 @@ impl HirDisplay for LifetimeData { LifetimeData::Placeholder(idx) => { let id = lt_from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name.display(f.db.upcast()))?; Ok(()) } diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs new file mode 100644 index 0000000000..ea10e6881e --- /dev/null +++ b/crates/hir-ty/src/generics.rs @@ -0,0 +1,263 @@ +//! Utilities for working with generics. +//! +//! The layout for generics as expected by chalk are as follows: +//! - Optional Self parameter +//! - Type or Const parameters +//! - Lifetime parameters +//! - Parent parameters +//! +//! where parent follows the same scheme. +use std::ops; + +use chalk_ir::{cast::Cast as _, BoundVar, DebruijnIndex}; +use hir_def::{ + db::DefDatabase, + generics::{ + GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, + TypeParamProvenance, + }, + ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, + LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, +}; +use intern::Interned; + +use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution}; + +pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { + let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); + Generics { def, params: db.generic_params(def), parent_generics } +} +#[derive(Clone, Debug)] +pub(crate) struct Generics { + def: GenericDefId, + params: Interned<GenericParams>, + parent_generics: Option<Box<Generics>>, +} + +impl<T> ops::Index<T> for Generics +where + GenericParams: ops::Index<T>, +{ + type Output = <GenericParams as ops::Index<T>>::Output; + fn index(&self, index: T) -> &Self::Output { + &self.params[index] + } +} + +impl Generics { + pub(crate) fn def(&self) -> GenericDefId { + self.def + } + + pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { + self.iter_self_id().chain(self.iter_parent_id()) + } + + pub(crate) fn iter_self_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { + self.iter_self().map(|(id, _)| id) + } + + fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { + self.iter_parent().map(|(id, _)| id) + } + + pub(crate) fn iter_self_type_or_consts( + &self, + ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> { + self.params.iter_type_or_consts() + } + + /// Iterate over the params followed by the parent params. + pub(crate) fn iter( + &self, + ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { + self.iter_self().chain(self.iter_parent()) + } + + /// Iterate over the params without parent params. + pub(crate) fn iter_self( + &self, + ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { + self.params + .iter_type_or_consts() + .map(from_toc_id(self)) + .chain(self.params.iter_lt().map(from_lt_id(self))) + } + + /// Iterator over types and const params of parent. + fn iter_parent( + &self, + ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { + self.parent_generics().into_iter().flat_map(|it| { + let lt_iter = it.params.iter_lt().map(from_lt_id(it)); + it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter) + }) + } + + /// Returns total number of generic parameters in scope, including those from parent. + pub(crate) fn len(&self) -> usize { + let parent = self.parent_generics().map_or(0, Generics::len); + let child = self.params.len(); + parent + child + } + + /// Returns numbers of generic parameters excluding those from parent. + pub(crate) fn len_self(&self) -> usize { + self.params.len() + } + + /// (parent total, self param, type params, const params, impl trait list, lifetimes) + pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) { + let mut self_param = false; + let mut type_params = 0; + let mut impl_trait_params = 0; + let mut const_params = 0; + self.params.iter_type_or_consts().for_each(|(_, data)| match data { + TypeOrConstParamData::TypeParamData(p) => match p.provenance { + TypeParamProvenance::TypeParamList => type_params += 1, + TypeParamProvenance::TraitSelf => self_param |= true, + TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, + }, + TypeOrConstParamData::ConstParamData(_) => const_params += 1, + }); + + let lifetime_params = self.params.iter_lt().count(); + + let parent_len = self.parent_generics().map_or(0, Generics::len); + (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params) + } + + pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> { + self.find_type_or_const_param(param) + } + + fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option<usize> { + if param.parent == self.def { + let idx = param.local_id.into_raw().into_u32() as usize; + debug_assert!(idx <= self.params.type_or_consts.len()); + Some(idx) + } else { + debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent)); + self.parent_generics() + .and_then(|g| g.find_type_or_const_param(param)) + // Remember that parent parameters come after parameters for self. + .map(|idx| self.len_self() + idx) + } + } + + pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> { + self.find_lifetime(lifetime) + } + + fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<usize> { + if lifetime.parent == self.def { + let idx = lifetime.local_id.into_raw().into_u32() as usize; + debug_assert!(idx <= self.params.lifetimes.len()); + Some(self.params.type_or_consts.len() + idx) + } else { + debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent)); + self.parent_generics() + .and_then(|g| g.find_lifetime(lifetime)) + .map(|idx| self.len_self() + idx) + } + } + + pub(crate) fn parent_generics(&self) -> Option<&Generics> { + self.parent_generics.as_deref() + } + + pub(crate) fn parent_or_self(&self) -> &Generics { + self.parent_generics.as_deref().unwrap_or(self) + } + + /// Returns a Substitution that replaces each parameter by a bound variable. + pub(crate) fn bound_vars_subst( + &self, + db: &dyn HirDatabase, + debruijn: DebruijnIndex, + ) -> Substitution { + Substitution::from_iter( + Interner, + self.iter_id().enumerate().map(|(idx, id)| match id { + GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx) + .to_const(Interner, db.const_param_ty(id)) + .cast(Interner), + GenericParamId::TypeParamId(_) => { + BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner) + } + GenericParamId::LifetimeParamId(_) => { + BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) + } + }), + ) + } + + /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). + pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { + Substitution::from_iter( + Interner, + self.iter_id().map(|id| match id { + GenericParamId::TypeParamId(id) => { + to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner) + } + GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into()) + .to_const(Interner, db.const_param_ty(id)) + .cast(Interner), + GenericParamId::LifetimeParamId(id) => { + lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner) + } + }), + ) + } +} + +fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { + let container = match def { + GenericDefId::FunctionId(it) => it.lookup(db).container, + GenericDefId::TypeAliasId(it) => it.lookup(db).container, + GenericDefId::ConstId(it) => it.lookup(db).container, + GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), + GenericDefId::AdtId(_) + | GenericDefId::TraitId(_) + | GenericDefId::ImplId(_) + | GenericDefId::TraitAliasId(_) => return None, + }; + + match container { + ItemContainerId::ImplId(it) => Some(it.into()), + ItemContainerId::TraitId(it) => Some(it.into()), + ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, + } +} + +fn from_toc_id<'a>( + it: &'a Generics, +) -> impl Fn( + (LocalTypeOrConstParamId, &'a TypeOrConstParamData), +) -> (GenericParamId, GenericParamDataRef<'a>) { + move |(local_id, p): (_, _)| { + let id = TypeOrConstParamId { parent: it.def, local_id }; + match p { + TypeOrConstParamData::TypeParamData(p) => ( + GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), + GenericParamDataRef::TypeParamData(p), + ), + TypeOrConstParamData::ConstParamData(p) => ( + GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), + GenericParamDataRef::ConstParamData(p), + ), + } + } +} + +fn from_lt_id<'a>( + it: &'a Generics, +) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>) +{ + move |(local_id, p): (_, _)| { + ( + GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), + GenericParamDataRef::LifetimeParamData(p), + ) + } +} diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 25bce0b31a..aeb6e69ce7 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -49,6 +49,7 @@ use hir_def::{ use hir_expand::name::{name, Name}; use indexmap::IndexSet; use la_arena::{ArenaMap, Entry}; +use once_cell::unsync::OnceCell; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; use triomphe::Arc; @@ -56,11 +57,12 @@ use triomphe::Arc; use crate::{ db::HirDatabase, error_lifetime, fold_tys, + generics::Generics, infer::{coerce::CoerceMany, unify::InferenceTable}, lower::ImplTraitLoweringMode, to_assoc_type_id, traits::FnTrait, - utils::{Generics, InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, + utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId, ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, @@ -526,6 +528,7 @@ pub(crate) struct InferenceContext<'a> { pub(crate) owner: DefWithBodyId, pub(crate) body: &'a Body, pub(crate) resolver: Resolver, + generics: OnceCell<Option<Generics>>, table: unify::InferenceTable<'a>, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet<TraitId>, @@ -611,6 +614,7 @@ impl<'a> InferenceContext<'a> { ) -> Self { let trait_env = db.trait_environment_for_body(owner); InferenceContext { + generics: OnceCell::new(), result: InferenceResult::default(), table: unify::InferenceTable::new(db, trait_env), tuple_field_accesses_rev: Default::default(), @@ -632,8 +636,14 @@ impl<'a> InferenceContext<'a> { } } - pub(crate) fn generics(&self) -> Option<Generics> { - Some(crate::utils::generics(self.db.upcast(), self.resolver.generic_def()?)) + pub(crate) fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| { + self.resolver + .generic_def() + .map(|def| crate::generics::generics(self.db.upcast(), def)) + }) + .as_ref() } // FIXME: This function should be private in module. It is currently only used in the consteval, since we need @@ -1263,7 +1273,7 @@ impl<'a> InferenceContext<'a> { forbid_unresolved_segments((ty, Some(var.into())), unresolved) } TypeNs::SelfType(impl_id) => { - let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); + let generics = crate::generics::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index a25498eff3..b7c7b66545 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -22,11 +22,13 @@ use stdx::never; use crate::{ db::{HirDatabase, InternedClosure}, - error_lifetime, from_chalk_trait_id, from_placeholder_idx, make_binders, + error_lifetime, from_chalk_trait_id, from_placeholder_idx, + generics::Generics, + make_binders, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, to_chalk_trait_id, traits::FnTrait, - utils::{self, elaborate_clause_supertraits, Generics}, + utils::{self, elaborate_clause_supertraits}, Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTyExt, Substitution, Ty, TyExt, WhereClause, @@ -337,7 +339,7 @@ impl CapturedItemWithoutTy { fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders<Ty> { struct Filler<'a> { db: &'a dyn HirDatabase, - generics: Generics, + generics: &'a Generics, } impl FallibleTypeFolder<Interner> for Filler<'_> { type Error = (); @@ -380,7 +382,7 @@ impl CapturedItemWithoutTy { }; let filler = &mut Filler { db: ctx.db, generics }; let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty); - make_binders(ctx.db, &filler.generics, result) + make_binders(ctx.db, filler.generics, result) } } } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 4c12786362..95f28531ac 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -24,6 +24,7 @@ use crate::{ consteval, db::{InternedClosure, InternedCoroutine}, error_lifetime, + generics::{generics, Generics}, infer::{ coerce::{CoerceMany, CoercionCause}, find_continuable, @@ -39,7 +40,6 @@ use crate::{ primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, - utils::{generics, Generics}, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnAbi, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, @@ -1830,13 +1830,13 @@ impl InferenceContext<'_> { ) -> Substitution { let ( parent_params, - self_params, + has_self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); - assert_eq!(self_params, 0); // method shouldn't have another Self param + assert!(!has_self_param); // method shouldn't have another Self param let total_len = parent_params + type_params + const_params + impl_trait_params + lifetime_params; let mut substs = Vec::with_capacity(total_len); @@ -1844,13 +1844,11 @@ impl InferenceContext<'_> { // handle provided arguments if let Some(generic_args) = generic_args { // if args are provided, it should be all of them, but we can't rely on that - for (arg, kind_id) in generic_args - .args - .iter() - .take(type_params + const_params + lifetime_params) - .zip(def_generics.iter_id()) + let self_params = type_params + const_params + lifetime_params; + for (arg, kind_id) in + generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params) { - if let Some(g) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, kind_id, arg, @@ -1869,9 +1867,8 @@ impl InferenceContext<'_> { ) }, |this, lt_ref| this.make_lifetime(lt_ref), - ) { - substs.push(g); - } + ); + substs.push(arg); } }; diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 9a1835b625..d876008cd5 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -12,11 +12,10 @@ use stdx::never; use crate::{ builder::ParamKind, consteval, error_lifetime, + generics::generics, method_resolution::{self, VisibleFromModule}, - to_chalk_trait_id, - utils::generics, - InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, - TyKind, ValueTyDefId, + to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, + TyBuilder, TyExt, TyKind, ValueTyDefId, }; use super::{ExprOrPatId, InferenceContext}; @@ -64,7 +63,7 @@ impl InferenceContext<'_> { it.into() } ValueNs::ImplSelf(impl_id) => { - let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); + let generics = crate::generics::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 9d596e957b..685aceb233 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -22,6 +22,7 @@ extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; mod builder; mod chalk_db; mod chalk_ext; +mod generics; mod infer; mod inhabitedness; mod interner; @@ -67,11 +68,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ast::{make, ConstArg}; use traits::FnTrait; use triomphe::Arc; -use utils::Generics; use crate::{ - consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable, - utils::generics, + consteval::unknown_const, db::HirDatabase, display::HirDisplay, generics::Generics, + infer::unify::InferenceTable, }; pub use autoderef::autoderef; @@ -289,7 +289,7 @@ impl Hash for ConstScalar { /// Return an index of a parameter in the generic type parameter list by it's id. pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> { - generics(db.upcast(), id.parent).type_or_const_param_idx(id) + generics::generics(db.upcast(), id.parent).type_or_const_param_idx(id) } pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T> diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 2e100d5c55..30d6b2f664 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -45,6 +45,7 @@ use hir_def::{ use hir_expand::{name::Name, ExpandResult}; use intern::Interned; use la_arena::{Arena, ArenaMap}; +use once_cell::unsync::OnceCell; use rustc_hash::FxHashSet; use smallvec::SmallVec; use stdx::{impl_from, never}; @@ -58,12 +59,13 @@ use crate::{ unknown_const_as_generic, }, db::HirDatabase, - error_lifetime, make_binders, + error_lifetime, + generics::{generics, Generics}, + make_binders, mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::{ - self, all_super_trait_refs, associated_type_by_name_including_super_traits, generics, - Generics, InTypeConstIdMetadata, + all_super_trait_refs, associated_type_by_name_including_super_traits, InTypeConstIdMetadata, }, AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, @@ -121,6 +123,7 @@ impl ImplTraitLoweringState { pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, + generics: OnceCell<Option<Generics>>, in_binders: DebruijnIndex, // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases // where expected @@ -152,6 +155,7 @@ impl<'a> TyLoweringContext<'a> { Self { db, resolver, + generics: OnceCell::new(), owner, in_binders, impl_trait_mode, @@ -174,6 +178,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_mode, expander: RefCell::new(expander), unsized_types: RefCell::new(unsized_types), + generics: self.generics.clone(), ..*self }; let result = f(&new_ctx); @@ -245,8 +250,10 @@ impl<'a> TyLoweringContext<'a> { ) } - fn generics(&self) -> Option<Generics> { - Some(generics(self.db.upcast(), self.resolver.generic_def()?)) + fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| self.resolver.generic_def().map(|def| generics(self.db.upcast(), def))) + .as_ref() } pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) { @@ -374,7 +381,7 @@ impl<'a> TyLoweringContext<'a> { counter.set(idx + count_impl_traits(type_ref) as u16); let ( _parent_params, - self_params, + self_param, type_params, const_params, _impl_trait_params, @@ -385,7 +392,7 @@ impl<'a> TyLoweringContext<'a> { .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_params + type_params + const_params, + idx as usize + self_param as usize + type_params + const_params, )) .intern(Interner) } @@ -705,7 +712,8 @@ impl<'a> TyLoweringContext<'a> { None, ); - let len_self = utils::generics(self.db.upcast(), associated_ty.into()).len_self(); + let len_self = + crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self(); let substs = Substitution::from_iter( Interner, @@ -815,14 +823,14 @@ impl<'a> TyLoweringContext<'a> { let def_generics = generics(self.db.upcast(), def); let ( parent_params, - self_params, + self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); let item_len = - self_params + type_params + const_params + impl_trait_params + lifetime_params; + self_param as usize + type_params + const_params + impl_trait_params + lifetime_params; let total_len = parent_params + item_len; let ty_error = TyKind::Error.intern(Interner).cast(Interner); @@ -830,18 +838,16 @@ impl<'a> TyLoweringContext<'a> { let mut def_generic_iter = def_generics.iter_id(); let fill_self_params = || { - for x in explicit_self_ty - .into_iter() - .map(|x| x.cast(Interner)) - .chain(iter::repeat(ty_error.clone())) - .take(self_params) - { + if self_param { + let self_ty = + explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone()); + if let Some(id) = def_generic_iter.next() { assert!(matches!( id, GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_) )); - substs.push(x); + substs.push(self_ty); } } }; @@ -852,11 +858,11 @@ impl<'a> TyLoweringContext<'a> { fill_self_params(); } let expected_num = if generic_args.has_self_type { - self_params + type_params + const_params + self_param as usize + type_params + const_params } else { type_params + const_params }; - let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; + let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 }; // if args are provided, it should be all of them, but we can't rely on that for arg in generic_args .args @@ -866,7 +872,7 @@ impl<'a> TyLoweringContext<'a> { .take(expected_num) { if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -874,13 +880,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // we just filtered them out - never!("Unexpected lifetime argument"); - } + ); + had_explicit_args = true; + substs.push(arg); } } @@ -893,7 +895,7 @@ impl<'a> TyLoweringContext<'a> { // Taking into the fact that def_generic_iter will always have lifetimes at the end // Should have some test cases tho to test this behaviour more properly if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -901,13 +903,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // Never return a None explicitly - never!("Unexpected None by generic_arg_to_chalk"); - } + ); + had_explicit_args = true; + substs.push(arg); } } } else { @@ -1176,7 +1174,7 @@ impl<'a> TyLoweringContext<'a> { let ty = if let Some(target_param_idx) = target_param_idx { let mut counter = 0; let generics = self.generics().expect("generics in scope"); - for (idx, data) in generics.params.type_or_consts.iter() { + for (idx, data) in generics.iter_self_type_or_consts() { // Count the number of `impl Trait` things that appear before // the target of our `bound`. // Our counter within `impl_trait_mode` should be that number @@ -1478,7 +1476,7 @@ fn named_associated_type_shorthand_candidates<R>( // Handle `Self::Type` referring to own associated type in trait definitions if let GenericDefId::TraitId(trait_id) = param_id.parent() { let trait_generics = generics(db.upcast(), trait_id.into()); - if trait_generics.params[param_id.local_id()].is_trait_self() { + if trait_generics[param_id.local_id()].is_trait_self() { let def_generics = generics(db.upcast(), def); let starting_idx = match def { GenericDefId::TraitId(_) => 0, @@ -2168,7 +2166,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut /// Checks if the provided generic arg matches its expected kind, then lower them via /// provided closures. Use unknown if there was kind mismatch. /// -/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime. pub(crate) fn generic_arg_to_chalk<'a, T>( db: &dyn HirDatabase, kind_id: GenericParamId, @@ -2177,7 +2174,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a, -) -> Option<crate::GenericArg> { +) -> crate::GenericArg { let kind = match kind_id { GenericParamId::TypeParamId(_) => ParamKind::Type, GenericParamId::ConstParamId(id) => { @@ -2186,7 +2183,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( } GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, }; - Some(match (arg, kind) { + match (arg, kind) { (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner), (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner), (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { @@ -2199,11 +2196,12 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( // as types. Maybe here is not the best place to do it, but // it works. if let TypeRef::Path(p) = t { - let p = p.mod_path()?; - if p.kind == PathKind::Plain { - if let [n] = p.segments() { - let c = ConstRef::Path(n.clone()); - return Some(for_const(this, &c, c_ty).cast(Interner)); + if let Some(p) = p.mod_path() { + if p.kind == PathKind::Plain { + if let [n] = p.segments() { + let c = ConstRef::Path(n.clone()); + return for_const(this, &c, c_ty).cast(Interner); + } } } } @@ -2212,17 +2210,17 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty), (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), - }) + } } -pub(crate) fn const_or_path_to_chalk( +pub(crate) fn const_or_path_to_chalk<'g>( db: &dyn HirDatabase, resolver: &Resolver, owner: TypeOwnerId, expected_ty: Ty, value: &ConstRef, mode: ParamLoweringMode, - args: impl FnOnce() -> Option<Generics>, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, ) -> Const { match value { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 6d662959f1..09302846f1 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -28,6 +28,7 @@ use crate::{ db::{HirDatabase, InternedClosure}, display::HirDisplay, error_lifetime, + generics::generics, infer::{CaptureKind, CapturedItem, TypeMismatch}, inhabitedness::is_ty_uninhabited_from, layout::LayoutError, @@ -42,7 +43,7 @@ use crate::{ }, static_lifetime, traits::FnTrait, - utils::{generics, ClosureSubst}, + utils::ClosureSubst, Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, }; diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs index a384c9306e..43afa61504 100644 --- a/crates/hir-ty/src/mir/monomorphization.rs +++ b/crates/hir-ty/src/mir/monomorphization.rs @@ -21,8 +21,8 @@ use crate::{ consteval::{intern_const_scalar, unknown_const}, db::{HirDatabase, InternedClosure}, from_placeholder_idx, + generics::{generics, Generics}, infer::normalize, - utils::{generics, Generics}, ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind, }; diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index cff8e6b036..969999cdb8 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -5,25 +5,19 @@ use std::{hash::Hash, iter}; use base_db::CrateId; use chalk_ir::{ - cast::Cast, fold::{FallibleTypeFolder, Shift}, - BoundVar, DebruijnIndex, + DebruijnIndex, }; use hir_def::{ db::DefDatabase, - generics::{ - GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, - TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, - }, + generics::{WherePredicate, WherePredicateTypeTarget}, lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, - ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, - LifetimeParamId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, - TypeParamId, + EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, + TypeOrConstParamId, }; use hir_expand::name::Name; -use intern::Interned; use rustc_abi::TargetDataLayout; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; @@ -161,7 +155,7 @@ impl Iterator for ClauseElaborator<'_> { fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { let resolver = trait_.resolver(db); let generic_params = db.generic_params(trait_.into()); - let trait_self = generic_params.find_trait_self_param(); + let trait_self = generic_params.trait_self_param(); generic_params .where_predicates .iter() @@ -194,7 +188,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) { let generic_params = db.generic_params(trait_ref.hir_trait_id().into()); - let trait_self = match generic_params.find_trait_self_param() { + let trait_self = match generic_params.trait_self_param() { Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p }, None => return, }; @@ -226,11 +220,6 @@ pub(super) fn associated_type_by_name_including_super_traits( }) } -pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { - let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - Generics { def, params: db.generic_params(def), parent_generics } -} - /// It is a bit different from the rustc equivalent. Currently it stores: /// - 0: the function signature, encoded as a function pointer type /// - 1..n: generics of the parent @@ -262,275 +251,6 @@ impl<'a> ClosureSubst<'a> { } } -#[derive(Clone, Debug)] -pub(crate) struct Generics { - def: GenericDefId, - pub(crate) params: Interned<GenericParams>, - parent_generics: Option<Box<Generics>>, -} - -impl Generics { - pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { - self.iter().map(|(id, _)| id) - } - - pub(crate) fn def(&self) -> GenericDefId { - self.def - } - - /// Iterator over types and const params of self, then parent. - pub(crate) fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a { - let from_toc_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a TypeOrConstParamData)| { - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - } - }; - - let from_lt_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a LifetimeParamData)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - } - }; - - let lt_iter = self.params.iter_lt().map(from_lt_id(self)); - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(lt_iter) - .chain(self.iter_parent()) - } - - /// Iterate over types and const params without parent params. - pub(crate) fn iter_self<'a>( - &'a self, - ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a { - let from_toc_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a TypeOrConstParamData)| { - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - } - }; - - let from_lt_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a LifetimeParamData)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - } - }; - - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(self.params.iter_lt().map(from_lt_id(self))) - } - - /// Iterator over types and const params of parent. - pub(crate) fn iter_parent( - &self, - ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { - self.parent_generics().into_iter().flat_map(|it| { - let from_toc_id = move |(local_id, p)| { - let p: &_ = p; - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - }; - - let from_lt_id = move |(local_id, p): (_, _)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - }; - let lt_iter = it.params.iter_lt().map(from_lt_id); - it.params.iter_type_or_consts().map(from_toc_id).chain(lt_iter) - }) - } - - /// Returns total number of generic parameters in scope, including those from parent. - pub(crate) fn len(&self) -> usize { - let parent = self.parent_generics().map_or(0, Generics::len); - let child = self.params.len(); - parent + child - } - - /// Returns numbers of generic parameters and lifetimes excluding those from parent. - pub(crate) fn len_self(&self) -> usize { - self.params.len() - } - - /// Returns number of generic parameter excluding those from parent - fn len_type_and_const_params(&self) -> usize { - self.params.type_or_consts.len() - } - - /// (parent total, self param, type params, const params, impl trait list, lifetimes) - pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) { - let mut self_params = 0; - let mut type_params = 0; - let mut impl_trait_params = 0; - let mut const_params = 0; - let mut lifetime_params = 0; - self.params.iter_type_or_consts().for_each(|(_, data)| match data { - TypeOrConstParamData::TypeParamData(p) => match p.provenance { - TypeParamProvenance::TypeParamList => type_params += 1, - TypeParamProvenance::TraitSelf => self_params += 1, - TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, - }, - TypeOrConstParamData::ConstParamData(_) => const_params += 1, - }); - - self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1); - - let parent_len = self.parent_generics().map_or(0, Generics::len); - (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params) - } - - pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> { - Some(self.find_type_or_const_param(param)?.0) - } - - fn find_type_or_const_param( - &self, - param: TypeOrConstParamId, - ) -> Option<(usize, &TypeOrConstParamData)> { - if param.parent == self.def { - let idx = param.local_id.into_raw().into_u32() as usize; - if idx >= self.params.type_or_consts.len() { - return None; - } - Some((idx, &self.params.type_or_consts[param.local_id])) - } else { - self.parent_generics() - .and_then(|g| g.find_type_or_const_param(param)) - // Remember that parent parameters come after parameters for self. - .map(|(idx, data)| (self.len_self() + idx, data)) - } - } - - pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> { - Some(self.find_lifetime(lifetime)?.0) - } - - fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> { - if lifetime.parent == self.def { - let idx = lifetime.local_id.into_raw().into_u32() as usize; - if idx >= self.params.lifetimes.len() { - return None; - } - Some(( - self.len_type_and_const_params() + idx, - &self.params.lifetimes[lifetime.local_id], - )) - } else { - self.parent_generics() - .and_then(|g| g.find_lifetime(lifetime)) - .map(|(idx, data)| (self.len_self() + idx, data)) - } - } - - pub(crate) fn parent_generics(&self) -> Option<&Generics> { - self.parent_generics.as_deref() - } - - pub(crate) fn parent_or_self(&self) -> &Generics { - self.parent_generics.as_deref().unwrap_or(self) - } - - /// Returns a Substitution that replaces each parameter by a bound variable. - pub(crate) fn bound_vars_subst( - &self, - db: &dyn HirDatabase, - debruijn: DebruijnIndex, - ) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().enumerate().map(|(idx, id)| match id { - GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::TypeParamId(_) => { - BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner) - } - GenericParamId::LifetimeParamId(_) => { - BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) - } - }), - ) - } - - /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). - pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().map(|id| match id { - GenericParamId::TypeParamId(id) => { - crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner) - } - GenericParamId::ConstParamId(id) => crate::to_placeholder_idx(db, id.into()) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::LifetimeParamId(id) => { - crate::lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner) - } - }), - ) - } -} - -fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { - let container = match def { - GenericDefId::FunctionId(it) => it.lookup(db).container, - GenericDefId::TypeAliasId(it) => it.lookup(db).container, - GenericDefId::ConstId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), - GenericDefId::AdtId(_) - | GenericDefId::TraitId(_) - | GenericDefId::ImplId(_) - | GenericDefId::TraitAliasId(_) => return None, - }; - - match container { - ItemContainerId::ImplId(it) => Some(it.into()), - ItemContainerId::TraitId(it) => Some(it.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - } -} - pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { let data = db.function_data(func); if data.has_unsafe_kw() { |