Remove some allocations

This commit is contained in:
Lukas Wirth 2021-12-10 20:01:24 +01:00
parent c81aa68afe
commit 1bbc255ec5
13 changed files with 78 additions and 58 deletions

View File

@ -12,7 +12,10 @@
},
Interner, TraitRefExt, WhereClause,
};
use syntax::ast::{self, HasName};
use syntax::{
ast::{self, HasName},
SmolStr,
};
use crate::{
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
@ -247,7 +250,8 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect();
let krate = self.id.parent.krate(f.db).id;
let sized_trait =
f.db.lang_item(krate, "sized".into()).and_then(|lang_item| lang_item.as_trait());
f.db.lang_item(krate, SmolStr::new_inline("sized"))
.and_then(|lang_item| lang_item.as_trait());
let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
_ => false,

View File

@ -2427,7 +2427,7 @@ pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
let krate = self.krate;
let std_future_trait =
db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait());
db.lang_item(krate, SmolStr::new_inline("future_trait")).and_then(|it| it.as_trait());
let std_future_trait = match std_future_trait {
Some(it) => it,
None => return false,
@ -2516,7 +2516,7 @@ pub fn normalize_trait_assoc_type(
}
pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
let lang_item = db.lang_item(self.krate, SmolStr::new("copy"));
let lang_item = db.lang_item(self.krate, SmolStr::new_inline("copy"));
let copy_trait = match lang_item {
Some(LangItemTarget::TraitId(it)) => it,
_ => return false,

View File

@ -10,6 +10,7 @@
use hir_def::lang_item::LangItemTarget;
use hir_expand::name::name;
use limit::Limit;
use syntax::SmolStr;
use tracing::{info, warn};
use crate::{
@ -71,7 +72,10 @@ fn next(&mut self) -> Option<Self::Item> {
}
let (kind, new_ty) = if let Some(derefed) = builtin_deref(&self.ty.value) {
(AutoderefKind::Builtin, Canonical { value: derefed, binders: self.ty.binders.clone() })
(
AutoderefKind::Builtin,
Canonical { value: derefed.clone(), binders: self.ty.binders.clone() },
)
} else {
(
AutoderefKind::Overloaded,
@ -110,15 +114,17 @@ pub(crate) fn deref(
) -> Option<Canonical<Ty>> {
let _p = profile::span("deref");
match builtin_deref(&ty.goal.value) {
Some(derefed) => Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }),
Some(derefed) => {
Some(Canonical { value: derefed.clone(), binders: ty.goal.binders.clone() })
}
None => deref_by_trait(db, krate, ty),
}
}
fn builtin_deref(ty: &Ty) -> Option<Ty> {
fn builtin_deref(ty: &Ty) -> Option<&Ty> {
match ty.kind(&Interner) {
TyKind::Ref(.., ty) => Some(ty.clone()),
TyKind::Raw(.., ty) => Some(ty.clone()),
TyKind::Ref(.., ty) => Some(ty),
TyKind::Raw(.., ty) => Some(ty),
_ => None,
}
}
@ -129,7 +135,7 @@ fn deref_by_trait(
ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> {
let _p = profile::span("deref_by_trait");
let deref_trait = match db.lang_item(krate, "deref".into())? {
let deref_trait = match db.lang_item(krate, SmolStr::new_inline("deref"))? {
LangItemTarget::TraitId(it) => it,
_ => return None,
};

View File

@ -3,6 +3,7 @@
use std::sync::Arc;
use cov_mark::hit;
use syntax::SmolStr;
use tracing::debug;
use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@ -213,7 +214,7 @@ fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatu
crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
if let Some((future_trait, future_output)) = self
.db
.lang_item(self.krate, "future_trait".into())
.lang_item(self.krate, SmolStr::new_inline("future_trait"))
.and_then(|item| item.as_trait())
.and_then(|trait_| {
let alias =
@ -419,7 +420,7 @@ pub(crate) fn associated_ty_data_query(
if !ctx.unsized_types.borrow().contains(&self_ty) {
let sized_trait = resolver
.krate()
.and_then(|krate| db.lang_item(krate, "sized".into()))
.and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
let sized_bound = sized_trait.into_iter().map(|sized_trait| {
let trait_bound =

View File

@ -6,6 +6,7 @@
type_ref::Rawness,
FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
};
use syntax::SmolStr;
use crate::{
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
@ -187,7 +188,7 @@ fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereC
ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
let krate = def.module(db.upcast()).krate();
if let Some(future_trait) = db
.lang_item(krate, "future_trait".into())
.lang_item(krate, SmolStr::new_inline("future_trait"))
.and_then(|item| item.as_trait())
{
// This is only used by type walking.

View File

@ -50,6 +50,7 @@
use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId};
use smallvec::{smallvec, SmallVec};
use stdx::never;
use syntax::SmolStr;
use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind};
@ -905,7 +906,7 @@ fn is_field_list_non_exhaustive(variant_id: VariantId, cx: &MatchCheckCtx<'_>) -
fn adt_is_box(adt: hir_def::AdtId, cx: &MatchCheckCtx<'_>) -> bool {
use hir_def::lang_item::LangItemTarget;
match cx.db.lang_item(cx.module.krate(), "owned_box".into()) {
match cx.db.lang_item(cx.module.krate(), SmolStr::new_inline("owned_box")) {
Some(LangItemTarget::StructId(box_id)) => adt == box_id.into(),
_ => false,
}

View File

@ -20,6 +20,7 @@
};
use hir_expand::{hygiene::Hygiene, name::Name};
use itertools::Itertools;
use syntax::SmolStr;
use crate::{
const_from_placeholder_idx,
@ -774,8 +775,9 @@ fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
match self {
Self::NotSized => false,
Self::Sized { anchor } => {
let sized_trait =
db.lang_item(anchor, "sized".into()).and_then(|lang_item| lang_item.as_trait());
let sized_trait = db
.lang_item(anchor, SmolStr::new_inline("sized"))
.and_then(|lang_item| lang_item.as_trait());
Some(trait_) == sized_trait
}
}

View File

@ -10,6 +10,7 @@
use chalk_ir::{cast::Cast, Goal, Mutability, TyVariableKind};
use hir_def::{expr::ExprId, lang_item::LangItemTarget};
use stdx::always;
use syntax::SmolStr;
use crate::{
autoderef::{Autoderef, AutoderefKind},
@ -536,10 +537,11 @@ fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> CoerceResult {
reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
let krate = self.resolver.krate().unwrap();
let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) {
Some(LangItemTarget::TraitId(trait_)) => trait_,
_ => return Err(TypeError),
};
let coerce_unsized_trait =
match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
Some(LangItemTarget::TraitId(trait_)) => trait_,
_ => return Err(TypeError),
};
let coerce_unsized_tref = {
let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);

View File

@ -28,7 +28,7 @@
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use stdx::impl_from;
use syntax::ast;
use syntax::{ast, SmolStr};
use crate::all_super_traits;
use crate::{
@ -797,7 +797,7 @@ pub(crate) fn lower_type_bound(
let sized_trait = self
.resolver
.krate()
.and_then(|krate| self.db.lang_item(krate, "sized".into()))
.and_then(|krate| self.db.lang_item(krate, SmolStr::new_inline("sized")))
.and_then(|lang_item| lang_item.as_trait());
// Don't lower associated type bindings as the only possible relaxed trait bound
// `?Sized` has no of them.
@ -895,7 +895,7 @@ fn lower_impl_trait(
let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
let sized_trait = ctx
.db
.lang_item(krate, "sized".into())
.lang_item(krate, SmolStr::new_inline("sized"))
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
let sized_clause = sized_trait.map(|trait_id| {
let clause = WhereClause::Implemented(TraitRef {
@ -1200,7 +1200,7 @@ fn implicitly_sized_clauses<'a>(
let generic_args = &substitution.as_slice(&Interner)[is_trait_def as usize..];
let sized_trait = resolver
.krate()
.and_then(|krate| db.lang_item(krate, "sized".into()))
.and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
sized_trait.into_iter().flat_map(move |sized_trait| {

View File

@ -541,9 +541,10 @@ pub fn iterate_method_candidates_dyn(
// types*.
let deref_chain = autoderef_method_receiver(db, krate, ty);
for i in 0..deref_chain.len() {
let mut deref_chains = stdx::slice_tails(&deref_chain);
deref_chains.try_for_each(|deref_chain| {
iterate_method_candidates_with_autoref(
&deref_chain[i..],
deref_chain,
db,
env.clone(),
krate,
@ -551,9 +552,8 @@ pub fn iterate_method_candidates_dyn(
visible_from_module,
name,
callback,
)?;
}
ControlFlow::Continue(())
)
})
}
LookupMode::Path => {
// No autoderef for path lookups
@ -716,15 +716,14 @@ fn iterate_trait_method_candidates(
// if ty is `dyn Trait`, the trait doesn't need to be in scope
let inherent_trait =
self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
let env_traits = match self_ty.value.kind(&Interner) {
TyKind::Placeholder(_) => {
// if we have `T: Trait` in the param env, the trait doesn't need to be in scope
let env_traits = matches!(self_ty.value.kind(&Interner), TyKind::Placeholder(_))
// if we have `T: Trait` in the param env, the trait doesn't need to be in scope
.then(|| {
env.traits_in_scope_from_clauses(self_ty.value.clone())
.flat_map(|t| all_super_traits(db.upcast(), t))
.collect()
}
_ => Vec::new(),
};
})
.into_iter()
.flatten();
let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
'traits: for t in traits {
@ -747,10 +746,10 @@ fn iterate_trait_method_candidates(
// trait, but if we find out it doesn't, we'll skip the rest of the
// iteration
let mut known_implemented = false;
for (_name, item) in data.items.iter() {
for &(_, item) in data.items.iter() {
// Don't pass a `visible_from_module` down to `is_valid_candidate`,
// since only inherent methods should be included into visibility checking.
if !is_valid_candidate(db, env.clone(), name, receiver_ty, *item, self_ty, None) {
if !is_valid_candidate(db, env.clone(), name, receiver_ty, item, self_ty, None) {
continue;
}
if !known_implemented {
@ -761,7 +760,7 @@ fn iterate_trait_method_candidates(
}
known_implemented = true;
// FIXME: we shouldn't be ignoring the binders here
callback(self_ty, *item)?
callback(self_ty, item)?
}
}
ControlFlow::Continue(())
@ -774,18 +773,14 @@ fn filter_inherent_impls_for_self_ty<'i>(
// inherent methods on arrays are fingerprinted as [T; {unknown}], so we must also consider them when
// resolving a method call on an array with a known len
let array_impls = {
if let TyKind::Array(parameters, array_len) = self_ty.kind(&Interner) {
if !array_len.is_unknown() {
match self_ty.kind(&Interner) {
TyKind::Array(parameters, array_len) if !array_len.is_unknown() => {
let unknown_array_len_ty =
TyKind::Array(parameters.clone(), consteval::usize_const(None))
.intern(&Interner);
TyKind::Array(parameters.clone(), consteval::usize_const(None));
Some(impls.for_self_ty(&unknown_array_len_ty))
} else {
None
Some(impls.for_self_ty(&unknown_array_len_ty.intern(&Interner)))
}
} else {
None
_ => None,
}
}
.into_iter()

View File

@ -9,6 +9,7 @@
use base_db::CrateId;
use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;
use syntax::SmolStr;
use crate::{
db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
@ -169,7 +170,7 @@ pub enum FnTrait {
}
impl FnTrait {
fn lang_item_name(self) -> &'static str {
const fn lang_item_name(self) -> &'static str {
match self {
FnTrait::FnOnce => "fn_once",
FnTrait::FnMut => "fn_mut",
@ -178,7 +179,7 @@ fn lang_item_name(self) -> &'static str {
}
pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
let target = db.lang_item(krate, self.lang_item_name().into())?;
let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
match target {
LangItemTarget::TraitId(t) => Some(t),
_ => None,

View File

@ -18,6 +18,8 @@
};
use hir_expand::name::{name, Name};
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
use syntax::SmolStr;
use crate::{
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind,
@ -26,16 +28,16 @@
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
[
db.lang_item(krate, "fn".into()),
db.lang_item(krate, "fn_mut".into()),
db.lang_item(krate, "fn_once".into()),
db.lang_item(krate, SmolStr::new_inline("fn")),
db.lang_item(krate, SmolStr::new_inline("fn_mut")),
db.lang_item(krate, SmolStr::new_inline("fn_once")),
]
.into_iter()
.flatten()
.flat_map(|it| it.as_trait())
}
fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
let resolver = trait_.resolver(db);
// returning the iterator directly doesn't easily work because of
// lifetime problems, but since there usually shouldn't be more than a
@ -100,13 +102,13 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
/// Returns an iterator over the whole super trait hierarchy (including the
/// trait itself).
pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
// we need to take care a bit here to avoid infinite loops in case of cycles
// (i.e. if we have `trait A: B; trait B: A;`)
let mut result = vec![trait_];
let mut result = smallvec![trait_];
let mut i = 0;
while i < result.len() {
let t = result[i];
while let Some(&t) = result.get(i) {
// yeah this is quadratic, but trait hierarchies should be flat
// enough that this doesn't matter
for tt in direct_super_traits(db, t) {

View File

@ -193,6 +193,11 @@ pub fn iter_eq_by<I, I2, F>(this: I2, other: I, mut eq: F) -> bool
}
}
/// Returns all final segments of the argument, longest first.
pub fn slice_tails<T>(this: &[T]) -> impl Iterator<Item = &[T]> {
(0..this.len()).map(|i| &this[i..])
}
#[cfg(test)]
mod tests {
use super::*;