1
Fork 0

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

This reverts commit 18bb8c61a9, reversing
changes made to d9baa36190.
This commit is contained in:
Santiago Pastorino 2021-12-03 10:11:21 -03:00
parent 3e21768a0a
commit 85b723c4e6
No known key found for this signature in database
GPG key ID: 8131A24E0C79EFAF
49 changed files with 428 additions and 376 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};
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::{DiagnosticMessageId, Limit};
use rustc_span::def_id::LOCAL_CRATE;

View file

@ -9,6 +9,7 @@ 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,17 +370,12 @@ 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(),
param_env.constness(),
);
new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal());
}
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,
TypeFoldable, WithConstness,
};
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,
Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_session::Limit;

View file

@ -4,6 +4,7 @@ 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;
@ -230,6 +231,21 @@ 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>,
@ -238,6 +254,15 @@ 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())
}
@ -654,7 +679,12 @@ 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 infcx.predicate_must_hold_considering_regions(obligation) {
//
// 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)
{
debug!(
"selecting trait at depth {} evaluated to holds",
obligation.recursion_depth
@ -708,7 +738,12 @@ 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 self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
//
// 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)
{
return ProcessResult::Changed(vec![]);
} else {
tracing::debug!("Does NOT hold: {:?}", obligation);

View file

@ -33,7 +33,8 @@ 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, COMMON_VTABLE_ENTRIES,
self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
COMMON_VTABLE_ENTRIES,
};
use rustc_span::{sym, Span};
use smallvec::SmallVec;
@ -306,11 +307,8 @@ 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(),
unnormalized_env.constness(),
);
let elaborated_env =
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
// 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
@ -362,11 +360,8 @@ 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(),
unnormalized_env.constness(),
);
let outlives_env =
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
let outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
@ -386,11 +381,7 @@ 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(),
unnormalized_env.constness(),
)
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
}
pub fn fully_normalize<'a, 'tcx, T>(
@ -573,17 +564,14 @@ 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_pred()
pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_ref()
});
'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,
next_super_trait.value,
emit_vptr_on_new_entry,
Some(direct_super_traits_iter),
));
@ -615,11 +603,7 @@ 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)) {
// 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;
*inner_most_trait_ref = next_inner_most_trait_ref.value;
*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};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
use rustc_middle::ty::{Predicate, ToPredicate};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
@ -698,11 +698,7 @@ 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(),
param_env.constness(),
)
ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
};
// 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};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
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};
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
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 obligation.param_env.constness() == hir::Constness::Const {
if self.is_in_const_context {
self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
} else {
debug!("passing ~const Drop bound; in non-const context");
@ -383,19 +383,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.param_env
.caller_bounds()
.iter()
.filter_map(|o| o.to_opt_poly_trait_pred());
.filter_map(|o| o.to_opt_poly_trait_ref());
// Micro-optimization: filter out predicates relating to different traits.
let matching_bounds =
all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
all_bounds.filter(|p| p.value.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 {
// 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))?;
let wc = self.evaluate_where_clause(stack, bound.value)?;
if wc.may_apply() {
candidates.vec.push(ParamCandidate(bound));
candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
}
}

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};
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
@ -58,9 +58,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ParamCandidate(param) => {
let obligations =
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
Ok(ImplSource::Param(obligations, param.skip_binder().constness))
let obligations = self.confirm_param_candidate(obligation, param.0.value);
Ok(ImplSource::Param(obligations, param.0.constness))
}
ImplCandidate(impl_def_id) => {
@ -140,7 +139,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).trait_ref;
self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
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() {
@ -151,9 +150,8 @@ 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_pred()
.expect("projection candidate is not a trait predicate")
.map_bound(|t| t.trait_ref);
.to_opt_poly_trait_ref()
.expect("projection candidate is not a trait predicate");
let mut obligations = Vec::new();
let candidate = normalize_with_depth_to(
self,
@ -167,7 +165,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, candidate)
.sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)
})?);

View file

@ -39,6 +39,7 @@ 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;
@ -127,6 +128,9 @@ 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.
@ -137,9 +141,9 @@ pub struct SelectionContext<'cx, 'tcx> {
struct TraitObligationStack<'prev, 'tcx> {
obligation: &'prev TraitObligation<'tcx>,
/// The trait predicate from `obligation` but "freshened" with the
/// The trait ref from `obligation` but "freshened" with the
/// selection-context's freshener. Used to check for recursion.
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
/// Starts out equal to `depth` -- if, during evaluation, we
/// encounter a cycle, then we will set this flag to the minimum
@ -218,6 +222,7 @@ 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,
}
}
@ -229,6 +234,7 @@ 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,
}
}
@ -244,6 +250,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@ -259,10 +266,26 @@ 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
@ -295,6 +318,20 @@ 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
//
@ -679,22 +716,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
let stack = self.push_stack(previous_stack, &obligation);
let mut fresh_trait_pred = stack.fresh_trait_pred;
let mut param_env = obligation.param_env;
let fresh_trait_ref = stack.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
});
debug!(?fresh_trait_ref);
debug!(?fresh_trait_pred);
if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
if let Some(result) = self.check_evaluation_cache(
obligation.param_env,
fresh_trait_ref,
obligation.polarity(),
) {
debug!(?result, "CACHE HIT");
return Ok(result);
}
if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
debug!(?result, "PROVISIONAL CACHE HIT");
stack.update_reached_depth(result.reached_depth);
return Ok(result.result);
@ -719,12 +754,19 @@ 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(param_env, fresh_trait_pred, dep_node, result);
self.insert_evaluation_cache(
obligation.param_env,
fresh_trait_ref,
obligation.polarity(),
dep_node,
result,
);
stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
self.insert_evaluation_cache(
param_env,
fresh_trait_pred,
obligation.param_env,
fresh_trait_ref,
obligation.polarity(),
dep_node,
provisional_result.max(result),
);
@ -734,10 +776,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(
"caching provisionally because {:?} \
is a cycle participant (at depth {}, reached depth {})",
fresh_trait_pred, stack.depth, reached_depth,
fresh_trait_ref, stack.depth, reached_depth,
);
stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result);
}
Ok(result)
@ -771,7 +813,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_pred == prev.fresh_trait_pred
&& stack.fresh_trait_ref == prev.fresh_trait_ref
})
.map(|stack| stack.depth)
{
@ -834,7 +876,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_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
stack.fresh_trait_ref.value.skip_binder().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
@ -872,8 +914,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_pred,
prev.fresh_trait_pred,
stack.fresh_trait_ref,
prev.fresh_trait_ref,
prev.obligation.param_env,
)
})
@ -951,7 +993,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_pred.has_erased_regions() {
if stack.fresh_trait_ref.has_erased_regions() {
result = result.max(EvaluatedToOkModuloRegions);
}
@ -962,7 +1004,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_evaluation_cache(
&self,
param_env: ty::ParamEnv<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
polarity: ty::ImplPolarity,
) -> Option<EvaluationResult> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
@ -974,17 +1017,19 @@ 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_pred), tcx) {
if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
{
return Some(res);
}
}
self.infcx.evaluation_cache.get(&param_env.and(trait_pred), tcx)
self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
}
fn insert_evaluation_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
polarity: ty::ImplPolarity,
dep_node: DepNodeIndex,
result: EvaluationResult,
) {
@ -1003,19 +1048,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if self.can_use_global_caches(param_env) {
if !trait_pred.needs_infer() {
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
if !trait_ref.needs_infer() {
debug!(?trait_ref, ?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_pred), dep_node, result);
self.tcx().evaluation_cache.insert(
(param_env.and(trait_ref), polarity),
dep_node,
result,
);
return;
}
}
debug!(?trait_pred, ?result, "insert_evaluation_cache");
self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
debug!(?trait_ref, ?result, "insert_evaluation_cache");
self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
}
/// For various reasons, it's possible for a subobligation
@ -1093,15 +1142,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
for candidate in candidates {
// Respect const trait obligations
if obligation.is_const() {
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
match candidate {
// const impl
ImplCandidate(def_id)
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
// const param
ParamCandidate(trait_pred)
if trait_pred.skip_binder().constness
== ty::BoundConstness::ConstIfConst => {}
ParamCandidate((
ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
_,
)) => {}
// auto trait impl
AutoImplCandidate(..) => {}
// generator, this will raise error in other places
@ -1210,7 +1260,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_candidate_cache(
&mut self,
mut param_env: ty::ParamEnv<'tcx>,
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
@ -1221,15 +1271,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return None;
}
let tcx = self.tcx();
let mut pred = cache_fresh_trait_pred.skip_binder();
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
let pred = &cache_fresh_trait_pred.skip_binder();
let trait_ref = pred.trait_ref;
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx.selection_cache.get(&param_env.and(pred), tcx) {
if let Some(res) = tcx
.selection_cache
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
{
return Some(res);
}
}
self.infcx.selection_cache.get(&param_env.and(pred), tcx)
self.infcx
.selection_cache
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
}
/// Determines whether can we safely cache the result
@ -1267,36 +1321,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn insert_candidate_cache(
&mut self,
mut param_env: ty::ParamEnv<'tcx>,
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 mut pred = cache_fresh_trait_pred.skip_binder();
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
let pred = cache_fresh_trait_pred.skip_binder();
let trait_ref = pred.trait_ref;
if !self.can_cache_candidate(&candidate) {
debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable");
debug!(?trait_ref, ?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 !pred.needs_infer() {
} else if !trait_ref.needs_infer() {
if !candidate.needs_infer() {
debug!(?pred, ?candidate, "insert_candidate_cache global");
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
tcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
tcx.selection_cache.insert(
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
return;
}
}
}
debug!(?pred, ?candidate, "insert_candidate_cache local");
self.infcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
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,
);
}
/// Matches a predicate against the bounds of its self type.
@ -1487,7 +1548,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::PolyTraitPredicate<'tcx>| {
let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
};
@ -1520,22 +1581,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ConstDropCandidate,
) => false,
(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();
(
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();
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.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
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
{
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
@ -1565,11 +1629,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitAliasCandidate(..)
| ObjectCandidate(_)
| ProjectionCandidate(_),
) => !is_global(cand),
) => !is_global(&cand.0.value),
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(cand)
is_global(&cand.0.value)
}
(
ImplCandidate(_)
@ -1585,7 +1649,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(cand) && other.evaluation.must_apply_modulo_regions()
is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
}
(ProjectionCandidate(i), ProjectionCandidate(j))
@ -2145,8 +2209,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn match_fresh_trait_refs(
&self,
previous: ty::PolyTraitPredicate<'tcx>,
current: ty::PolyTraitPredicate<'tcx>,
previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
current: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
@ -2158,13 +2222,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &'o TraitObligation<'tcx>,
) -> TraitObligationStack<'o, 'tcx> {
let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener);
let fresh_trait_ref = obligation
.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 depth = previous_stack.depth() + 1;
TraitObligationStack {
obligation,
fresh_trait_pred,
fresh_trait_ref,
reached_depth: Cell::new(depth),
previous: previous_stack,
dfn,
@ -2358,7 +2426,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_pred, "update_reached_depth: marking as cycle participant");
debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant");
p.reached_depth.set(p.reached_depth.get().min(reached_depth));
p = p.previous.head.unwrap();
}
@ -2437,7 +2505,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::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
map: RefCell<FxHashMap<ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ProvisionalEvaluation>>,
}
/// A cache value for the provisional cache: contains the depth-first
@ -2469,28 +2537,28 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
/// `reached_depth` (from the returned value).
fn get_provisional(
&self,
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
) -> Option<ProvisionalEvaluation> {
debug!(
?fresh_trait_pred,
?fresh_trait_ref,
"get_provisional = {:#?}",
self.map.borrow().get(&fresh_trait_pred),
self.map.borrow().get(&fresh_trait_ref),
);
Some(*self.map.borrow().get(&fresh_trait_pred)?)
Some(*self.map.borrow().get(&fresh_trait_ref)?)
}
/// 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_pred`
/// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
/// and resulted in `result`.
fn insert_provisional(
&self,
from_dfn: usize,
reached_depth: usize,
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
result: EvaluationResult,
) {
debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional");
let mut map = self.map.borrow_mut();
@ -2514,7 +2582,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
}
}
map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
map.insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, reached_depth, result });
}
/// Invoked when the node with dfn `dfn` does not get a successful
@ -2565,16 +2633,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
fn on_completion(
&self,
dfn: usize,
mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
) {
debug!(?dfn, "on_completion");
for (fresh_trait_pred, eval) in
for (fresh_trait_ref, eval) in
self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
{
debug!(?fresh_trait_pred, ?eval, "on_completion");
debug!(?fresh_trait_ref, ?eval, "on_completion");
op(fresh_trait_pred, eval.result);
op(fresh_trait_ref, 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_pred() {
if Some(poly_trait_ref.def_id()) == sized_trait {
types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
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());
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};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
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_pred()
.map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
.to_opt_poly_trait_ref()
.map(|trait_ref| item.clone_and_push(trait_ref.value, *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_pred())
.map(|trait_ref| trait_ref.def_id())
.filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
.map(|trait_ref| trait_ref.value.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};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_span::Span;
use std::iter;
@ -298,10 +298,9 @@ 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_pred() {
if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() {
let derived_cause = traits::DerivedObligationCause {
// FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
parent_trait_ref: parent_trait_ref.value,
parent_code: Lrc::new(obligation.cause.code.clone()),
};
cause.make_mut().code =