re-use sized fast path
There's an existing fast path for the `type_op_prove_predicate` predicate, checking for trivially `Sized` types, which can be re-used when evaluating obligations within queries. This should improve performance, particularly in anticipation of new sizedness traits being added which can take advantage of this.
This commit is contained in:
parent
97c966bb40
commit
72d17bfebb
12 changed files with 70 additions and 31 deletions
|
@ -24,10 +24,10 @@ use super::{
|
|||
};
|
||||
use crate::error_reporting::InferCtxtErrorExt;
|
||||
use crate::infer::{InferCtxt, TyOrConstInferVar};
|
||||
use crate::traits::EvaluateConstErr;
|
||||
use crate::traits::normalize::normalize_with_depth_to;
|
||||
use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{EvaluateConstErr, sizedness_fast_path};
|
||||
|
||||
pub(crate) type PendingPredicateObligations<'tcx> = ThinVec<PendingPredicateObligation<'tcx>>;
|
||||
|
||||
|
@ -335,6 +335,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
|
||||
let infcx = self.selcx.infcx;
|
||||
|
||||
if sizedness_fast_path(infcx.tcx, obligation.predicate) {
|
||||
return ProcessResult::Changed(thin_vec::thin_vec![]);
|
||||
}
|
||||
|
||||
if obligation.predicate.has_aliases() {
|
||||
let mut obligations = PredicateObligations::new();
|
||||
let predicate = normalize_with_depth_to(
|
||||
|
|
|
@ -65,8 +65,8 @@ pub use self::specialize::{
|
|||
pub use self::structural_normalize::StructurallyNormalizeExt;
|
||||
pub use self::util::{
|
||||
BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final,
|
||||
supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices,
|
||||
with_replaced_escaping_bound_vars,
|
||||
sizedness_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item,
|
||||
upcast_choices, with_replaced_escaping_bound_vars,
|
||||
};
|
||||
use crate::error_reporting::InferCtxtErrorExt;
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use rustc_hir::LangItem;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
|
@ -7,7 +6,7 @@ use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
|
||||
use crate::traits::ObligationCtxt;
|
||||
use crate::traits::{ObligationCtxt, sizedness_fast_path};
|
||||
|
||||
impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
|
||||
type QueryResponse = ();
|
||||
|
@ -16,15 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
key: &ParamEnvAnd<'tcx, Self>,
|
||||
) -> Option<Self::QueryResponse> {
|
||||
// Proving Sized, very often on "obviously sized" types like
|
||||
// `&T`, accounts for about 60% percentage of the predicates
|
||||
// we have to prove. No need to canonicalize and all that for
|
||||
// such cases.
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
|
||||
key.value.predicate.kind().skip_binder()
|
||||
&& tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
|
||||
&& trait_ref.self_ty().is_trivially_sized(tcx)
|
||||
{
|
||||
if sizedness_fast_path(tcx, key.value.predicate) {
|
||||
return Some(());
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,9 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
|||
use crate::solve::InferCtxtSelectExt as _;
|
||||
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
|
||||
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
|
||||
use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects};
|
||||
use crate::traits::{
|
||||
EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path,
|
||||
};
|
||||
|
||||
mod _match;
|
||||
mod candidate_assembly;
|
||||
|
@ -603,6 +605,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
None => self.check_recursion_limit(&obligation, &obligation)?,
|
||||
}
|
||||
|
||||
if sizedness_fast_path(self.tcx(), obligation.predicate) {
|
||||
return Ok(EvaluatedToOk);
|
||||
}
|
||||
|
||||
ensure_sufficient_stack(|| {
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::collections::{BTreeMap, VecDeque};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
pub use rustc_infer::traits::util::*;
|
||||
|
@ -504,3 +505,21 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool {
|
||||
// Proving `Sized` very often on "obviously sized" types like `&T`, accounts for about 60%
|
||||
// percentage of the predicates we have to prove. No need to canonicalize and all that for
|
||||
// such cases.
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
|
||||
predicate.kind().skip_binder()
|
||||
{
|
||||
if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
|
||||
&& trait_ref.self_ty().is_trivially_sized(tcx)
|
||||
{
|
||||
debug!("fast path -- trivial sizedness");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue