add a per-param-env cache to impls_bound
There used to be only a global cache, which led to uncached calls to trait selection when there were type parameters. I'm running a check that there are no adverse performance effects. Fixes #37106 (drop elaboration times are now ~half of borrow checking, so might still be worthy of optimization, but not critical).
This commit is contained in:
parent
d34318dd53
commit
a61d85b2fe
@ -336,7 +336,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> {
|
||||
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'gcx> {
|
||||
self.infcx.param_env()
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ use util::nodemap::FnvHashMap;
|
||||
|
||||
use serialize::{self, Encodable, Encoder};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
@ -1220,6 +1220,12 @@ pub struct ParameterEnvironment<'tcx> {
|
||||
/// regions don't have this implicit scope and instead introduce
|
||||
/// relationships in the environment.
|
||||
pub free_id_outlive: CodeExtent,
|
||||
|
||||
/// A cache for `moves_by_default`.
|
||||
pub is_copy_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
|
||||
|
||||
/// A cache for `type_is_sized`
|
||||
pub is_sized_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
||||
@ -1232,6 +1238,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
||||
implicit_region_bound: self.implicit_region_bound,
|
||||
caller_bounds: caller_bounds,
|
||||
free_id_outlive: self.free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FnvHashMap()),
|
||||
is_sized_cache: RefCell::new(FnvHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2773,7 +2781,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
free_substs: Substs::empty(self),
|
||||
caller_bounds: Vec::new(),
|
||||
implicit_region_bound: self.mk_region(ty::ReEmpty),
|
||||
free_id_outlive: free_id_outlive
|
||||
free_id_outlive: free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FnvHashMap()),
|
||||
is_sized_cache: RefCell::new(FnvHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2844,6 +2854,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)),
|
||||
caller_bounds: predicates,
|
||||
free_id_outlive: free_id_outlive,
|
||||
is_copy_cache: RefCell::new(FnvHashMap()),
|
||||
is_sized_cache: RefCell::new(FnvHashMap()),
|
||||
};
|
||||
|
||||
let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
|
||||
|
@ -901,23 +901,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::ParameterEnvironment {
|
||||
free_substs: self.free_substs.fold_with(folder),
|
||||
implicit_region_bound: self.implicit_region_bound.fold_with(folder),
|
||||
caller_bounds: self.caller_bounds.fold_with(folder),
|
||||
free_id_outlive: self.free_id_outlive,
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.free_substs.visit_with(visitor) ||
|
||||
self.implicit_region_bound.visit_with(visitor) ||
|
||||
self.caller_bounds.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::error::ExpectedFound {
|
||||
|
@ -20,9 +20,11 @@ use ty::{Disr, ParameterEnvironment};
|
||||
use ty::fold::TypeVisitor;
|
||||
use ty::layout::{Layout, LayoutError};
|
||||
use ty::TypeVariants::*;
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cmp;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
@ -579,11 +581,24 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc
|
||||
impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>,
|
||||
bound: ty::BuiltinBound, span: Span) -> bool
|
||||
bound: ty::BuiltinBound,
|
||||
cache: &RefCell<FnvHashMap<Ty<'tcx>, bool>>,
|
||||
span: Span) -> bool
|
||||
{
|
||||
tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch).enter(|infcx| {
|
||||
traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
|
||||
})
|
||||
if self.has_param_types() || self.has_self_ty() {
|
||||
if let Some(result) = cache.borrow().get(self) {
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
let result =
|
||||
tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch)
|
||||
.enter(|infcx| {
|
||||
traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
|
||||
});
|
||||
if self.has_param_types() || self.has_self_ty() {
|
||||
cache.borrow_mut().insert(self, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// FIXME (@jroesch): I made this public to use it, not sure if should be private
|
||||
@ -610,7 +625,9 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) |
|
||||
TyClosure(..) | TyAdt(..) | TyAnon(..) |
|
||||
TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
|
||||
}.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span));
|
||||
}.unwrap_or_else(|| {
|
||||
!self.impls_bound(tcx, param_env, ty::BoundCopy, ¶m_env.is_copy_cache, span)
|
||||
});
|
||||
|
||||
if !self.has_param_types() && !self.has_self_ty() {
|
||||
self.flags.set(self.flags.get() | if result {
|
||||
@ -650,7 +667,9 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
|
||||
TyAdt(..) | TyProjection(..) | TyParam(..) |
|
||||
TyInfer(..) | TyAnon(..) | TyError => None
|
||||
}.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span));
|
||||
}.unwrap_or_else(|| {
|
||||
self.impls_bound(tcx, param_env, ty::BoundSized, ¶m_env.is_sized_cache, span)
|
||||
});
|
||||
|
||||
if !self.has_param_types() && !self.has_self_ty() {
|
||||
self.flags.set(self.flags.get() | if result {
|
||||
|
@ -1458,7 +1458,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn param_env(&self) -> &ty::ParameterEnvironment<'tcx> {
|
||||
pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> {
|
||||
&self.parameter_environment
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user