Replace ConstnessAnd<TraitRef>
with TraitPredicate
which conveys the same information
This commit is contained in:
parent
b16c811f1c
commit
d161cc2071
2 changed files with 46 additions and 69 deletions
|
@ -16,10 +16,8 @@ pub type SelectionCache<'tcx> = Cache<
|
||||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
pub type EvaluationCache<'tcx> = Cache<
|
pub type EvaluationCache<'tcx> =
|
||||||
(ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
|
Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitPredicate<'tcx>>, EvaluationResult>;
|
||||||
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
|
||||||
|
|
|
@ -39,7 +39,6 @@ use rustc_middle::ty::fast_reject;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::relate::TypeRelation;
|
use rustc_middle::ty::relate::TypeRelation;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::WithConstness;
|
|
||||||
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||||
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
@ -138,9 +137,9 @@ pub struct SelectionContext<'cx, 'tcx> {
|
||||||
struct TraitObligationStack<'prev, 'tcx> {
|
struct TraitObligationStack<'prev, 'tcx> {
|
||||||
obligation: &'prev TraitObligation<'tcx>,
|
obligation: &'prev TraitObligation<'tcx>,
|
||||||
|
|
||||||
/// The trait ref from `obligation` but "freshened" with the
|
/// The trait predicate from `obligation` but "freshened" with the
|
||||||
/// selection-context's freshener. Used to check for recursion.
|
/// selection-context's freshener. Used to check for recursion.
|
||||||
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
|
|
||||||
/// Starts out equal to `depth` -- if, during evaluation, we
|
/// Starts out equal to `depth` -- if, during evaluation, we
|
||||||
/// encounter a cycle, then we will set this flag to the minimum
|
/// encounter a cycle, then we will set this flag to the minimum
|
||||||
|
@ -676,20 +675,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let stack = self.push_stack(previous_stack, &obligation);
|
let stack = self.push_stack(previous_stack, &obligation);
|
||||||
let fresh_trait_ref = stack.fresh_trait_ref;
|
let fresh_trait_pred = stack.fresh_trait_pred;
|
||||||
|
|
||||||
debug!(?fresh_trait_ref);
|
debug!(?fresh_trait_pred);
|
||||||
|
|
||||||
if let Some(result) = self.check_evaluation_cache(
|
if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_pred) {
|
||||||
obligation.param_env,
|
|
||||||
fresh_trait_ref,
|
|
||||||
obligation.polarity(),
|
|
||||||
) {
|
|
||||||
debug!(?result, "CACHE HIT");
|
debug!(?result, "CACHE HIT");
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
|
if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
|
||||||
debug!(?result, "PROVISIONAL CACHE HIT");
|
debug!(?result, "PROVISIONAL CACHE HIT");
|
||||||
stack.update_reached_depth(result.reached_depth);
|
stack.update_reached_depth(result.reached_depth);
|
||||||
return Ok(result.result);
|
return Ok(result.result);
|
||||||
|
@ -714,19 +709,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let reached_depth = stack.reached_depth.get();
|
let reached_depth = stack.reached_depth.get();
|
||||||
if reached_depth >= stack.depth {
|
if reached_depth >= stack.depth {
|
||||||
debug!(?result, "CACHE MISS");
|
debug!(?result, "CACHE MISS");
|
||||||
self.insert_evaluation_cache(
|
self.insert_evaluation_cache(obligation.param_env, fresh_trait_pred, dep_node, result);
|
||||||
obligation.param_env,
|
|
||||||
fresh_trait_ref,
|
|
||||||
obligation.polarity(),
|
|
||||||
dep_node,
|
|
||||||
result,
|
|
||||||
);
|
|
||||||
|
|
||||||
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
|
stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
|
||||||
self.insert_evaluation_cache(
|
self.insert_evaluation_cache(
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
fresh_trait_ref,
|
fresh_trait_pred,
|
||||||
obligation.polarity(),
|
|
||||||
dep_node,
|
dep_node,
|
||||||
provisional_result.max(result),
|
provisional_result.max(result),
|
||||||
);
|
);
|
||||||
|
@ -736,10 +724,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
debug!(
|
debug!(
|
||||||
"caching provisionally because {:?} \
|
"caching provisionally because {:?} \
|
||||||
is a cycle participant (at depth {}, reached depth {})",
|
is a cycle participant (at depth {}, reached depth {})",
|
||||||
fresh_trait_ref, stack.depth, reached_depth,
|
fresh_trait_pred, stack.depth, reached_depth,
|
||||||
);
|
);
|
||||||
|
|
||||||
stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result);
|
stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -773,7 +761,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
.skip(1) // Skip top-most frame.
|
.skip(1) // Skip top-most frame.
|
||||||
.find(|prev| {
|
.find(|prev| {
|
||||||
stack.obligation.param_env == prev.obligation.param_env
|
stack.obligation.param_env == prev.obligation.param_env
|
||||||
&& stack.fresh_trait_ref == prev.fresh_trait_ref
|
&& stack.fresh_trait_pred == prev.fresh_trait_pred
|
||||||
})
|
})
|
||||||
.map(|stack| stack.depth)
|
.map(|stack| stack.depth)
|
||||||
{
|
{
|
||||||
|
@ -836,7 +824,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// terms of `Fn` etc, but we could probably make this more
|
// terms of `Fn` etc, but we could probably make this more
|
||||||
// precise still.
|
// precise still.
|
||||||
let unbound_input_types =
|
let unbound_input_types =
|
||||||
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
|
stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
|
||||||
|
|
||||||
if stack.obligation.polarity() != ty::ImplPolarity::Negative {
|
if stack.obligation.polarity() != ty::ImplPolarity::Negative {
|
||||||
// This check was an imperfect workaround for a bug in the old
|
// This check was an imperfect workaround for a bug in the old
|
||||||
|
@ -874,8 +862,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
&& stack.iter().skip(1).any(|prev| {
|
&& stack.iter().skip(1).any(|prev| {
|
||||||
stack.obligation.param_env == prev.obligation.param_env
|
stack.obligation.param_env == prev.obligation.param_env
|
||||||
&& self.match_fresh_trait_refs(
|
&& self.match_fresh_trait_refs(
|
||||||
stack.fresh_trait_ref,
|
stack.fresh_trait_pred,
|
||||||
prev.fresh_trait_ref,
|
prev.fresh_trait_pred,
|
||||||
prev.obligation.param_env,
|
prev.obligation.param_env,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -953,7 +941,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// not just the lifetime choice for this particular (non-erased)
|
// not just the lifetime choice for this particular (non-erased)
|
||||||
// predicate.
|
// predicate.
|
||||||
// See issue #80691
|
// See issue #80691
|
||||||
if stack.fresh_trait_ref.has_erased_regions() {
|
if stack.fresh_trait_pred.has_erased_regions() {
|
||||||
result = result.max(EvaluatedToOkModuloRegions);
|
result = result.max(EvaluatedToOkModuloRegions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,8 +952,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
fn check_evaluation_cache(
|
fn check_evaluation_cache(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
polarity: ty::ImplPolarity,
|
|
||||||
) -> Option<EvaluationResult> {
|
) -> Option<EvaluationResult> {
|
||||||
// Neither the global nor local cache is aware of intercrate
|
// Neither the global nor local cache is aware of intercrate
|
||||||
// mode, so don't do any caching. In particular, we might
|
// mode, so don't do any caching. In particular, we might
|
||||||
|
@ -977,19 +964,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
|
if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_pred), tcx) {
|
||||||
{
|
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
|
self.infcx.evaluation_cache.get(¶m_env.and(trait_pred), tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_evaluation_cache(
|
fn insert_evaluation_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
polarity: ty::ImplPolarity,
|
|
||||||
dep_node: DepNodeIndex,
|
dep_node: DepNodeIndex,
|
||||||
result: EvaluationResult,
|
result: EvaluationResult,
|
||||||
) {
|
) {
|
||||||
|
@ -1008,23 +993,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if !trait_ref.needs_infer() {
|
if !trait_pred.needs_infer() {
|
||||||
debug!(?trait_ref, ?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
|
// FIXME: Due to #50507 this overwrites the different values
|
||||||
// This should be changed to use HashMapExt::insert_same
|
// This should be changed to use HashMapExt::insert_same
|
||||||
// when that is fixed
|
// when that is fixed
|
||||||
self.tcx().evaluation_cache.insert(
|
self.tcx().evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
|
||||||
(param_env.and(trait_ref), polarity),
|
|
||||||
dep_node,
|
|
||||||
result,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(?trait_ref, ?result, "insert_evaluation_cache");
|
debug!(?trait_pred, ?result, "insert_evaluation_cache");
|
||||||
self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
|
self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For various reasons, it's possible for a subobligation
|
/// For various reasons, it's possible for a subobligation
|
||||||
|
@ -2154,8 +2135,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
fn match_fresh_trait_refs(
|
fn match_fresh_trait_refs(
|
||||||
&self,
|
&self,
|
||||||
previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
previous: ty::PolyTraitPredicate<'tcx>,
|
||||||
current: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
current: ty::PolyTraitPredicate<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
|
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
|
||||||
|
@ -2167,18 +2148,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
||||||
obligation: &'o TraitObligation<'tcx>,
|
obligation: &'o TraitObligation<'tcx>,
|
||||||
) -> TraitObligationStack<'o, 'tcx> {
|
) -> TraitObligationStack<'o, 'tcx> {
|
||||||
let fresh_trait_ref = obligation
|
let fresh_trait_pred = obligation
|
||||||
.predicate
|
.predicate
|
||||||
.to_poly_trait_ref()
|
|
||||||
.fold_with(&mut self.freshener)
|
.fold_with(&mut self.freshener)
|
||||||
.into_ok()
|
.into_ok();
|
||||||
.with_constness(obligation.predicate.skip_binder().constness);
|
|
||||||
|
|
||||||
let dfn = previous_stack.cache.next_dfn();
|
let dfn = previous_stack.cache.next_dfn();
|
||||||
let depth = previous_stack.depth() + 1;
|
let depth = previous_stack.depth() + 1;
|
||||||
TraitObligationStack {
|
TraitObligationStack {
|
||||||
obligation,
|
obligation,
|
||||||
fresh_trait_ref,
|
fresh_trait_pred,
|
||||||
reached_depth: Cell::new(depth),
|
reached_depth: Cell::new(depth),
|
||||||
previous: previous_stack,
|
previous: previous_stack,
|
||||||
dfn,
|
dfn,
|
||||||
|
@ -2372,7 +2351,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
|
||||||
debug!(reached_depth, "update_reached_depth");
|
debug!(reached_depth, "update_reached_depth");
|
||||||
let mut p = self;
|
let mut p = self;
|
||||||
while reached_depth < p.depth {
|
while reached_depth < p.depth {
|
||||||
debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant");
|
debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant");
|
||||||
p.reached_depth.set(p.reached_depth.get().min(reached_depth));
|
p.reached_depth.set(p.reached_depth.get().min(reached_depth));
|
||||||
p = p.previous.head.unwrap();
|
p = p.previous.head.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -2451,7 +2430,7 @@ struct ProvisionalEvaluationCache<'tcx> {
|
||||||
/// - then we determine that `E` is in error -- we will then clear
|
/// - then we determine that `E` is in error -- we will then clear
|
||||||
/// all cache values whose DFN is >= 4 -- in this case, that
|
/// all cache values whose DFN is >= 4 -- in this case, that
|
||||||
/// means the cached value for `F`.
|
/// means the cached value for `F`.
|
||||||
map: RefCell<FxHashMap<ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ProvisionalEvaluation>>,
|
map: RefCell<FxHashMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A cache value for the provisional cache: contains the depth-first
|
/// A cache value for the provisional cache: contains the depth-first
|
||||||
|
@ -2483,28 +2462,28 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
|
||||||
/// `reached_depth` (from the returned value).
|
/// `reached_depth` (from the returned value).
|
||||||
fn get_provisional(
|
fn get_provisional(
|
||||||
&self,
|
&self,
|
||||||
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> Option<ProvisionalEvaluation> {
|
) -> Option<ProvisionalEvaluation> {
|
||||||
debug!(
|
debug!(
|
||||||
?fresh_trait_ref,
|
?fresh_trait_pred,
|
||||||
"get_provisional = {:#?}",
|
"get_provisional = {:#?}",
|
||||||
self.map.borrow().get(&fresh_trait_ref),
|
self.map.borrow().get(&fresh_trait_pred),
|
||||||
);
|
);
|
||||||
Some(*self.map.borrow().get(&fresh_trait_ref)?)
|
Some(*self.map.borrow().get(&fresh_trait_pred)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a provisional result into the cache. The result came
|
/// Insert a provisional result into the cache. The result came
|
||||||
/// from the node with the given DFN. It accessed a minimum depth
|
/// from the node with the given DFN. It accessed a minimum depth
|
||||||
/// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
|
/// of `reached_depth` to compute. It evaluated `fresh_trait_pred`
|
||||||
/// and resulted in `result`.
|
/// and resulted in `result`.
|
||||||
fn insert_provisional(
|
fn insert_provisional(
|
||||||
&self,
|
&self,
|
||||||
from_dfn: usize,
|
from_dfn: usize,
|
||||||
reached_depth: usize,
|
reached_depth: usize,
|
||||||
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
result: EvaluationResult,
|
result: EvaluationResult,
|
||||||
) {
|
) {
|
||||||
debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional");
|
debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
|
||||||
|
|
||||||
let mut map = self.map.borrow_mut();
|
let mut map = self.map.borrow_mut();
|
||||||
|
|
||||||
|
@ -2528,7 +2507,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
map.insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, reached_depth, result });
|
map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when the node with dfn `dfn` does not get a successful
|
/// Invoked when the node with dfn `dfn` does not get a successful
|
||||||
|
@ -2579,16 +2558,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
|
||||||
fn on_completion(
|
fn on_completion(
|
||||||
&self,
|
&self,
|
||||||
dfn: usize,
|
dfn: usize,
|
||||||
mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
|
mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
|
||||||
) {
|
) {
|
||||||
debug!(?dfn, "on_completion");
|
debug!(?dfn, "on_completion");
|
||||||
|
|
||||||
for (fresh_trait_ref, eval) in
|
for (fresh_trait_pred, eval) in
|
||||||
self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
|
self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
|
||||||
{
|
{
|
||||||
debug!(?fresh_trait_ref, ?eval, "on_completion");
|
debug!(?fresh_trait_pred, ?eval, "on_completion");
|
||||||
|
|
||||||
op(fresh_trait_ref, eval.result);
|
op(fresh_trait_pred, eval.result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue