Unnamed repository; edit this file 'description' to name the repository.
Refactor the new solver's `Generics`
Chayim Refael Friedman 2 weeks ago
parent e6f3ca2 · commit 23f7297
-rw-r--r--crates/hir-ty/src/builtin_derive.rs14
-rw-r--r--crates/hir-ty/src/generics.rs2
-rw-r--r--crates/hir-ty/src/next_solver/generic_arg.rs82
-rw-r--r--crates/hir-ty/src/next_solver/generics.rs119
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs16
5 files changed, 98 insertions, 135 deletions
diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs
index 6a9b1671e7..f14e6e4e4d 100644
--- a/crates/hir-ty/src/builtin_derive.rs
+++ b/crates/hir-ty/src/builtin_derive.rs
@@ -12,7 +12,7 @@ use hir_def::{
use itertools::Itertools;
use la_arena::ArenaMap;
use rustc_type_ir::{
- AliasTyKind, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
+ AliasTyKind, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
inherent::{GenericArgs as _, IntoKind},
};
@@ -53,7 +53,10 @@ fn trait_args(trait_: BuiltinDeriveImplTrait, self_ty: Ty<'_>) -> GenericArgs<'_
}
}
-pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplId) -> Generics {
+pub(crate) fn generics_of<'db>(
+ interner: DbInterner<'db>,
+ id: BuiltinDeriveImplId,
+) -> Generics<'db> {
let db = interner.db;
let loc = id.loc(db);
match loc.trait_ {
@@ -65,15 +68,14 @@ pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplI
| BuiltinDeriveImplTrait::Ord
| BuiltinDeriveImplTrait::PartialOrd
| BuiltinDeriveImplTrait::Eq
- | BuiltinDeriveImplTrait::PartialEq => interner.generics_of(loc.adt.into()),
+ | BuiltinDeriveImplTrait::PartialEq => Generics::from_generic_def(db, loc.adt.into()),
BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
- let mut generics = interner.generics_of(loc.adt.into());
let trait_id = loc
.trait_
.get_id(interner.lang_items())
.expect("we don't pass the impl to the solver if we can't resolve the trait");
- generics.push_param(coerce_pointee_new_type_param(trait_id).into());
- generics
+ let additional_param = coerce_pointee_new_type_param(trait_id).into();
+ Generics::from_generic_def_plus_one(db, loc.adt.into(), additional_param)
}
}
}
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs
index 354acb1501..32482ca94b 100644
--- a/crates/hir-ty/src/generics.rs
+++ b/crates/hir-ty/src/generics.rs
@@ -294,7 +294,7 @@ pub(crate) struct ProvenanceSplit {
pub(crate) lifetimes: usize,
}
-pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
+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,
diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs
index 05955d060b..75df2b541e 100644
--- a/crates/hir-ty/src/next_solver/generic_arg.rs
+++ b/crates/hir-ty/src/next_solver/generic_arg.rs
@@ -8,6 +8,7 @@
use std::{hint::unreachable_unchecked, marker::PhantomData, ptr::NonNull};
+use arrayvec::ArrayVec;
use hir_def::{GenericDefId, GenericParamId};
use intern::InternedRef;
use rustc_type_ir::{
@@ -18,7 +19,6 @@ use rustc_type_ir::{
relate::{Relate, VarianceDiagInfo},
walk::TypeWalker,
};
-use smallvec::SmallVec;
use crate::next_solver::{
ConstInterned, RegionInterned, TyInterned, impl_foldable_for_interned_slice, interned_slice,
@@ -495,7 +495,47 @@ impl<'db> TypeFoldable<DbInterner<'db>> for StoredGenericArgs {
}
}
+trait GenericArgsBuilder<'db>: AsRef<[GenericArg<'db>]> {
+ fn push(&mut self, arg: GenericArg<'db>);
+}
+
+impl<'db, const N: usize> GenericArgsBuilder<'db> for ArrayVec<GenericArg<'db>, N> {
+ fn push(&mut self, arg: GenericArg<'db>) {
+ self.push(arg);
+ }
+}
+
+impl<'db> GenericArgsBuilder<'db> for Vec<GenericArg<'db>> {
+ fn push(&mut self, arg: GenericArg<'db>) {
+ self.push(arg);
+ }
+}
+
impl<'db> GenericArgs<'db> {
+ #[inline(always)]
+ fn fill_builder<F>(
+ args: &mut impl GenericArgsBuilder<'db>,
+ defs: &Generics<'db>,
+ mut mk_kind: F,
+ ) where
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ {
+ defs.iter_id().enumerate().for_each(|(idx, param_id)| {
+ let new_arg = mk_kind(idx as u32, param_id, args.as_ref());
+ args.push(new_arg);
+ });
+ }
+
+ #[cold]
+ fn fill_vec_builder<F>(defs: &Generics<'db>, count: usize, mk_kind: F) -> GenericArgs<'db>
+ where
+ F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
+ {
+ let mut args = Vec::with_capacity(count);
+ Self::fill_builder(&mut args, defs, mk_kind);
+ GenericArgs::new_from_slice(&args)
+ }
+
/// Creates an `GenericArgs` for generic parameter definitions,
/// by calling closures to obtain each kind.
/// The closures get to observe the `GenericArgs` as they're
@@ -504,7 +544,7 @@ impl<'db> GenericArgs<'db> {
pub fn for_item<F>(
interner: DbInterner<'db>,
def_id: SolverDefId,
- mut mk_kind: F,
+ mk_kind: F,
) -> GenericArgs<'db>
where
F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
@@ -513,12 +553,14 @@ impl<'db> GenericArgs<'db> {
let count = defs.count();
if count == 0 {
- return Default::default();
+ GenericArgs::default()
+ } else if count <= 10 {
+ let mut args = ArrayVec::<_, 10>::new();
+ Self::fill_builder(&mut args, &defs, mk_kind);
+ GenericArgs::new_from_slice(&args)
+ } else {
+ Self::fill_vec_builder(&defs, count, mk_kind)
}
-
- let mut args = SmallVec::with_capacity(count);
- Self::fill_item(&mut args, interner, defs, &mut mk_kind);
- interner.mk_args(&args)
}
/// Creates an all-error `GenericArgs`.
@@ -577,32 +619,6 @@ impl<'db> GenericArgs<'db> {
})
}
- fn fill_item<F>(
- args: &mut SmallVec<[GenericArg<'db>; 8]>,
- interner: DbInterner<'_>,
- defs: Generics,
- mk_kind: &mut F,
- ) where
- F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
- {
- if let Some(def_id) = defs.parent {
- let parent_defs = interner.generics_of(def_id.into());
- Self::fill_item(args, interner, parent_defs, mk_kind);
- }
- Self::fill_single(args, &defs, mk_kind);
- }
-
- fn fill_single<F>(args: &mut SmallVec<[GenericArg<'db>; 8]>, defs: &Generics, mk_kind: &mut F)
- where
- F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
- {
- args.reserve(defs.own_params.len());
- for param in &defs.own_params {
- let kind = mk_kind(args.len() as u32, param.id, args);
- args.push(kind);
- }
- }
-
pub fn types(self) -> impl Iterator<Item = Ty<'db>> {
self.iter().filter_map(|it| it.as_type())
}
diff --git a/crates/hir-ty/src/next_solver/generics.rs b/crates/hir-ty/src/next_solver/generics.rs
index f31de21796..570e245922 100644
--- a/crates/hir-ty/src/next_solver/generics.rs
+++ b/crates/hir-ty/src/next_solver/generics.rs
@@ -1,117 +1,60 @@
//! Things related to generics in the next-trait-solver.
-use hir_def::{
- ConstParamId, GenericDefId, GenericParamId, LifetimeParamId, TypeOrConstParamId, TypeParamId,
- hir::generics::{GenericParams, TypeOrConstParamData},
-};
-use rustc_type_ir::inherent::GenericsOf;
+use hir_def::{GenericDefId, GenericParamId};
-use crate::generics::parent_generic_def;
+use crate::db::HirDatabase;
use super::SolverDefId;
use super::DbInterner;
-pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics {
- let mk_lt = |parent, index, local_id| {
- let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id });
- GenericParamDef { index, id }
- };
- let mk_ty = |parent, index, local_id, p: &TypeOrConstParamData| {
- let id = TypeOrConstParamId { parent, local_id };
- let id = match p {
- TypeOrConstParamData::TypeParamData(_) => {
- GenericParamId::TypeParamId(TypeParamId::from_unchecked(id))
- }
- TypeOrConstParamData::ConstParamData(_) => {
- GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
- }
- };
- GenericParamDef { index, id }
- };
- let own_params_for_generic_params = |parent, params: &GenericParams| {
- let mut result = Vec::with_capacity(params.len());
- let mut type_and_consts = params.iter_type_or_consts();
- let mut index = 0;
- if let Some(self_param) = params.trait_self_param() {
- result.push(mk_ty(parent, 0, self_param, &params[self_param]));
- type_and_consts.next();
- index += 1;
- }
- result.extend(params.iter_lt().map(|(local_id, _data)| {
- let lt = mk_lt(parent, index, local_id);
- index += 1;
- lt
- }));
- result.extend(type_and_consts.map(|(local_id, data)| {
- let ty = mk_ty(parent, index, local_id, data);
- index += 1;
- ty
- }));
- result
- };
-
+pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<'_> {
let db = interner.db;
- let (parent, own_params) = match (def.try_into(), def) {
- (Ok(def), _) => (
- parent_generic_def(db, def),
- own_params_for_generic_params(def, GenericParams::of(db, def)),
- ),
- (_, SolverDefId::InternedOpaqueTyId(id)) => {
- match db.lookup_intern_impl_trait_id(id) {
- crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => {
- // The opaque type itself does not have generics - only the parent function
- (Some(GenericDefId::FunctionId(function_id)), vec![])
- }
- crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => {
- (Some(type_alias_id.into()), Vec::new())
- }
- }
- }
+ let def = match (def.try_into(), def) {
+ (Ok(def), _) => def,
+ (_, SolverDefId::InternedOpaqueTyId(id)) => match db.lookup_intern_impl_trait_id(id) {
+ crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => function_id.into(),
+ crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => type_alias_id.into(),
+ },
(_, SolverDefId::BuiltinDeriveImplId(id)) => {
return crate::builtin_derive::generics_of(interner, id);
}
_ => panic!("No generics for {def:?}"),
};
- let parent_generics = parent.map(|def| Box::new(generics(interner, def.into())));
- Generics {
- parent,
- parent_count: parent_generics.map_or(0, |g| g.parent_count + g.own_params.len()),
- own_params,
- }
+ Generics::from_generic_def(db, def)
}
#[derive(Debug)]
-pub struct Generics {
- pub parent: Option<GenericDefId>,
- pub parent_count: usize,
- pub own_params: Vec<GenericParamDef>,
+pub struct Generics<'db> {
+ generics: crate::generics::Generics<'db>,
+ /// This is used for builtin derives, specifically `CoercePointee`.
+ additional_param: Option<GenericParamId>,
}
-impl Generics {
- pub(crate) fn push_param(&mut self, id: GenericParamId) {
- let index = self.count() as u32;
- self.own_params.push(GenericParamDef { index, id });
+impl<'db> Generics<'db> {
+ pub(crate) fn from_generic_def(db: &'db dyn HirDatabase, def: GenericDefId) -> Generics<'db> {
+ Generics { generics: crate::generics::generics(db, def), additional_param: None }
}
-}
-#[derive(Debug)]
-pub struct GenericParamDef {
- index: u32,
- pub(crate) id: GenericParamId,
-}
+ pub(crate) fn from_generic_def_plus_one(
+ db: &'db dyn HirDatabase,
+ def: GenericDefId,
+ additional_param: GenericParamId,
+ ) -> Generics<'db> {
+ Generics {
+ generics: crate::generics::generics(db, def),
+ additional_param: Some(additional_param),
+ }
+ }
-impl GenericParamDef {
- /// Returns the index of the param on the self generics only
- /// (i.e. not including parent generics)
- pub fn index(&self) -> u32 {
- self.index
+ pub(super) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> {
+ self.generics.iter_id().chain(self.additional_param)
}
}
-impl<'db> rustc_type_ir::inherent::GenericsOf<DbInterner<'db>> for Generics {
+impl<'db> rustc_type_ir::inherent::GenericsOf<DbInterner<'db>> for Generics<'db> {
fn count(&self) -> usize {
- self.parent_count + self.own_params.len()
+ self.generics.len() + usize::from(self.additional_param.is_some())
}
}
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index fc83ebc625..bdbcaee4f6 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -967,7 +967,7 @@ impl<'db> Interner for DbInterner<'db> {
type Clause = Clause<'db>;
type Clauses = Clauses<'db>;
- type GenericsOf = Generics;
+ type GenericsOf = Generics<'db>;
type VariancesOf = VariancesOf<'db>;
@@ -1124,12 +1124,14 @@ impl<'db> Interner for DbInterner<'db> {
def_id: Self::DefId,
args: Self::GenericArgs,
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
- let trait_def_id = self.parent(def_id);
- let trait_generics = self.generics_of(trait_def_id);
- let trait_args =
- GenericArgs::new_from_slice(&args.as_slice()[0..trait_generics.own_params.len()]);
- let alias_args = &args.as_slice()[trait_generics.own_params.len()..];
- (TraitRef::new_from_args(self, trait_def_id.try_into().unwrap(), trait_args), alias_args)
+ let SolverDefId::TraitId(trait_def_id) = self.parent(def_id) else {
+ panic!("expected a trait");
+ };
+ let trait_generics = crate::generics::generics(self.db, trait_def_id.into());
+ let trait_generics_len = trait_generics.len();
+ let trait_args = GenericArgs::new_from_slice(&args.as_slice()[..trait_generics_len]);
+ let alias_args = &args.as_slice()[trait_generics_len..];
+ (TraitRef::new_from_args(self, trait_def_id.into(), trait_args), alias_args)
}
fn check_args_compatible(self, _def_id: Self::DefId, _args: Self::GenericArgs) -> bool {