Save allocations for empty generic_defaults query results

This commit is contained in:
Lukas Wirth 2024-06-21 19:09:43 +02:00
parent 2761b1e236
commit 34ba8db3ed
3 changed files with 67 additions and 60 deletions

View file

@ -21,12 +21,12 @@ use crate::{
chalk_db, chalk_db,
consteval::ConstEvalError, consteval::ConstEvalError,
layout::{Layout, LayoutError}, layout::{Layout, LayoutError},
lower::GenericPredicates, lower::{GenericDefaults, GenericPredicates},
method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
mir::{BorrowckResult, MirBody, MirLowerError}, mir::{BorrowckResult, MirBody, MirLowerError},
Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, ImplTraits, Binders, CallableDefId, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult,
InferenceResult, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, TraitRef, Ty,
TraitRef, Ty, TyDefId, ValueTyDefId, TyDefId, ValueTyDefId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
@ -159,7 +159,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::generic_defaults_query)] #[salsa::invoke(crate::lower::generic_defaults_query)]
#[salsa::cycle(crate::lower::generic_defaults_recover)] #[salsa::cycle(crate::lower::generic_defaults_recover)]
fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>; fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;
#[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>; fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;

View file

@ -330,18 +330,15 @@ pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
) )
} }
pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>( pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
db: &dyn HirDatabase, db: &dyn HirDatabase,
count: usize,
generics: &Generics, generics: &Generics,
value: T, value: T,
) -> Binders<T> { ) -> Binders<T> {
let it = generics.iter_id().take(count);
Binders::new( Binders::new(
VariableKinds::from_iter( VariableKinds::from_iter(
Interner, Interner,
it.map(|x| match x { generics.iter_id().map(|x| match x {
hir_def::GenericParamId::ConstParamId(id) => { hir_def::GenericParamId::ConstParamId(id) => {
chalk_ir::VariableKind::Const(db.const_param_ty(id)) chalk_ir::VariableKind::Const(db.const_param_ty(id))
} }
@ -355,14 +352,6 @@ pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
) )
} }
pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
db: &dyn HirDatabase,
generics: &Generics,
value: T,
) -> Binders<T> {
make_binders_with_count(db, usize::MAX, generics, value)
}
// FIXME: get rid of this, just replace it by FnPointer // FIXME: get rid of this, just replace it by FnPointer
/// A function signature as seen by type inference: Several parameter types and /// A function signature as seen by type inference: Several parameter types and
/// one return type. /// one return type.

View file

@ -8,7 +8,7 @@
use std::{ use std::{
cell::{Cell, RefCell, RefMut}, cell::{Cell, RefCell, RefMut},
iter, iter,
ops::Not as _, ops::{self, Not as _},
}; };
use base_db::{ use base_db::{
@ -1693,9 +1693,11 @@ pub(crate) fn trait_environment_query(
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>); pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>);
impl GenericPredicates { impl ops::Deref for GenericPredicates {
pub fn iter(&self) -> impl Iterator<Item = &Binders<QuantifiedWhereClause>> + '_ + Clone { type Target = [Binders<crate::QuantifiedWhereClause>];
self.0.as_ref().into_iter().flat_map(Arc::as_ref)
fn deref(&self) -> &Self::Target {
self.0.as_deref().unwrap_or(&[])
} }
} }
@ -1767,68 +1769,84 @@ fn implicitly_sized_clauses<'a, 'subst: 'a>(
}) })
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericDefaults(Option<Arc<[Binders<crate::GenericArg>]>>);
impl ops::Deref for GenericDefaults {
type Target = [Binders<crate::GenericArg>];
fn deref(&self) -> &Self::Target {
self.0.as_deref().unwrap_or(&[])
}
}
/// Resolve the default type params from generics /// Resolve the default type params from generics
pub(crate) fn generic_defaults_query( pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults {
db: &dyn HirDatabase,
def: GenericDefId,
) -> Arc<[Binders<crate::GenericArg>]> {
let resolver = def.resolver(db.upcast());
let generic_params = generics(db.upcast(), def); let generic_params = generics(db.upcast(), def);
if generic_params.len() == 0 {
return GenericDefaults(None);
}
let resolver = def.resolver(db.upcast());
let parent_start_idx = generic_params.len_self(); let parent_start_idx = generic_params.len_self();
let ctx = TyLoweringContext::new(db, &resolver, def.into()) let ctx = TyLoweringContext::new(db, &resolver, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| { GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map(
match p { |(idx, (id, p))| {
GenericParamDataRef::TypeParamData(p) => { match p {
let mut ty = GenericParamDataRef::TypeParamData(p) => {
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t)); let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
// Each default can only refer to previous parameters. // Each default can only refer to previous parameters.
// Type variable default referring to parameter coming // Type variable default referring to parameter coming
// after it is forbidden (FIXME: report diagnostic) // after it is forbidden (FIXME: report diagnostic)
ty = fallback_bound_vars(ty, idx, parent_start_idx); fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx)
crate::make_binders(db, &generic_params, ty.cast(Interner)) });
} crate::make_binders(db, &generic_params, ty.cast(Interner))
GenericParamDataRef::ConstParamData(p) => { }
let GenericParamId::ConstParamId(id) = id else { GenericParamDataRef::ConstParamData(p) => {
unreachable!("Unexpected lifetime or type argument") let GenericParamId::ConstParamId(id) = id else {
}; unreachable!("Unexpected lifetime or type argument")
};
let mut val = p.default.as_ref().map_or_else( let mut val = p.default.as_ref().map_or_else(
|| unknown_const_as_generic(db.const_param_ty(id)), || unknown_const_as_generic(db.const_param_ty(id)),
|c| { |c| {
let c = ctx.lower_const(c, ctx.lower_ty(&p.ty)); let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
c.cast(Interner) c.cast(Interner)
}, },
); );
// Each default can only refer to previous parameters, see above. // Each default can only refer to previous parameters, see above.
val = fallback_bound_vars(val, idx, parent_start_idx); val = fallback_bound_vars(val, idx, parent_start_idx);
make_binders(db, &generic_params, val) make_binders(db, &generic_params, val)
}
GenericParamDataRef::LifetimeParamData(_) => {
make_binders(db, &generic_params, error_lifetime().cast(Interner))
}
} }
GenericParamDataRef::LifetimeParamData(_) => { },
make_binders(db, &generic_params, error_lifetime().cast(Interner)) ))))
}
}
}))
} }
pub(crate) fn generic_defaults_recover( pub(crate) fn generic_defaults_recover(
db: &dyn HirDatabase, db: &dyn HirDatabase,
_cycle: &Cycle, _cycle: &Cycle,
def: &GenericDefId, def: &GenericDefId,
) -> Arc<[Binders<crate::GenericArg>]> { ) -> GenericDefaults {
let generic_params = generics(db.upcast(), *def); let generic_params = generics(db.upcast(), *def);
if generic_params.len() == 0 {
return GenericDefaults(None);
}
// FIXME: this code is not covered in tests. // FIXME: this code is not covered in tests.
// we still need one default per parameter // we still need one default per parameter
Arc::from_iter(generic_params.iter_id().map(|id| { GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| {
let val = match id { let val = match id {
GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)),
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
}; };
crate::make_binders(db, &generic_params, val) crate::make_binders(db, &generic_params, val)
})) }))))
} }
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {