Make selection and evaluation caches use constness
This commit is contained in:
parent
36ace4c0ad
commit
3bab45d2ac
2 changed files with 59 additions and 32 deletions
|
@ -12,12 +12,12 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_query_system::cache::Cache;
|
use rustc_query_system::cache::Cache;
|
||||||
|
|
||||||
pub type SelectionCache<'tcx> = Cache<
|
pub type SelectionCache<'tcx> = Cache<
|
||||||
ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
|
ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
|
||||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
pub type EvaluationCache<'tcx> =
|
pub type EvaluationCache<'tcx> =
|
||||||
Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, EvaluationResult>;
|
Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'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
|
||||||
|
|
|
@ -41,6 +41,7 @@ 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;
|
||||||
|
@ -141,7 +142,7 @@ struct TraitObligationStack<'prev, 'tcx> {
|
||||||
|
|
||||||
/// The trait ref from `obligation` but "freshened" with the
|
/// The trait ref 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::PolyTraitRef<'tcx>,
|
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'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
|
||||||
|
@ -804,7 +805,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.skip_binder().substs.types().any(|ty| ty.is_fresh());
|
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
|
||||||
// This check was an imperfect workaround for a bug in the old
|
// This check was an imperfect workaround for a bug in the old
|
||||||
// intercrate mode; it should be removed when that goes away.
|
// intercrate mode; it should be removed when that goes away.
|
||||||
if unbound_input_types && self.intercrate {
|
if unbound_input_types && self.intercrate {
|
||||||
|
@ -925,7 +926,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::PolyTraitRef<'tcx>,
|
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
) -> Option<EvaluationResult> {
|
) -> Option<EvaluationResult> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
|
@ -939,7 +940,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, '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::PolyTraitRef<'tcx>,
|
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
dep_node: DepNodeIndex,
|
dep_node: DepNodeIndex,
|
||||||
result: EvaluationResult,
|
result: EvaluationResult,
|
||||||
) {
|
) {
|
||||||
|
@ -1024,18 +1025,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
// Respect const trait obligations
|
// Respect const trait obligations
|
||||||
if let hir::Constness::Const = obligation.predicate.skip_binder().constness {
|
if let hir::Constness::Const = obligation.predicate.skip_binder().constness {
|
||||||
match candidate {
|
if Some(obligation.predicate.skip_binder().trait_ref.def_id)
|
||||||
// const impl
|
!= tcx.lang_items().sized_trait()
|
||||||
ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
// const Sized bounds are skipped
|
||||||
// const param
|
{
|
||||||
ParamCandidate(ty::ConstnessAnd { constness: hir::Constness::Const, .. }) => {}
|
match candidate {
|
||||||
// auto trait impl
|
// const impl
|
||||||
AutoImplCandidate(..) => {}
|
ImplCandidate(def_id)
|
||||||
// FIXME check if this is right, but this would allow Sized impls
|
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
||||||
// BuiltinCandidate { .. } => {}
|
// const param
|
||||||
_ => {
|
ParamCandidate(ty::ConstnessAnd {
|
||||||
// reject all other types of candidates
|
constness: hir::Constness::Const, ..
|
||||||
return Err(Unimplemented);
|
}) => {}
|
||||||
|
// auto trait impl
|
||||||
|
AutoImplCandidate(..) => {}
|
||||||
|
// FIXME check if this is right, but this would allow Sized impls
|
||||||
|
// BuiltinCandidate { .. } => {}
|
||||||
|
_ => {
|
||||||
|
// reject all other types of candidates
|
||||||
|
return Err(Unimplemented);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1121,13 +1130,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, '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 tcx = self.tcx();
|
||||||
let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
|
let pred = &cache_fresh_trait_pred.skip_binder();
|
||||||
|
let trait_ref = pred.trait_ref;
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if let Some(res) = tcx.selection_cache.get(¶m_env.and(*trait_ref), tcx) {
|
if let Some(res) = tcx
|
||||||
|
.selection_cache
|
||||||
|
.get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
|
||||||
|
{
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx.selection_cache.get(¶m_env.and(*trait_ref), tcx)
|
self.infcx
|
||||||
|
.selection_cache
|
||||||
|
.get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether can we safely cache the result
|
/// Determines whether can we safely cache the result
|
||||||
|
@ -1164,7 +1179,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
|
let pred = cache_fresh_trait_pred.skip_binder();
|
||||||
|
let trait_ref = pred.trait_ref;
|
||||||
|
|
||||||
if !self.can_cache_candidate(&candidate) {
|
if !self.can_cache_candidate(&candidate) {
|
||||||
debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
|
||||||
|
@ -1178,14 +1194,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if !candidate.needs_infer() {
|
if !candidate.needs_infer() {
|
||||||
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
|
||||||
// This may overwrite the cache with the same value.
|
// This may overwrite the cache with the same value.
|
||||||
tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
|
tcx.selection_cache.insert(
|
||||||
|
param_env.and(trait_ref).with_constness(pred.constness),
|
||||||
|
dep_node,
|
||||||
|
candidate,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
|
||||||
self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
|
self.infcx.selection_cache.insert(
|
||||||
|
param_env.and(trait_ref).with_constness(pred.constness),
|
||||||
|
dep_node,
|
||||||
|
candidate,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches a predicate against the bounds of its self type.
|
/// Matches a predicate against the bounds of its self type.
|
||||||
|
@ -2015,8 +2039,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
fn match_fresh_trait_refs(
|
fn match_fresh_trait_refs(
|
||||||
&self,
|
&self,
|
||||||
previous: ty::PolyTraitRef<'tcx>,
|
previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
current: ty::PolyTraitRef<'tcx>,
|
current: ty::ConstnessAnd<ty::PolyTraitRef<'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);
|
||||||
|
@ -2028,8 +2052,11 @@ 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 =
|
let fresh_trait_ref = obligation
|
||||||
obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
|
.predicate
|
||||||
|
.to_poly_trait_ref()
|
||||||
|
.fold_with(&mut self.freshener)
|
||||||
|
.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;
|
||||||
|
@ -2308,7 +2335,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::PolyTraitRef<'tcx>, ProvisionalEvaluation>>,
|
map: RefCell<FxHashMap<ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ProvisionalEvaluation>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A cache value for the provisional cache: contains the depth-first
|
/// A cache value for the provisional cache: contains the depth-first
|
||||||
|
@ -2340,7 +2367,7 @@ 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::PolyTraitRef<'tcx>,
|
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
) -> Option<ProvisionalEvaluation> {
|
) -> Option<ProvisionalEvaluation> {
|
||||||
debug!(
|
debug!(
|
||||||
?fresh_trait_ref,
|
?fresh_trait_ref,
|
||||||
|
@ -2358,7 +2385,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
|
||||||
&self,
|
&self,
|
||||||
from_dfn: usize,
|
from_dfn: usize,
|
||||||
reached_depth: usize,
|
reached_depth: usize,
|
||||||
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
|
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
result: EvaluationResult,
|
result: EvaluationResult,
|
||||||
) {
|
) {
|
||||||
debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional");
|
debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional");
|
||||||
|
@ -2436,7 +2463,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
|
||||||
fn on_completion(
|
fn on_completion(
|
||||||
&self,
|
&self,
|
||||||
dfn: usize,
|
dfn: usize,
|
||||||
mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult),
|
mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
|
||||||
) {
|
) {
|
||||||
debug!(?dfn, "on_completion");
|
debug!(?dfn, "on_completion");
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue