global old solver cache: use TypingEnv
This commit is contained in:
parent
a8c8ab1acd
commit
795ff6576c
5 changed files with 53 additions and 41 deletions
|
@ -264,11 +264,12 @@ pub struct InferCtxt<'tcx> {
|
||||||
lexical_region_resolutions: RefCell<Option<LexicalRegionResolutions<'tcx>>>,
|
lexical_region_resolutions: RefCell<Option<LexicalRegionResolutions<'tcx>>>,
|
||||||
|
|
||||||
/// Caches the results of trait selection. This cache is used
|
/// Caches the results of trait selection. This cache is used
|
||||||
/// for things that have to do with the parameters in scope.
|
/// for things that depends on inference variables or placeholders.
|
||||||
pub selection_cache: select::SelectionCache<'tcx>,
|
pub selection_cache: select::SelectionCache<'tcx, ty::ParamEnv<'tcx>>,
|
||||||
|
|
||||||
/// Caches the results of trait evaluation.
|
/// Caches the results of trait evaluation. This cache is used
|
||||||
pub evaluation_cache: select::EvaluationCache<'tcx>,
|
/// for things that depends on inference variables or placeholders.
|
||||||
|
pub evaluation_cache: select::EvaluationCache<'tcx, ty::ParamEnv<'tcx>>,
|
||||||
|
|
||||||
/// The set of predicates on which errors have been reported, to
|
/// The set of predicates on which errors have been reported, to
|
||||||
/// avoid reporting the same error twice.
|
/// avoid reporting the same error twice.
|
||||||
|
|
|
@ -551,7 +551,7 @@ pub struct DerivedCause<'tcx> {
|
||||||
pub parent_code: InternedObligationCauseCode<'tcx>,
|
pub parent_code: InternedObligationCauseCode<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, TypeVisitable)]
|
#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
|
||||||
pub enum SelectionError<'tcx> {
|
pub enum SelectionError<'tcx> {
|
||||||
/// The trait is not implemented.
|
/// The trait is not implemented.
|
||||||
Unimplemented,
|
Unimplemented,
|
||||||
|
@ -573,7 +573,7 @@ pub enum SelectionError<'tcx> {
|
||||||
ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> },
|
ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, TypeVisitable)]
|
#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
|
||||||
pub struct SignatureMismatchData<'tcx> {
|
pub struct SignatureMismatchData<'tcx> {
|
||||||
pub found_trait_ref: ty::TraitRef<'tcx>,
|
pub found_trait_ref: ty::TraitRef<'tcx>,
|
||||||
pub expected_trait_ref: ty::TraitRef<'tcx>,
|
pub expected_trait_ref: ty::TraitRef<'tcx>,
|
||||||
|
|
|
@ -11,20 +11,10 @@ use self::EvaluationResult::*;
|
||||||
use super::{SelectionError, SelectionResult};
|
use super::{SelectionError, SelectionResult};
|
||||||
use crate::ty;
|
use crate::ty;
|
||||||
|
|
||||||
pub type SelectionCache<'tcx> = Cache<
|
pub type SelectionCache<'tcx, ENV> =
|
||||||
// This cache does not use `ParamEnvAnd` in its keys because `ParamEnv::and` can replace
|
Cache<(ENV, ty::TraitPredicate<'tcx>), SelectionResult<'tcx, SelectionCandidate<'tcx>>>;
|
||||||
// caller bounds with an empty list if the `TraitPredicate` looks global, which may happen
|
|
||||||
// after erasing lifetimes from the predicate.
|
|
||||||
(ty::ParamEnv<'tcx>, ty::TraitPredicate<'tcx>),
|
|
||||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
|
||||||
>;
|
|
||||||
|
|
||||||
pub type EvaluationCache<'tcx> = Cache<
|
pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>), EvaluationResult>;
|
||||||
// See above: this cache does not use `ParamEnvAnd` in its keys due to sometimes incorrectly
|
|
||||||
// caching with the wrong `ParamEnv`.
|
|
||||||
(ty::ParamEnv<'tcx>, ty::PolyTraitPredicate<'tcx>),
|
|
||||||
EvaluationResult,
|
|
||||||
>;
|
|
||||||
|
|
||||||
/// The selection process begins by considering all impls, where
|
/// The selection process begins by considering all impls, where
|
||||||
/// clauses, and so forth that might resolve an obligation. Sometimes
|
/// clauses, and so forth that might resolve an obligation. Sometimes
|
||||||
|
|
|
@ -1326,12 +1326,12 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
|
|
||||||
/// Caches the results of trait selection. This cache is used
|
/// Caches the results of trait selection. This cache is used
|
||||||
/// for things that do not have to do with the parameters in scope.
|
/// for things that do not have to do with the parameters in scope.
|
||||||
pub selection_cache: traits::SelectionCache<'tcx>,
|
pub selection_cache: traits::SelectionCache<'tcx, ty::TypingEnv<'tcx>>,
|
||||||
|
|
||||||
/// Caches the results of trait evaluation. This cache is used
|
/// Caches the results of trait evaluation. This cache is used
|
||||||
/// for things that do not have to do with the parameters in scope.
|
/// for things that do not have to do with the parameters in scope.
|
||||||
/// Merge this with `selection_cache`?
|
/// Merge this with `selection_cache`?
|
||||||
pub evaluation_cache: traits::EvaluationCache<'tcx>,
|
pub evaluation_cache: traits::EvaluationCache<'tcx, ty::TypingEnv<'tcx>>,
|
||||||
|
|
||||||
/// Caches the results of goal evaluation in the new solver.
|
/// Caches the results of goal evaluation in the new solver.
|
||||||
pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
|
pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
|
||||||
|
|
|
@ -1310,14 +1310,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> Option<EvaluationResult> {
|
) -> Option<EvaluationResult> {
|
||||||
let tcx = self.tcx();
|
let infcx = self.infcx;
|
||||||
|
let tcx = infcx.tcx;
|
||||||
if self.can_use_global_caches(param_env, trait_pred) {
|
if self.can_use_global_caches(param_env, trait_pred) {
|
||||||
if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) {
|
let key = (infcx.typing_env(param_env), trait_pred);
|
||||||
return Some(res);
|
if let Some(res) = tcx.evaluation_cache.get(&key, tcx) {
|
||||||
}
|
Some(res)
|
||||||
|
} else {
|
||||||
|
debug_assert_eq!(infcx.evaluation_cache.get(&(param_env, trait_pred), tcx), None);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
self.infcx.evaluation_cache.get(&(param_env, trait_pred), tcx)
|
self.infcx.evaluation_cache.get(&(param_env, trait_pred), tcx)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_evaluation_cache(
|
fn insert_evaluation_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1332,19 +1338,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.can_use_global_caches(param_env, trait_pred) && !trait_pred.has_infer() {
|
let infcx = self.infcx;
|
||||||
|
let tcx = infcx.tcx;
|
||||||
|
if self.can_use_global_caches(param_env, trait_pred) {
|
||||||
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
|
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
|
||||||
// This may overwrite the cache with the same value
|
// This may overwrite the cache with the same value
|
||||||
// FIXME: Due to #50507 this overwrites the different values
|
tcx.evaluation_cache.insert(
|
||||||
// This should be changed to use HashMapExt::insert_same
|
(infcx.typing_env(param_env), trait_pred),
|
||||||
// when that is fixed
|
dep_node,
|
||||||
self.tcx().evaluation_cache.insert((param_env, trait_pred), dep_node, result);
|
result,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
debug!(?trait_pred, ?result, "insert_evaluation_cache local");
|
||||||
debug!(?trait_pred, ?result, "insert_evaluation_cache");
|
|
||||||
self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
|
self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_recursion_depth<T>(
|
fn check_recursion_depth<T>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1485,7 +1494,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// If there are any inference variables in the `ParamEnv`, then we
|
// If there are any inference variables in the `ParamEnv`, then we
|
||||||
// always use a cache local to this particular scope. Otherwise, we
|
// always use a cache local to this particular scope. Otherwise, we
|
||||||
// switch to a global cache.
|
// switch to a global cache.
|
||||||
if param_env.has_infer() {
|
if param_env.has_infer() || pred.has_infer() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1522,15 +1531,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
|
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
|
||||||
let tcx = self.tcx();
|
let infcx = self.infcx;
|
||||||
|
let tcx = infcx.tcx;
|
||||||
let pred = cache_fresh_trait_pred.skip_binder();
|
let pred = cache_fresh_trait_pred.skip_binder();
|
||||||
|
|
||||||
if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
|
if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
|
||||||
if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) {
|
if let Some(res) = tcx.selection_cache.get(&(infcx.typing_env(param_env), pred), tcx) {
|
||||||
return Some(res);
|
Some(res)
|
||||||
|
} else {
|
||||||
|
debug_assert_eq!(infcx.selection_cache.get(&(param_env, pred), tcx), None);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
infcx.selection_cache.get(&(param_env, pred), tcx)
|
||||||
}
|
}
|
||||||
self.infcx.selection_cache.get(&(param_env, pred), tcx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether can we safely cache the result
|
/// Determines whether can we safely cache the result
|
||||||
|
@ -1567,7 +1581,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
dep_node: DepNodeIndex,
|
dep_node: DepNodeIndex,
|
||||||
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx();
|
let infcx = self.infcx;
|
||||||
|
let tcx = infcx.tcx;
|
||||||
let pred = cache_fresh_trait_pred.skip_binder();
|
let pred = cache_fresh_trait_pred.skip_binder();
|
||||||
|
|
||||||
if !self.can_cache_candidate(&candidate) {
|
if !self.can_cache_candidate(&candidate) {
|
||||||
|
@ -1578,10 +1593,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
|
if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
|
||||||
if let Err(Overflow(OverflowError::Canonical)) = candidate {
|
if let Err(Overflow(OverflowError::Canonical)) = candidate {
|
||||||
// Don't cache overflow globally; we only produce this in certain modes.
|
// Don't cache overflow globally; we only produce this in certain modes.
|
||||||
} else if !pred.has_infer() && !candidate.has_infer() {
|
} else {
|
||||||
debug!(?pred, ?candidate, "insert_candidate_cache global");
|
debug!(?pred, ?candidate, "insert_candidate_cache global");
|
||||||
|
debug_assert!(!candidate.has_infer());
|
||||||
|
|
||||||
// This may overwrite the cache with the same value.
|
// This may overwrite the cache with the same value.
|
||||||
tcx.selection_cache.insert((param_env, pred), dep_node, candidate);
|
tcx.selection_cache.insert(
|
||||||
|
(infcx.typing_env(param_env), pred),
|
||||||
|
dep_node,
|
||||||
|
candidate,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue