Auto merge of #91354 - fee1-dead:const_env, r=spastorino

Cleanup: Eliminate ConstnessAnd

This is almost a behaviour-free change and purely a refactoring. "almost" because we appear to be using the wrong ParamEnv somewhere already, and this is now exposed by failing a test using the unstable `~const` feature.

We most definitely need to review all `without_const` and at some point should probably get rid of many of them by using `TraitPredicate` instead of `TraitRef`.

This is a continuation of https://github.com/rust-lang/rust/pull/90274.

r? `@oli-obk`

cc `@spastorino` `@ecstatic-morse`
This commit is contained in:
bors 2021-12-02 11:48:58 +00:00
commit 18bb8c61a9
49 changed files with 380 additions and 430 deletions

View file

@ -3,7 +3,7 @@ use crate::traits::{self, TraitEngine};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::{DiagnosticMessageId, Limit};
use rustc_span::def_id::LOCAL_CRATE;

View file

@ -9,7 +9,6 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, Quer
use rustc_middle::traits::query::Fallible;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::WithConstness;
use rustc_middle::ty::{self, Ty, TypeFoldable};
use rustc_span::{Span, DUMMY_SP};

View file

@ -370,12 +370,17 @@ impl AutoTraitFinder<'tcx> {
computed_preds.clone().chain(user_computed_preds.iter().cloned()),
)
.map(|o| o.predicate);
new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal());
new_env = ty::ParamEnv::new(
tcx.mk_predicates(normalized_preds),
param_env.reveal(),
param_env.constness(),
);
}
let final_user_env = ty::ParamEnv::new(
tcx.mk_predicates(user_computed_preds.into_iter()),
user_env.reveal(),
user_env.constness(),
);
debug!(
"evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \

View file

@ -24,7 +24,7 @@ use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::{
self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
TypeFoldable, WithConstness,
TypeFoldable,
};
use rustc_session::DiagnosticMessageId;
use rustc_span::symbol::{kw, sym};

View file

@ -21,7 +21,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_session::Limit;

View file

@ -4,7 +4,6 @@ use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
@ -231,21 +230,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: rustc_hir::Constness,
) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_with_constness_where_possible(infcx, constness);
if !errors.is_empty() {
return errors;
}
}
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
@ -254,15 +238,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.select(&mut selcx)
}
fn select_with_constness_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: hir::Constness,
) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::with_constness(infcx, constness);
self.select(&mut selcx)
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.predicates.map_pending_obligations(|o| o.obligation.clone())
}
@ -679,12 +654,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
if obligation.predicate.is_known_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
//
// If the predicate is considered const, then we cannot use this because
// it will cause false negatives in the ui tests.
if !self.selcx.is_predicate_const(obligation.predicate)
&& infcx.predicate_must_hold_considering_regions(obligation)
{
if infcx.predicate_must_hold_considering_regions(obligation) {
debug!(
"selecting trait at depth {} evaluated to holds",
obligation.recursion_depth
@ -738,12 +708,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
if obligation.predicate.is_global(tcx) {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
//
// If the predicate is considered const, then we cannot use this because
// it will cause false negatives in the ui tests.
if !self.selcx.is_predicate_const(obligation.predicate)
&& self.selcx.infcx().predicate_must_hold_considering_regions(obligation)
{
if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
return ProcessResult::Changed(vec![]);
} else {
tracing::debug!("Does NOT hold: {:?}", obligation);

View file

@ -33,8 +33,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{
self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
COMMON_VTABLE_ENTRIES,
self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, COMMON_VTABLE_ENTRIES,
};
use rustc_span::{sym, Span};
use smallvec::SmallVec;
@ -307,8 +306,11 @@ pub fn normalize_param_env_or_error<'tcx>(
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
let elaborated_env =
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
let elaborated_env = ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
unnormalized_env.reveal(),
unnormalized_env.constness(),
);
// HACK: we are trying to normalize the param-env inside *itself*. The problem is that
// normalization expects its param-env to be already normalized, which means we have
@ -360,8 +362,11 @@ pub fn normalize_param_env_or_error<'tcx>(
// predicates here anyway. Keeping them here anyway because it seems safer.
let outlives_env: Vec<_> =
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
let outlives_env =
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
let outlives_env = ty::ParamEnv::new(
tcx.intern_predicates(&outlives_env),
unnormalized_env.reveal(),
unnormalized_env.constness(),
);
let outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
@ -381,7 +386,11 @@ pub fn normalize_param_env_or_error<'tcx>(
let mut predicates = non_outlives_predicates;
predicates.extend(outlives_predicates);
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
unnormalized_env.reveal(),
unnormalized_env.constness(),
)
}
pub fn fully_normalize<'a, 'tcx, T>(
@ -564,14 +573,17 @@ fn prepare_vtable_segments<'tcx, T>(
.predicates
.into_iter()
.filter_map(move |(pred, _)| {
pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_ref()
pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
});
'diving_in_skip_visited_traits: loop {
if let Some(next_super_trait) = direct_super_traits_iter.next() {
if visited.insert(next_super_trait.to_predicate(tcx)) {
// We're throwing away potential constness of super traits here.
// FIXME: handle ~const super traits
let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref);
stack.push((
next_super_trait.value,
next_super_trait,
emit_vptr_on_new_entry,
Some(direct_super_traits_iter),
));
@ -603,7 +615,11 @@ fn prepare_vtable_segments<'tcx, T>(
if let Some(siblings) = siblings_opt {
if let Some(next_inner_most_trait_ref) = siblings.next() {
if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
*inner_most_trait_ref = next_inner_most_trait_ref.value;
// We're throwing away potential constness of super traits here.
// FIXME: handle ~const super traits
let next_inner_most_trait_ref =
next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
*inner_most_trait_ref = next_inner_most_trait_ref;
*emit_vptr = emit_vptr_on_new_entry;
break 'exiting_out;
} else {

View file

@ -18,7 +18,7 @@ use rustc_errors::FatalError;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_middle::ty::{Predicate, ToPredicate};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
@ -698,7 +698,11 @@ fn receiver_is_dispatchable<'tcx>(
.chain(array::IntoIter::new([unsize_predicate, trait_predicate]))
.collect();
ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
ty::ParamEnv::new(
tcx.intern_predicates(&caller_bounds),
param_env.reveal(),
param_env.constness(),
)
};
// Receiver: DispatchFromDyn<Receiver[Self => U]>

View file

@ -27,7 +27,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
use std::collections::BTreeMap;

View file

@ -11,7 +11,7 @@ use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
use rustc_target::spec::abi::Abi;
use crate::traits;
@ -303,7 +303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} else if lang_items.drop_trait() == Some(def_id)
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
{
if self.is_in_const_context {
if obligation.param_env.constness() == hir::Constness::Const {
self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
} else {
debug!("passing ~const Drop bound; in non-const context");
@ -383,17 +383,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.param_env
.caller_bounds()
.iter()
.filter_map(|o| o.to_opt_poly_trait_ref());
.filter_map(|o| o.to_opt_poly_trait_pred());
// Micro-optimization: filter out predicates relating to different traits.
let matching_bounds =
all_bounds.filter(|p| p.value.def_id() == stack.obligation.predicate.def_id());
all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
// Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in matching_bounds {
let wc = self.evaluate_where_clause(stack, bound.value)?;
// FIXME(oli-obk): it is suspicious that we are dropping the constness and
// polarity here.
let wc = self.evaluate_where_clause(stack, bound.map_bound(|t| t.trait_ref))?;
if wc.may_apply() {
candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
candidates.vec.push(ParamCandidate(bound));
}
}

View file

@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
@ -58,8 +58,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ParamCandidate(param) => {
let obligations = self.confirm_param_candidate(obligation, param.0.value);
Ok(ImplSource::Param(obligations, param.0.constness))
let obligations =
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
Ok(ImplSource::Param(obligations, param.skip_binder().constness))
}
ImplCandidate(impl_def_id) => {
@ -139,7 +140,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
let placeholder_trait_predicate =
self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
@ -150,8 +151,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs);
let candidate = candidate_predicate
.to_opt_poly_trait_ref()
.expect("projection candidate is not a trait predicate");
.to_opt_poly_trait_pred()
.expect("projection candidate is not a trait predicate")
.map_bound(|t| t.trait_ref);
let mut obligations = Vec::new();
let candidate = normalize_with_depth_to(
self,
@ -165,7 +167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations.extend(self.infcx.commit_if_ok(|_| {
self.infcx
.at(&obligation.cause, obligation.param_env)
.sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value)
.sup(placeholder_trait_predicate, candidate)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)
})?);

View file

@ -39,7 +39,6 @@ use rustc_middle::ty::fast_reject;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
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::{Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::sym;
@ -128,9 +127,6 @@ pub struct SelectionContext<'cx, 'tcx> {
/// and a negative impl
allow_negative_impls: bool,
/// Are we in a const context that needs `~const` bounds to be const?
is_in_const_context: bool,
/// The mode that trait queries run in, which informs our error handling
/// policy. In essence, canonicalized queries need their errors propagated
/// rather than immediately reported because we do not have accurate spans.
@ -141,9 +137,9 @@ pub struct SelectionContext<'cx, 'tcx> {
struct TraitObligationStack<'prev, '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.
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
/// Starts out equal to `depth` -- if, during evaluation, we
/// encounter a cycle, then we will set this flag to the minimum
@ -222,7 +218,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@ -234,7 +229,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: true,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@ -250,7 +244,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@ -266,26 +259,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
is_in_const_context: false,
query_mode,
}
}
pub fn with_constness(
infcx: &'cx InferCtxt<'cx, 'tcx>,
constness: hir::Constness,
) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
is_in_const_context: matches!(constness, hir::Constness::Const),
query_mode: TraitQueryMode::Standard,
}
}
/// Enables tracking of intercrate ambiguity causes. These are
/// used in coherence to give improved diagnostics. We don't do
/// this until we detect a coherence error because it can lead to
@ -318,20 +295,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.intercrate
}
/// Returns `true` if the trait predicate is considerd `const` to this selection context.
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
}
/// Returns `true` if the predicate is considered `const` to
/// this selection context.
pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
match pred.kind().skip_binder() {
ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred),
_ => false,
}
}
///////////////////////////////////////////////////////////////////////////
// Selection
//
@ -712,20 +675,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
let stack = self.push_stack(previous_stack, &obligation);
let fresh_trait_ref = stack.fresh_trait_ref;
let mut fresh_trait_pred = stack.fresh_trait_pred;
let mut param_env = obligation.param_env;
debug!(?fresh_trait_ref);
fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
pred
});
if let Some(result) = self.check_evaluation_cache(
obligation.param_env,
fresh_trait_ref,
obligation.polarity(),
) {
debug!(?fresh_trait_pred);
if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
debug!(?result, "CACHE HIT");
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");
stack.update_reached_depth(result.reached_depth);
return Ok(result.result);
@ -750,19 +715,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let reached_depth = stack.reached_depth.get();
if reached_depth >= stack.depth {
debug!(?result, "CACHE MISS");
self.insert_evaluation_cache(
obligation.param_env,
fresh_trait_ref,
obligation.polarity(),
dep_node,
result,
);
self.insert_evaluation_cache(param_env, fresh_trait_pred, 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(
obligation.param_env,
fresh_trait_ref,
obligation.polarity(),
param_env,
fresh_trait_pred,
dep_node,
provisional_result.max(result),
);
@ -772,10 +730,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(
"caching provisionally because {:?} \
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)
@ -809,7 +767,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.skip(1) // Skip top-most frame.
.find(|prev| {
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)
{
@ -872,7 +830,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// terms of `Fn` etc, but we could probably make this more
// precise still.
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 {
// This check was an imperfect workaround for a bug in the old
@ -910,8 +868,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
&& self.match_fresh_trait_refs(
stack.fresh_trait_ref,
prev.fresh_trait_ref,
stack.fresh_trait_pred,
prev.fresh_trait_pred,
prev.obligation.param_env,
)
})
@ -989,7 +947,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// not just the lifetime choice for this particular (non-erased)
// predicate.
// See issue #80691
if stack.fresh_trait_ref.has_erased_regions() {
if stack.fresh_trait_pred.has_erased_regions() {
result = result.max(EvaluatedToOkModuloRegions);
}
@ -1000,8 +958,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_evaluation_cache(
&self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
polarity: ty::ImplPolarity,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<EvaluationResult> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
@ -1013,19 +970,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.tcx();
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(&param_env.and(trait_pred), tcx) {
return Some(res);
}
}
self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
self.infcx.evaluation_cache.get(&param_env.and(trait_pred), tcx)
}
fn insert_evaluation_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
polarity: ty::ImplPolarity,
trait_pred: ty::PolyTraitPredicate<'tcx>,
dep_node: DepNodeIndex,
result: EvaluationResult,
) {
@ -1044,23 +999,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if self.can_use_global_caches(param_env) {
if !trait_ref.needs_infer() {
debug!(?trait_ref, ?result, "insert_evaluation_cache global");
if !trait_pred.needs_infer() {
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
// This may overwrite the cache with the same value
// FIXME: Due to #50507 this overwrites the different values
// This should be changed to use HashMapExt::insert_same
// when that is fixed
self.tcx().evaluation_cache.insert(
(param_env.and(trait_ref), polarity),
dep_node,
result,
);
self.tcx().evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
return;
}
}
debug!(?trait_ref, ?result, "insert_evaluation_cache");
self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
debug!(?trait_pred, ?result, "insert_evaluation_cache");
self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
}
/// For various reasons, it's possible for a subobligation
@ -1138,16 +1089,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
for candidate in candidates {
// Respect const trait obligations
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
if obligation.is_const() {
match candidate {
// const impl
ImplCandidate(def_id)
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
// const param
ParamCandidate((
ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
_,
)) => {}
ParamCandidate(trait_pred)
if trait_pred.skip_binder().constness
== ty::BoundConstness::ConstIfConst => {}
// auto trait impl
AutoImplCandidate(..) => {}
// generator, this will raise error in other places
@ -1256,7 +1206,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_candidate_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
mut param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
// Neither the global nor local cache is aware of intercrate
@ -1267,19 +1217,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return None;
}
let tcx = self.tcx();
let pred = &cache_fresh_trait_pred.skip_binder();
let trait_ref = pred.trait_ref;
let mut pred = cache_fresh_trait_pred.skip_binder();
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx
.selection_cache
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
{
if let Some(res) = tcx.selection_cache.get(&param_env.and(pred), tcx) {
return Some(res);
}
}
self.infcx
.selection_cache
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
self.infcx.selection_cache.get(&param_env.and(pred), tcx)
}
/// Determines whether can we safely cache the result
@ -1317,43 +1263,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn insert_candidate_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
mut param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
dep_node: DepNodeIndex,
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
) {
let tcx = self.tcx();
let pred = cache_fresh_trait_pred.skip_binder();
let trait_ref = pred.trait_ref;
let mut pred = cache_fresh_trait_pred.skip_binder();
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
if !self.can_cache_candidate(&candidate) {
debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable");
return;
}
if self.can_use_global_caches(param_env) {
if let Err(Overflow) = candidate {
// Don't cache overflow globally; we only produce this in certain modes.
} else if !trait_ref.needs_infer() {
} else if !pred.needs_infer() {
if !candidate.needs_infer() {
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
debug!(?pred, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
tcx.selection_cache.insert(
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
tcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
return;
}
}
}
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
self.infcx.selection_cache.insert(
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
debug!(?pred, ?candidate, "insert_candidate_cache local");
self.infcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
}
/// Matches a predicate against the bounds of its self type.
@ -1544,7 +1483,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
};
@ -1577,25 +1516,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ConstDropCandidate,
) => false,
(
ParamCandidate((other, other_polarity)),
ParamCandidate((victim, victim_polarity)),
) => {
let same_except_bound_vars = other.value.skip_binder()
== victim.value.skip_binder()
&& other.constness == victim.constness
&& other_polarity == victim_polarity
&& !other.value.skip_binder().has_escaping_bound_vars();
(ParamCandidate(other), ParamCandidate(victim)) => {
let same_except_bound_vars = other.skip_binder().trait_ref
== victim.skip_binder().trait_ref
&& other.skip_binder().constness == victim.skip_binder().constness
&& other.skip_binder().polarity == victim.skip_binder().polarity
&& !other.skip_binder().trait_ref.has_escaping_bound_vars();
if same_except_bound_vars {
// See issue #84398. In short, we can generate multiple ParamCandidates which are
// the same except for unused bound vars. Just pick the one with the fewest bound vars
// or the current one if tied (they should both evaluate to the same answer). This is
// probably best characterized as a "hack", since we might prefer to just do our
// best to *not* create essentially duplicate candidates in the first place.
other.value.bound_vars().len() <= victim.value.bound_vars().len()
} else if other.value == victim.value
&& victim.constness == ty::BoundConstness::NotConst
&& other_polarity == victim_polarity
other.bound_vars().len() <= victim.bound_vars().len()
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
&& other.skip_binder().polarity == victim.skip_binder().polarity
{
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
@ -1625,11 +1561,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitAliasCandidate(..)
| ObjectCandidate(_)
| ProjectionCandidate(_),
) => !is_global(&cand.0.value),
) => !is_global(cand),
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(&cand.0.value)
is_global(cand)
}
(
ImplCandidate(_)
@ -1645,7 +1581,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
is_global(cand) && other.evaluation.must_apply_modulo_regions()
}
(ProjectionCandidate(i), ProjectionCandidate(j))
@ -2205,8 +2141,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn match_fresh_trait_refs(
&self,
previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
current: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
previous: ty::PolyTraitPredicate<'tcx>,
current: ty::PolyTraitPredicate<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
@ -2218,18 +2154,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &'o TraitObligation<'tcx>,
) -> TraitObligationStack<'o, 'tcx> {
let fresh_trait_ref = obligation
.predicate
.to_poly_trait_ref()
.fold_with(&mut self.freshener)
.into_ok()
.with_constness(obligation.predicate.skip_binder().constness);
let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener).into_ok();
let dfn = previous_stack.cache.next_dfn();
let depth = previous_stack.depth() + 1;
TraitObligationStack {
obligation,
fresh_trait_ref,
fresh_trait_pred,
reached_depth: Cell::new(depth),
previous: previous_stack,
dfn,
@ -2423,7 +2354,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
debug!(reached_depth, "update_reached_depth");
let mut p = self;
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 = p.previous.head.unwrap();
}
@ -2502,7 +2433,7 @@ struct ProvisionalEvaluationCache<'tcx> {
/// - then we determine that `E` is in error -- we will then clear
/// all cache values whose DFN is >= 4 -- in this case, that
/// 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
@ -2534,28 +2465,28 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
/// `reached_depth` (from the returned value).
fn get_provisional(
&self,
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<ProvisionalEvaluation> {
debug!(
?fresh_trait_ref,
?fresh_trait_pred,
"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
/// 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`.
fn insert_provisional(
&self,
from_dfn: usize,
reached_depth: usize,
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
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();
@ -2579,7 +2510,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
@ -2630,16 +2561,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
fn on_completion(
&self,
dfn: usize,
mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
) {
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)
{
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);
}
}
}

View file

@ -508,9 +508,9 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<St
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
for (p, _) in predicates {
if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
if Some(poly_trait_ref.value.def_id()) == sized_trait {
types_without_default_bounds.remove(poly_trait_ref.value.self_ty().skip_binder());
if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
if Some(poly_trait_ref.def_id()) == sized_trait {
types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
continue;
}
}

View file

@ -6,7 +6,7 @@ use smallvec::SmallVec;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
pub use rustc_infer::traits::{self, util::*};
@ -126,8 +126,8 @@ impl<'tcx> TraitAliasExpander<'tcx> {
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
pred.subst_supertrait(tcx, &trait_ref)
.to_opt_poly_trait_ref()
.map(|trait_ref| item.clone_and_push(trait_ref.value, *span))
.to_opt_poly_trait_pred()
.map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
});
debug!("expand_trait_aliases: items={:?}", items.clone());
@ -183,8 +183,8 @@ impl Iterator for SupertraitDefIds<'tcx> {
predicates
.predicates
.iter()
.filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
.map(|trait_ref| trait_ref.value.def_id())
.filter_map(|(pred, _)| pred.to_opt_poly_trait_pred())
.map(|trait_ref| trait_ref.def_id())
.filter(|&super_def_id| visited.insert(super_def_id)),
);
Some(def_id)

View file

@ -6,7 +6,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use std::iter;
@ -298,9 +298,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let extend = |obligation: traits::PredicateObligation<'tcx>| {
let mut cause = cause.clone();
if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() {
if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() {
let derived_cause = traits::DerivedObligationCause {
parent_trait_ref: parent_trait_ref.value,
// FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
parent_code: Lrc::new(obligation.cause.code.clone()),
};
cause.make_mut().code =