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 @@ use hir_ty::{
}, },
Interner, TraitRefExt, WhereClause, Interner, TraitRefExt, WhereClause,
}; };
use syntax::ast::{self, HasName}; use syntax::{
ast::{self, HasName},
SmolStr,
};
use crate::{ use crate::{
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility, Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
@ -247,7 +250,8 @@ impl HirDisplay for TypeParam {
bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect(); bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect();
let krate = self.id.parent.krate(f.db).id; let krate = self.id.parent.krate(f.db).id;
let sized_trait = 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() { let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait, WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
_ => false, _ => false,

View file

@ -2427,7 +2427,7 @@ impl Type {
let krate = self.krate; let krate = self.krate;
let std_future_trait = 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 { let std_future_trait = match std_future_trait {
Some(it) => it, Some(it) => it,
None => return false, None => return false,
@ -2516,7 +2516,7 @@ impl Type {
} }
pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { 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 { let copy_trait = match lang_item {
Some(LangItemTarget::TraitId(it)) => it, Some(LangItemTarget::TraitId(it)) => it,
_ => return false, _ => return false,

View file

@ -10,6 +10,7 @@ use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
use hir_def::lang_item::LangItemTarget; use hir_def::lang_item::LangItemTarget;
use hir_expand::name::name; use hir_expand::name::name;
use limit::Limit; use limit::Limit;
use syntax::SmolStr;
use tracing::{info, warn}; use tracing::{info, warn};
use crate::{ use crate::{
@ -71,7 +72,10 @@ impl Iterator for Autoderef<'_> {
} }
let (kind, new_ty) = if let Some(derefed) = builtin_deref(&self.ty.value) { 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 { } else {
( (
AutoderefKind::Overloaded, AutoderefKind::Overloaded,
@ -110,15 +114,17 @@ pub(crate) fn deref(
) -> Option<Canonical<Ty>> { ) -> Option<Canonical<Ty>> {
let _p = profile::span("deref"); let _p = profile::span("deref");
match builtin_deref(&ty.goal.value) { 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), 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) { match ty.kind(&Interner) {
TyKind::Ref(.., ty) => Some(ty.clone()), TyKind::Ref(.., ty) => Some(ty),
TyKind::Raw(.., ty) => Some(ty.clone()), TyKind::Raw(.., ty) => Some(ty),
_ => None, _ => None,
} }
} }
@ -129,7 +135,7 @@ fn deref_by_trait(
ty: InEnvironment<&Canonical<Ty>>, ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> { ) -> Option<Canonical<Ty>> {
let _p = profile::span("deref_by_trait"); 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, LangItemTarget::TraitId(it) => it,
_ => return None, _ => return None,
}; };

View file

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

View file

@ -6,6 +6,7 @@ use hir_def::{
type_ref::Rawness, type_ref::Rawness,
FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId, FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
}; };
use syntax::SmolStr;
use crate::{ use crate::{
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
@ -187,7 +188,7 @@ impl TyExt for Ty {
ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => { ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
let krate = def.module(db.upcast()).krate(); let krate = def.module(db.upcast()).krate();
if let Some(future_trait) = db 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()) .and_then(|item| item.as_trait())
{ {
// This is only used by type walking. // This is only used by type walking.

View file

@ -50,6 +50,7 @@ use std::{
use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId}; use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use stdx::never; use stdx::never;
use syntax::SmolStr;
use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind}; 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 { fn adt_is_box(adt: hir_def::AdtId, cx: &MatchCheckCtx<'_>) -> bool {
use hir_def::lang_item::LangItemTarget; 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(), Some(LangItemTarget::StructId(box_id)) => adt == box_id.into(),
_ => false, _ => false,
} }

View file

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

View file

@ -10,6 +10,7 @@ use std::iter;
use chalk_ir::{cast::Cast, Goal, Mutability, TyVariableKind}; use chalk_ir::{cast::Cast, Goal, Mutability, TyVariableKind};
use hir_def::{expr::ExprId, lang_item::LangItemTarget}; use hir_def::{expr::ExprId, lang_item::LangItemTarget};
use stdx::always; use stdx::always;
use syntax::SmolStr;
use crate::{ use crate::{
autoderef::{Autoderef, AutoderefKind}, autoderef::{Autoderef, AutoderefKind},
@ -536,7 +537,8 @@ impl<'a> InferenceContext<'a> {
reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone()); reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
let krate = self.resolver.krate().unwrap(); let krate = self.resolver.krate().unwrap();
let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) { let coerce_unsized_trait =
match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
Some(LangItemTarget::TraitId(trait_)) => trait_, Some(LangItemTarget::TraitId(trait_)) => trait_,
_ => return Err(TypeError), _ => return Err(TypeError),
}; };

View file

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

View file

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

View file

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

View file

@ -18,6 +18,8 @@ use hir_def::{
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::{name, Name};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
use syntax::SmolStr;
use crate::{ use crate::{
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind, db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind,
@ -26,16 +28,16 @@ use crate::{
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> { pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
[ [
db.lang_item(krate, "fn".into()), db.lang_item(krate, SmolStr::new_inline("fn")),
db.lang_item(krate, "fn_mut".into()), db.lang_item(krate, SmolStr::new_inline("fn_mut")),
db.lang_item(krate, "fn_once".into()), db.lang_item(krate, SmolStr::new_inline("fn_once")),
] ]
.into_iter() .into_iter()
.flatten() .flatten()
.flat_map(|it| it.as_trait()) .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); let resolver = trait_.resolver(db);
// returning the iterator directly doesn't easily work because of // returning the iterator directly doesn't easily work because of
// lifetime problems, but since there usually shouldn't be more than a // 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 /// Returns an iterator over the whole super trait hierarchy (including the
/// trait itself). /// 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 // 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;`) // (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; let mut i = 0;
while i < result.len() { while let Some(&t) = result.get(i) {
let t = result[i];
// yeah this is quadratic, but trait hierarchies should be flat // yeah this is quadratic, but trait hierarchies should be flat
// enough that this doesn't matter // enough that this doesn't matter
for tt in direct_super_traits(db, t) { for tt in direct_super_traits(db, t) {

View file

@ -193,6 +193,11 @@ where
} }
} }
/// 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;