1
Fork 0

Make selection and evaluation caches use constness

This commit is contained in:
Deadbeef 2021-07-24 19:12:24 +08:00
parent 36ace4c0ad
commit 3bab45d2ac
No known key found for this signature in database
GPG key ID: 027DF9338862ADDD
2 changed files with 59 additions and 32 deletions

View file

@ -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

View file

@ -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(&param_env.and(*trait_ref), tcx) { if let Some(res) = tcx
.selection_cache
.get(&param_env.and(trait_ref).with_constness(pred.constness), tcx)
{
return Some(res); return Some(res);
} }
} }
self.infcx.selection_cache.get(&param_env.and(*trait_ref), tcx) self.infcx
.selection_cache
.get(&param_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");