Intern Substitutions

(Costs a bit of performance, reduces memory usage on RA by ~10%.)
This commit is contained in:
Florian Diebold 2021-04-08 18:25:18 +02:00
parent a169fa6a83
commit be03db0e3a
8 changed files with 34 additions and 27 deletions

View file

@ -1825,7 +1825,7 @@ impl Type {
Solution::Unique(s) => s Solution::Unique(s) => s
.value .value
.subst .subst
.interned() .as_slice(&Interner)
.first() .first()
.map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())), .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
Solution::Ambig(_) => None, Solution::Ambig(_) => None,

View file

@ -265,7 +265,7 @@ impl HirDisplay for ProjectionTy {
write!(f, " as {}", trait_.name)?; write!(f, " as {}", trait_.name)?;
if self.substitution.len(&Interner) > 1 { if self.substitution.len(&Interner) > 1 {
write!(f, "<")?; write!(f, "<")?;
f.write_joined(&self.substitution.interned()[1..], ", ")?; f.write_joined(&self.substitution.as_slice(&Interner)[1..], ", ")?;
write!(f, ">")?; write!(f, ">")?;
} }
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?; write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
@ -416,7 +416,7 @@ impl HirDisplay for Ty {
write!(f, ",)")?; write!(f, ",)")?;
} else { } else {
write!(f, "(")?; write!(f, "(")?;
f.write_joined(&*substs.interned(), ", ")?; f.write_joined(&*substs.as_slice(&Interner), ", ")?;
write!(f, ")")?; write!(f, ")")?;
} }
} }
@ -444,7 +444,7 @@ impl HirDisplay for Ty {
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if total_len > 0 { if total_len > 0 {
write!(f, "<")?; write!(f, "<")?;
f.write_joined(&parameters.interned()[..total_len], ", ")?; f.write_joined(&parameters.as_slice(&Interner)[..total_len], ", ")?;
write!(f, ">")?; write!(f, ">")?;
} }
} }
@ -491,7 +491,7 @@ impl HirDisplay for Ty {
.map(|generic_def_id| f.db.generic_defaults(generic_def_id)) .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
.filter(|defaults| !defaults.is_empty()) .filter(|defaults| !defaults.is_empty())
{ {
None => parameters.interned().as_ref(), None => parameters.as_slice(&Interner),
Some(default_parameters) => { Some(default_parameters) => {
let mut default_from = 0; let mut default_from = 0;
for (i, parameter) in parameters.iter(&Interner).enumerate() { for (i, parameter) in parameters.iter(&Interner).enumerate() {
@ -515,11 +515,11 @@ impl HirDisplay for Ty {
} }
} }
} }
&parameters.interned()[0..default_from] &parameters.as_slice(&Interner)[0..default_from]
} }
} }
} else { } else {
parameters.interned().as_ref() parameters.as_slice(&Interner)
}; };
if !parameters_to_write.is_empty() { if !parameters_to_write.is_empty() {
write!(f, "<")?; write!(f, "<")?;
@ -542,7 +542,7 @@ impl HirDisplay for Ty {
write!(f, "{}::{}", trait_.name, type_alias_data.name)?; write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
if parameters.len(&Interner) > 0 { if parameters.len(&Interner) > 0 {
write!(f, "<")?; write!(f, "<")?;
f.write_joined(&*parameters.interned(), ", ")?; f.write_joined(&*parameters.as_slice(&Interner), ", ")?;
write!(f, ">")?; write!(f, ">")?;
} }
} else { } else {
@ -749,13 +749,13 @@ fn write_bounds_like_dyn_trait(
// existential) here, which is the only thing that's // existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it // possible in actual Rust, and hence don't print it
write!(f, "{}", f.db.trait_data(trait_).name)?; write!(f, "{}", f.db.trait_data(trait_).name)?;
if let [_, params @ ..] = &*trait_ref.substitution.interned().as_slice() { if let [_, params @ ..] = &*trait_ref.substitution.as_slice(&Interner) {
if is_fn_trait { if is_fn_trait {
if let Some(args) = if let Some(args) =
params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple()) params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
{ {
write!(f, "(")?; write!(f, "(")?;
f.write_joined(&*args.interned(), ", ")?; f.write_joined(args.as_slice(&Interner), ", ")?;
write!(f, ")")?; write!(f, ")")?;
} }
} else if !params.is_empty() { } else if !params.is_empty() {
@ -814,7 +814,7 @@ fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<()
write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?; write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
if tr.substitution.len(&Interner) > 1 { if tr.substitution.len(&Interner) > 1 {
write!(f, "<")?; write!(f, "<")?;
f.write_joined(&tr.substitution.interned()[1..], ", ")?; f.write_joined(&tr.substitution.as_slice(&Interner)[1..], ", ")?;
write!(f, ">")?; write!(f, ">")?;
} }
Ok(()) Ok(())

View file

@ -462,7 +462,7 @@ impl<'a> InferenceContext<'a> {
}; };
match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) { match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| { TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
substs.interned().get(idx).map(|a| a.assert_ty_ref(&Interner)).cloned() substs.as_slice(&Interner).get(idx).map(|a| a.assert_ty_ref(&Interner)).cloned()
}), }),
TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => { TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
let local_id = self.db.struct_data(*s).variant_data.field(name)?; let local_id = self.db.struct_data(*s).variant_data.field(name)?;

View file

@ -122,7 +122,7 @@ impl<'a> InferenceContext<'a> {
let ty = match &body[pat] { let ty = match &body[pat] {
&Pat::Tuple { ref args, ellipsis } => { &Pat::Tuple { ref args, ellipsis } => {
let expectations = match expected.as_tuple() { let expectations = match expected.as_tuple() {
Some(parameters) => &*parameters.interned().as_slice(), Some(parameters) => &*parameters.as_slice(&Interner),
_ => &[], _ => &[],
}; };
@ -242,7 +242,7 @@ impl<'a> InferenceContext<'a> {
let (inner_ty, alloc_ty) = match expected.as_adt() { let (inner_ty, alloc_ty) = match expected.as_adt() {
Some((adt, subst)) if adt == box_adt => ( Some((adt, subst)) if adt == box_adt => (
subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(), subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
subst.interned().get(1).and_then(|a| a.ty(&Interner).cloned()), subst.as_slice(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()),
), ),
_ => (self.result.standard_types.unknown.clone(), None), _ => (self.result.standard_types.unknown.clone(), None),
}; };

View file

@ -101,7 +101,7 @@ impl<'a> InferenceContext<'a> {
let substs = ctx.substs_from_path(path, typable, true); let substs = ctx.substs_from_path(path, typable, true);
let ty = TyBuilder::value_ty(self.db, typable) let ty = TyBuilder::value_ty(self.db, typable)
.use_parent_substs(&parent_substs) .use_parent_substs(&parent_substs)
.fill(substs.interned()[parent_substs.len(&Interner)..].iter().cloned()) .fill(substs.as_slice(&Interner)[parent_substs.len(&Interner)..].iter().cloned())
.build(); .build();
Some(ty) Some(ty)
} }

View file

@ -109,7 +109,7 @@ pub type WhereClause = chalk_ir::WhereClause<Interner>;
pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution { pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
Substitution::from_iter( Substitution::from_iter(
&Interner, &Interner,
s.interned()[..std::cmp::min(s.len(&Interner), n)].iter().cloned(), s.as_slice(&Interner)[..std::cmp::min(s.len(&Interner), n)].iter().cloned(),
) )
} }
@ -187,7 +187,7 @@ impl CallableSig {
.shifted_out_to(&Interner, DebruijnIndex::ONE) .shifted_out_to(&Interner, DebruijnIndex::ONE)
.expect("unexpected lifetime vars in fn ptr") .expect("unexpected lifetime vars in fn ptr")
.0 .0
.interned() .as_slice(&Interner)
.iter() .iter()
.map(|arg| arg.assert_ty_ref(&Interner).clone()) .map(|arg| arg.assert_ty_ref(&Interner).clone())
.collect(), .collect(),

View file

@ -3,11 +3,12 @@
use super::tls; use super::tls;
use base_db::salsa::InternId; use base_db::salsa::InternId;
use chalk_ir::{GenericArg, Goal, GoalData}; use chalk_ir::{Goal, GoalData};
use hir_def::{ use hir_def::{
intern::{impl_internable, InternStorage, Internable, Interned}, intern::{impl_internable, InternStorage, Internable, Interned},
TypeAliasId, TypeAliasId,
}; };
use crate::GenericArg;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{fmt, sync::Arc}; use std::{fmt, sync::Arc};
@ -32,7 +33,13 @@ pub(crate) type Variances = chalk_ir::Variances<Interner>;
#[derive(PartialEq, Eq, Hash, Debug)] #[derive(PartialEq, Eq, Hash, Debug)]
pub struct InternedVariableKindsInner(Vec<chalk_ir::VariableKind<Interner>>); pub struct InternedVariableKindsInner(Vec<chalk_ir::VariableKind<Interner>>);
impl_internable!(InternedVariableKindsInner,); #[derive(PartialEq, Eq, Hash, Debug)]
pub struct InternedSubstitutionInner(SmallVec<[GenericArg; 2]>);
impl_internable!(
InternedVariableKindsInner,
InternedSubstitutionInner,
);
impl chalk_ir::interner::Interner for Interner { impl chalk_ir::interner::Interner for Interner {
type InternedType = Arc<chalk_ir::TyData<Self>>; type InternedType = Arc<chalk_ir::TyData<Self>>;
@ -42,7 +49,7 @@ impl chalk_ir::interner::Interner for Interner {
type InternedGenericArg = chalk_ir::GenericArgData<Self>; type InternedGenericArg = chalk_ir::GenericArgData<Self>;
type InternedGoal = Arc<GoalData<Self>>; type InternedGoal = Arc<GoalData<Self>>;
type InternedGoals = Vec<Goal<Self>>; type InternedGoals = Vec<Goal<Self>>;
type InternedSubstitution = SmallVec<[GenericArg<Self>; 2]>; type InternedSubstitution = Interned<InternedSubstitutionInner>;
type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>; type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>;
type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>;
type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
@ -107,7 +114,7 @@ impl chalk_ir::interner::Interner for Interner {
} }
fn debug_generic_arg( fn debug_generic_arg(
parameter: &GenericArg<Interner>, parameter: &GenericArg,
fmt: &mut fmt::Formatter<'_>, fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> { ) -> Option<fmt::Result> {
tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt)))
@ -272,16 +279,16 @@ impl chalk_ir::interner::Interner for Interner {
fn intern_substitution<E>( fn intern_substitution<E>(
&self, &self,
data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, data: impl IntoIterator<Item = Result<GenericArg, E>>,
) -> Result<Self::InternedSubstitution, E> { ) -> Result<Self::InternedSubstitution, E> {
data.into_iter().collect() Ok(Interned::new(InternedSubstitutionInner(data.into_iter().collect::<Result<SmallVec<_>, _>>()?)))
} }
fn substitution_data<'a>( fn substitution_data<'a>(
&self, &self,
substitution: &'a Self::InternedSubstitution, substitution: &'a Self::InternedSubstitution,
) -> &'a [GenericArg<Self>] { ) -> &'a [GenericArg] {
substitution &substitution.as_ref().0
} }
fn intern_program_clause( fn intern_program_clause(

View file

@ -99,7 +99,7 @@ pub(super) fn generic_predicate_to_inline_bound(
// have the expected self type // have the expected self type
return None; return None;
} }
let args_no_self = trait_ref.substitution.interned()[1..] let args_no_self = trait_ref.substitution.as_slice(&Interner)[1..]
.iter() .iter()
.map(|ty| ty.clone().cast(&Interner)) .map(|ty| ty.clone().cast(&Interner))
.collect(); .collect();
@ -111,7 +111,7 @@ pub(super) fn generic_predicate_to_inline_bound(
return None; return None;
} }
let trait_ = projection_ty.trait_(db); let trait_ = projection_ty.trait_(db);
let args_no_self = projection_ty.substitution.interned()[1..] let args_no_self = projection_ty.substitution.as_slice(&Interner)[1..]
.iter() .iter()
.map(|ty| ty.clone().cast(&Interner)) .map(|ty| ty.clone().cast(&Interner))
.collect(); .collect();