mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Auto merge of #91491 - spastorino:revert-91354, r=oli-obk
Revert "Auto merge of #91354 - fee1-dead:const_env, r=spastorino" This reverts commit18bb8c61a9
, reversing changes made tod9baa36190
. Reverts #91354 in order to address #91489. We would need to place this changes in a more granular way and would also be nice to address the small perf regression that was also introduced. r? `@oli-obk` cc `@fee1-dead`
This commit is contained in:
commit
ff2439b7b9
@ -31,7 +31,7 @@ use rustc_middle::ty::fold::TypeFoldable;
|
|||||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
|
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
|
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
|
||||||
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
|
||||||
};
|
};
|
||||||
use rustc_span::def_id::CRATE_DEF_ID;
|
use rustc_span::def_id::CRATE_DEF_ID;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
@ -7,7 +7,6 @@ use crate::interpret::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
@ -216,7 +215,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
||||||
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
|
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
|
||||||
assert!(key.param_env.constness() == hir::Constness::Const);
|
|
||||||
// see comment in eval_to_allocation_raw_provider for what we're doing here
|
// see comment in eval_to_allocation_raw_provider for what we're doing here
|
||||||
if key.param_env.reveal() == Reveal::All {
|
if key.param_env.reveal() == Reveal::All {
|
||||||
let mut key = key;
|
let mut key = key;
|
||||||
@ -251,7 +249,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
||||||
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
|
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
|
||||||
assert!(key.param_env.constness() == hir::Constness::Const);
|
|
||||||
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
|
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
|
||||||
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
|
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
|
||||||
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
|
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
|
||||||
|
@ -918,7 +918,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
} else {
|
} else {
|
||||||
self.param_env
|
self.param_env
|
||||||
};
|
};
|
||||||
let param_env = param_env.with_const();
|
|
||||||
let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
|
let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
|
||||||
self.raw_const_to_mplace(val)
|
self.raw_const_to_mplace(val)
|
||||||
}
|
}
|
||||||
|
@ -817,7 +817,8 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx =
|
||||||
|
SelectionContext::with_constness(&infcx, hir::Constness::Const);
|
||||||
selcx.select(&obligation)
|
selcx.select(&obligation)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
//! See the `Qualif` trait for more info.
|
//! See the `Qualif` trait for more info.
|
||||||
|
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
|
use rustc_hir as hir;
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
|
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
|
||||||
@ -166,7 +167,7 @@ impl Qualif for NeedsNonConstDrop {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
|
let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
|
||||||
selcx.select(&obligation)
|
selcx.select(&obligation)
|
||||||
});
|
});
|
||||||
!matches!(
|
!matches!(
|
||||||
|
@ -3230,6 +3230,31 @@ impl<'hir> Node<'hir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `Constness::Const` when this node is a const fn/impl/item.
|
||||||
|
pub fn constness_for_typeck(&self) -> Constness {
|
||||||
|
match self {
|
||||||
|
Node::Item(Item {
|
||||||
|
kind: ItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| Node::TraitItem(TraitItem {
|
||||||
|
kind: TraitItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| Node::ImplItem(ImplItem {
|
||||||
|
kind: ImplItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| Node::Item(Item { kind: ItemKind::Impl(Impl { constness, .. }), .. }) => *constness,
|
||||||
|
|
||||||
|
Node::Item(Item { kind: ItemKind::Const(..), .. })
|
||||||
|
| Node::TraitItem(TraitItem { kind: TraitItemKind::Const(..), .. })
|
||||||
|
| Node::ImplItem(ImplItem { kind: ImplItemKind::Const(..), .. }) => Constness::Const,
|
||||||
|
|
||||||
|
_ => Constness::NotConst,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_owner(self) -> Option<OwnerNode<'hir>> {
|
pub fn as_owner(self) -> Option<OwnerNode<'hir>> {
|
||||||
match self {
|
match self {
|
||||||
Node::Item(i) => Some(OwnerNode::Item(i)),
|
Node::Item(i) => Some(OwnerNode::Item(i)),
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use crate::traits::Obligation;
|
use crate::traits::Obligation;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::ty::{self, ToPredicate, Ty};
|
use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
|
||||||
|
|
||||||
use super::FulfillmentError;
|
use super::FulfillmentError;
|
||||||
use super::{ObligationCause, PredicateObligation};
|
use super::{ObligationCause, PredicateObligation};
|
||||||
@ -47,9 +48,26 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
|||||||
|
|
||||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
|
fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
|
||||||
|
|
||||||
|
fn select_all_with_constness_or_error(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
_constness: hir::Constness,
|
||||||
|
) -> Vec<FulfillmentError<'tcx>> {
|
||||||
|
self.select_all_or_error(infcx)
|
||||||
|
}
|
||||||
|
|
||||||
fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
|
fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
|
||||||
-> Vec<FulfillmentError<'tcx>>;
|
-> Vec<FulfillmentError<'tcx>>;
|
||||||
|
|
||||||
|
// FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
|
||||||
|
fn select_with_constness_where_possible(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
_constness: hir::Constness,
|
||||||
|
) -> Vec<FulfillmentError<'tcx>> {
|
||||||
|
self.select_where_possible(infcx)
|
||||||
|
}
|
||||||
|
|
||||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
|
||||||
|
|
||||||
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
|
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
|
||||||
|
@ -69,16 +69,6 @@ impl PredicateObligation<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TraitObligation<'tcx> {
|
|
||||||
/// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
|
|
||||||
pub fn is_const(&self) -> bool {
|
|
||||||
match (self.predicate.skip_binder().constness, self.param_env.constness()) {
|
|
||||||
(ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
static_assert_size!(PredicateObligation<'_>, 32);
|
static_assert_size!(PredicateObligation<'_>, 32);
|
||||||
|
@ -3,7 +3,7 @@ use smallvec::smallvec;
|
|||||||
use crate::infer::outlives::components::{push_outlives_components, Component};
|
use crate::infer::outlives::components::{push_outlives_components, Component};
|
||||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||||
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
|
use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
@ -328,8 +328,8 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
|
|||||||
));
|
));
|
||||||
for (super_predicate, _) in super_predicates.predicates {
|
for (super_predicate, _) in super_predicates.predicates {
|
||||||
let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
|
let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
|
||||||
if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
|
if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
|
||||||
stack.push(binder.map_bound(|t| t.trait_ref));
|
stack.push(binder.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,8 +362,8 @@ impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToT
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||||
while let Some(obligation) = self.base_iterator.next() {
|
while let Some(obligation) = self.base_iterator.next() {
|
||||||
if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() {
|
if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() {
|
||||||
return Some(data.map_bound(|t| t.trait_ref));
|
return Some(data.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -474,8 +474,7 @@ impl<'hir> Map<'hir> {
|
|||||||
/// Panics if `LocalDefId` does not have an associated body.
|
/// Panics if `LocalDefId` does not have an associated body.
|
||||||
///
|
///
|
||||||
/// This should only be used for determining the context of a body, a return
|
/// This should only be used for determining the context of a body, a return
|
||||||
/// value of `Some` does not always suggest that the owner of the body is `const`,
|
/// value of `Some` does not always suggest that the owner of the body is `const`.
|
||||||
/// just that it has to be checked as if it were.
|
|
||||||
pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
|
pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
|
||||||
let hir_id = self.local_def_id_to_hir_id(did);
|
let hir_id = self.local_def_id_to_hir_id(did);
|
||||||
let ccx = match self.body_owner_kind(hir_id) {
|
let ccx = match self.body_owner_kind(hir_id) {
|
||||||
|
@ -64,7 +64,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
cid: GlobalId<'tcx>,
|
cid: GlobalId<'tcx>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
) -> EvalToConstValueResult<'tcx> {
|
) -> EvalToConstValueResult<'tcx> {
|
||||||
let param_env = param_env.with_const();
|
|
||||||
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
|
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
|
||||||
// improve caching of queries.
|
// improve caching of queries.
|
||||||
let inputs = self.erase_regions(param_env.and(cid));
|
let inputs = self.erase_regions(param_env.and(cid));
|
||||||
@ -93,7 +92,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
gid: GlobalId<'tcx>,
|
gid: GlobalId<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Result<&'tcx mir::Allocation, ErrorHandled> {
|
) -> Result<&'tcx mir::Allocation, ErrorHandled> {
|
||||||
let param_env = param_env.with_const();
|
|
||||||
trace!("eval_to_allocation: Need to compute {:?}", gid);
|
trace!("eval_to_allocation: Need to compute {:?}", gid);
|
||||||
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
|
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
|
||||||
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
|
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
|
||||||
|
@ -12,12 +12,14 @@ 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::TraitPredicate<'tcx>>,
|
(ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
|
||||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
pub type EvaluationCache<'tcx> =
|
pub type EvaluationCache<'tcx> = Cache<
|
||||||
Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitPredicate<'tcx>>, EvaluationResult>;
|
(ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
|
||||||
|
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
|
||||||
@ -101,7 +103,7 @@ pub enum SelectionCandidate<'tcx> {
|
|||||||
/// `false` if there are no *further* obligations.
|
/// `false` if there are no *further* obligations.
|
||||||
has_nested: bool,
|
has_nested: bool,
|
||||||
},
|
},
|
||||||
ParamCandidate(ty::PolyTraitPredicate<'tcx>),
|
ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
|
||||||
ImplCandidate(DefId),
|
ImplCandidate(DefId),
|
||||||
AutoImplCandidate(DefId),
|
AutoImplCandidate(DefId),
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ impl<'tcx> Elaborator<'tcx> {
|
|||||||
.predicates
|
.predicates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|(pred, _)| {
|
.flat_map(|(pred, _)| {
|
||||||
pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
|
pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_ref()
|
||||||
})
|
})
|
||||||
.map(|t| t.map_bound(|pred| pred.trait_ref))
|
.map(|t| t.value)
|
||||||
.filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
|
.filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
|
||||||
|
|
||||||
self.stack.extend(supertrait_refs);
|
self.stack.extend(supertrait_refs);
|
||||||
|
@ -230,19 +230,6 @@ pub enum BoundConstness {
|
|||||||
ConstIfConst,
|
ConstIfConst,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoundConstness {
|
|
||||||
/// Reduce `self` and `constness` to two possible combined states instead of four.
|
|
||||||
pub fn and(&mut self, constness: hir::Constness) -> hir::Constness {
|
|
||||||
match (constness, self) {
|
|
||||||
(hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const,
|
|
||||||
(_, this) => {
|
|
||||||
*this = BoundConstness::NotConst;
|
|
||||||
hir::Constness::NotConst
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for BoundConstness {
|
impl fmt::Display for BoundConstness {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -859,6 +846,20 @@ impl ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
|
||||||
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
|
self.value
|
||||||
|
.map_bound(|trait_ref| {
|
||||||
|
PredicateKind::Trait(ty::TraitPredicate {
|
||||||
|
trait_ref,
|
||||||
|
constness: self.constness,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.to_predicate(tcx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
|
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
|
||||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||||
self.map_bound(PredicateKind::Trait).to_predicate(tcx)
|
self.map_bound(PredicateKind::Trait).to_predicate(tcx)
|
||||||
@ -884,10 +885,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Predicate<'tcx> {
|
impl<'tcx> Predicate<'tcx> {
|
||||||
pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
|
pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
|
||||||
let predicate = self.kind();
|
let predicate = self.kind();
|
||||||
match predicate.skip_binder() {
|
match predicate.skip_binder() {
|
||||||
PredicateKind::Trait(t) => Some(predicate.rebind(t)),
|
PredicateKind::Trait(t) => {
|
||||||
|
Some(ConstnessAnd { constness: t.constness, value: predicate.rebind(t.trait_ref) })
|
||||||
|
}
|
||||||
PredicateKind::Projection(..)
|
PredicateKind::Projection(..)
|
||||||
| PredicateKind::Subtype(..)
|
| PredicateKind::Subtype(..)
|
||||||
| PredicateKind::Coerce(..)
|
| PredicateKind::Coerce(..)
|
||||||
@ -1218,33 +1221,23 @@ pub struct ParamEnv<'tcx> {
|
|||||||
/// want `Reveal::All`.
|
/// want `Reveal::All`.
|
||||||
///
|
///
|
||||||
/// Note: This is packed, use the reveal() method to access it.
|
/// Note: This is packed, use the reveal() method to access it.
|
||||||
packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>,
|
packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, traits::Reveal, true>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
|
||||||
struct ParamTag {
|
const BITS: usize = 1;
|
||||||
reveal: traits::Reveal,
|
|
||||||
constness: hir::Constness,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag {
|
|
||||||
const BITS: usize = 2;
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_usize(self) -> usize {
|
fn into_usize(self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
|
traits::Reveal::UserFacing => 0,
|
||||||
Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1,
|
traits::Reveal::All => 1,
|
||||||
Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2,
|
|
||||||
Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn from_usize(ptr: usize) -> Self {
|
unsafe fn from_usize(ptr: usize) -> Self {
|
||||||
match ptr {
|
match ptr {
|
||||||
0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
|
0 => traits::Reveal::UserFacing,
|
||||||
1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
|
1 => traits::Reveal::All,
|
||||||
2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
|
|
||||||
3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
|
|
||||||
_ => std::hint::unreachable_unchecked(),
|
_ => std::hint::unreachable_unchecked(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1255,7 +1248,6 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
|
|||||||
f.debug_struct("ParamEnv")
|
f.debug_struct("ParamEnv")
|
||||||
.field("caller_bounds", &self.caller_bounds())
|
.field("caller_bounds", &self.caller_bounds())
|
||||||
.field("reveal", &self.reveal())
|
.field("reveal", &self.reveal())
|
||||||
.field("constness", &self.constness())
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1264,7 +1256,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
|
|||||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
||||||
self.caller_bounds().hash_stable(hcx, hasher);
|
self.caller_bounds().hash_stable(hcx, hasher);
|
||||||
self.reveal().hash_stable(hcx, hasher);
|
self.reveal().hash_stable(hcx, hasher);
|
||||||
self.constness().hash_stable(hcx, hasher);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1276,14 +1267,12 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
|
|||||||
Ok(ParamEnv::new(
|
Ok(ParamEnv::new(
|
||||||
self.caller_bounds().try_fold_with(folder)?,
|
self.caller_bounds().try_fold_with(folder)?,
|
||||||
self.reveal().try_fold_with(folder)?,
|
self.reveal().try_fold_with(folder)?,
|
||||||
self.constness().try_fold_with(folder)?,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
|
||||||
self.caller_bounds().visit_with(visitor)?;
|
self.caller_bounds().visit_with(visitor)?;
|
||||||
self.reveal().visit_with(visitor)?;
|
self.reveal().visit_with(visitor)
|
||||||
self.constness().visit_with(visitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1294,7 +1283,7 @@ impl<'tcx> ParamEnv<'tcx> {
|
|||||||
/// type-checking.
|
/// type-checking.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::new(List::empty(), Reveal::UserFacing, hir::Constness::NotConst)
|
Self::new(List::empty(), Reveal::UserFacing)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -1304,12 +1293,7 @@ impl<'tcx> ParamEnv<'tcx> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reveal(self) -> traits::Reveal {
|
pub fn reveal(self) -> traits::Reveal {
|
||||||
self.packed.tag().reveal
|
self.packed.tag()
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn constness(self) -> hir::Constness {
|
|
||||||
self.packed.tag().constness
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a trait environment with no where-clauses in scope
|
/// Construct a trait environment with no where-clauses in scope
|
||||||
@ -1321,31 +1305,17 @@ impl<'tcx> ParamEnv<'tcx> {
|
|||||||
/// or invoke `param_env.with_reveal_all()`.
|
/// or invoke `param_env.with_reveal_all()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reveal_all() -> Self {
|
pub fn reveal_all() -> Self {
|
||||||
Self::new(List::empty(), Reveal::All, hir::Constness::NotConst)
|
Self::new(List::empty(), Reveal::All)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a trait environment with the given set of predicates.
|
/// Construct a trait environment with the given set of predicates.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(caller_bounds: &'tcx List<Predicate<'tcx>>, reveal: Reveal) -> Self {
|
||||||
caller_bounds: &'tcx List<Predicate<'tcx>>,
|
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) }
|
||||||
reveal: Reveal,
|
|
||||||
constness: hir::Constness,
|
|
||||||
) -> Self {
|
|
||||||
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal, constness }) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_user_facing(mut self) -> Self {
|
pub fn with_user_facing(mut self) -> Self {
|
||||||
self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
|
self.packed.set_tag(Reveal::UserFacing);
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_constness(mut self, constness: hir::Constness) -> Self {
|
|
||||||
self.packed.set_tag(ParamTag { constness, ..self.packed.tag() });
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_const(mut self) -> Self {
|
|
||||||
self.packed.set_tag(ParamTag { constness: hir::Constness::Const, ..self.packed.tag() });
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,21 +1329,17 @@ impl<'tcx> ParamEnv<'tcx> {
|
|||||||
/// will be normalized to their underlying types.
|
/// will be normalized to their underlying types.
|
||||||
/// See PR #65989 and issue #65918 for more details
|
/// See PR #65989 and issue #65918 for more details
|
||||||
pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
|
pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
|
||||||
if self.packed.tag().reveal == traits::Reveal::All {
|
if self.packed.tag() == traits::Reveal::All {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParamEnv::new(
|
ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All)
|
||||||
tcx.normalize_opaque_types(self.caller_bounds()),
|
|
||||||
Reveal::All,
|
|
||||||
self.constness(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns this same environment but with no caller bounds.
|
/// Returns this same environment but with no caller bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn without_caller_bounds(self) -> Self {
|
pub fn without_caller_bounds(self) -> Self {
|
||||||
Self::new(List::empty(), self.reveal(), self.constness())
|
Self::new(List::empty(), self.reveal())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a suitable environment in which to perform trait
|
/// Creates a suitable environment in which to perform trait
|
||||||
@ -1403,23 +1369,33 @@ impl<'tcx> ParamEnv<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
|
||||||
|
pub struct ConstnessAnd<T> {
|
||||||
|
pub constness: BoundConstness,
|
||||||
|
pub value: T,
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
|
// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
|
||||||
// the constness of trait bounds is being propagated correctly.
|
// the constness of trait bounds is being propagated correctly.
|
||||||
impl PolyTraitRef<'tcx> {
|
pub trait WithConstness: Sized {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> {
|
fn with_constness(self, constness: BoundConstness) -> ConstnessAnd<Self> {
|
||||||
self.map_bound(|trait_ref| ty::TraitPredicate {
|
ConstnessAnd { constness, value: self }
|
||||||
trait_ref,
|
|
||||||
constness,
|
|
||||||
polarity: ty::ImplPolarity::Positive,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
|
fn with_const_if_const(self) -> ConstnessAnd<Self> {
|
||||||
|
self.with_constness(BoundConstness::ConstIfConst)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn without_const(self) -> ConstnessAnd<Self> {
|
||||||
self.with_constness(BoundConstness::NotConst)
|
self.with_constness(BoundConstness::NotConst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> WithConstness for T {}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
|
||||||
pub struct ParamEnvAnd<'tcx, T> {
|
pub struct ParamEnvAnd<'tcx, T> {
|
||||||
pub param_env: ParamEnv<'tcx>,
|
pub param_env: ParamEnv<'tcx>,
|
||||||
|
@ -218,6 +218,19 @@ impl<'tcx> Relate<'tcx> for ty::BoundConstness {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::ConstnessAnd<T> {
|
||||||
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
|
relation: &mut R,
|
||||||
|
a: ty::ConstnessAnd<T>,
|
||||||
|
b: ty::ConstnessAnd<T>,
|
||||||
|
) -> RelateResult<'tcx, ty::ConstnessAnd<T>> {
|
||||||
|
Ok(ty::ConstnessAnd {
|
||||||
|
constness: relation.relate(a.constness, b.constness)?,
|
||||||
|
value: relation.relate(a.value, b.value)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Relate<'tcx> for ast::Unsafety {
|
impl<'tcx> Relate<'tcx> for ast::Unsafety {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
relation: &mut R,
|
||||||
|
@ -480,7 +480,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
|
|||||||
type Lifted = ty::ParamEnv<'tcx>;
|
type Lifted = ty::ParamEnv<'tcx>;
|
||||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||||
tcx.lift(self.caller_bounds())
|
tcx.lift(self.caller_bounds())
|
||||||
.map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.constness()))
|
.map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,9 @@ use crate::infer::canonical::Canonical;
|
|||||||
use crate::ty::fold::ValidateBoundVars;
|
use crate::ty::fold::ValidateBoundVars;
|
||||||
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
|
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
|
||||||
use crate::ty::InferTy::{self, *};
|
use crate::ty::InferTy::{self, *};
|
||||||
use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
|
use crate::ty::{
|
||||||
|
self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
|
||||||
|
};
|
||||||
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
|
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
|
||||||
use polonius_engine::Atom;
|
use polonius_engine::Atom;
|
||||||
use rustc_data_structures::captures::Captures;
|
use rustc_data_structures::captures::Captures;
|
||||||
|
@ -3,7 +3,7 @@ use crate::traits::{self, TraitEngine};
|
|||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::infer::InferCtxt;
|
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_middle::ty::{ToPredicate, TypeFoldable};
|
||||||
use rustc_session::{DiagnosticMessageId, Limit};
|
use rustc_session::{DiagnosticMessageId, Limit};
|
||||||
use rustc_span::def_id::LOCAL_CRATE;
|
use rustc_span::def_id::LOCAL_CRATE;
|
||||||
|
@ -9,6 +9,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, Quer
|
|||||||
use rustc_middle::traits::query::Fallible;
|
use rustc_middle::traits::query::Fallible;
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::ToPredicate;
|
use rustc_middle::ty::ToPredicate;
|
||||||
|
use rustc_middle::ty::WithConstness;
|
||||||
use rustc_middle::ty::{self, Ty, TypeFoldable};
|
use rustc_middle::ty::{self, Ty, TypeFoldable};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
|
@ -370,17 +370,12 @@ impl AutoTraitFinder<'tcx> {
|
|||||||
computed_preds.clone().chain(user_computed_preds.iter().cloned()),
|
computed_preds.clone().chain(user_computed_preds.iter().cloned()),
|
||||||
)
|
)
|
||||||
.map(|o| o.predicate);
|
.map(|o| o.predicate);
|
||||||
new_env = ty::ParamEnv::new(
|
new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal());
|
||||||
tcx.mk_predicates(normalized_preds),
|
|
||||||
param_env.reveal(),
|
|
||||||
param_env.constness(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let final_user_env = ty::ParamEnv::new(
|
let final_user_env = ty::ParamEnv::new(
|
||||||
tcx.mk_predicates(user_computed_preds.into_iter()),
|
tcx.mk_predicates(user_computed_preds.into_iter()),
|
||||||
user_env.reveal(),
|
user_env.reveal(),
|
||||||
user_env.constness(),
|
|
||||||
);
|
);
|
||||||
debug!(
|
debug!(
|
||||||
"evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
|
"evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
|
||||||
|
@ -24,7 +24,7 @@ use rustc_middle::ty::error::ExpectedFound;
|
|||||||
use rustc_middle::ty::fold::TypeFolder;
|
use rustc_middle::ty::fold::TypeFolder;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
|
self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
|
||||||
TypeFoldable,
|
TypeFoldable, WithConstness,
|
||||||
};
|
};
|
||||||
use rustc_session::DiagnosticMessageId;
|
use rustc_session::DiagnosticMessageId;
|
||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::{kw, sym};
|
||||||
|
@ -21,7 +21,7 @@ use rustc_hir::lang_items::LangItem;
|
|||||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
|
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_middle::ty::{TypeAndMut, TypeckResults};
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
|
@ -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::{Error, ForestObligation, Outcome};
|
||||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
|
use rustc_hir as hir;
|
||||||
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
|
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
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()
|
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(
|
fn select_where_possible(
|
||||||
&mut self,
|
&mut self,
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
@ -238,6 +254,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
|||||||
self.select(&mut selcx)
|
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>> {
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||||
self.predicates.map_pending_obligations(|o| o.obligation.clone())
|
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() {
|
if obligation.predicate.is_known_global() {
|
||||||
// no type variables present, can use evaluation for better caching.
|
// no type variables present, can use evaluation for better caching.
|
||||||
// FIXME: consider caching errors too.
|
// 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!(
|
debug!(
|
||||||
"selecting trait at depth {} evaluated to holds",
|
"selecting trait at depth {} evaluated to holds",
|
||||||
obligation.recursion_depth
|
obligation.recursion_depth
|
||||||
@ -708,7 +738,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
if obligation.predicate.is_global(tcx) {
|
if obligation.predicate.is_global(tcx) {
|
||||||
// no type variables present, can use evaluation for better caching.
|
// no type variables present, can use evaluation for better caching.
|
||||||
// FIXME: consider caching errors too.
|
// 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![]);
|
return ProcessResult::Changed(vec![]);
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("Does NOT hold: {:?}", obligation);
|
tracing::debug!("Does NOT hold: {:?}", obligation);
|
||||||
|
@ -33,7 +33,8 @@ use rustc_hir::lang_items::LangItem;
|
|||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::{
|
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 rustc_span::{sym, Span};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -306,11 +307,8 @@ pub fn normalize_param_env_or_error<'tcx>(
|
|||||||
|
|
||||||
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
|
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
|
||||||
|
|
||||||
let elaborated_env = ty::ParamEnv::new(
|
let elaborated_env =
|
||||||
tcx.intern_predicates(&predicates),
|
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
|
||||||
unnormalized_env.reveal(),
|
|
||||||
unnormalized_env.constness(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// HACK: we are trying to normalize the param-env inside *itself*. The problem is that
|
// 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
|
// 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.
|
// predicates here anyway. Keeping them here anyway because it seems safer.
|
||||||
let outlives_env: Vec<_> =
|
let outlives_env: Vec<_> =
|
||||||
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
|
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
|
||||||
let outlives_env = ty::ParamEnv::new(
|
let outlives_env =
|
||||||
tcx.intern_predicates(&outlives_env),
|
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
|
||||||
unnormalized_env.reveal(),
|
|
||||||
unnormalized_env.constness(),
|
|
||||||
);
|
|
||||||
let outlives_predicates = match do_normalize_predicates(
|
let outlives_predicates = match do_normalize_predicates(
|
||||||
tcx,
|
tcx,
|
||||||
region_context,
|
region_context,
|
||||||
@ -386,11 +381,7 @@ pub fn normalize_param_env_or_error<'tcx>(
|
|||||||
let mut predicates = non_outlives_predicates;
|
let mut predicates = non_outlives_predicates;
|
||||||
predicates.extend(outlives_predicates);
|
predicates.extend(outlives_predicates);
|
||||||
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
|
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
|
||||||
ty::ParamEnv::new(
|
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
|
||||||
tcx.intern_predicates(&predicates),
|
|
||||||
unnormalized_env.reveal(),
|
|
||||||
unnormalized_env.constness(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fully_normalize<'a, 'tcx, T>(
|
pub fn fully_normalize<'a, 'tcx, T>(
|
||||||
@ -573,17 +564,14 @@ fn prepare_vtable_segments<'tcx, T>(
|
|||||||
.predicates
|
.predicates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(move |(pred, _)| {
|
.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 {
|
'diving_in_skip_visited_traits: loop {
|
||||||
if let Some(next_super_trait) = direct_super_traits_iter.next() {
|
if let Some(next_super_trait) = direct_super_traits_iter.next() {
|
||||||
if visited.insert(next_super_trait.to_predicate(tcx)) {
|
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((
|
stack.push((
|
||||||
next_super_trait,
|
next_super_trait.value,
|
||||||
emit_vptr_on_new_entry,
|
emit_vptr_on_new_entry,
|
||||||
Some(direct_super_traits_iter),
|
Some(direct_super_traits_iter),
|
||||||
));
|
));
|
||||||
@ -615,11 +603,7 @@ fn prepare_vtable_segments<'tcx, T>(
|
|||||||
if let Some(siblings) = siblings_opt {
|
if let Some(siblings) = siblings_opt {
|
||||||
if let Some(next_inner_most_trait_ref) = siblings.next() {
|
if let Some(next_inner_most_trait_ref) = siblings.next() {
|
||||||
if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
|
if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
|
||||||
// We're throwing away potential constness of super traits here.
|
*inner_most_trait_ref = next_inner_most_trait_ref.value;
|
||||||
// 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;
|
*emit_vptr = emit_vptr_on_new_entry;
|
||||||
break 'exiting_out;
|
break 'exiting_out;
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,7 +18,7 @@ use rustc_errors::FatalError;
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
|
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_middle::ty::{Predicate, ToPredicate};
|
||||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
@ -698,11 +698,7 @@ fn receiver_is_dispatchable<'tcx>(
|
|||||||
.chain(array::IntoIter::new([unsize_predicate, trait_predicate]))
|
.chain(array::IntoIter::new([unsize_predicate, trait_predicate]))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
ty::ParamEnv::new(
|
ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
|
||||||
tcx.intern_predicates(&caller_bounds),
|
|
||||||
param_env.reveal(),
|
|
||||||
param_env.constness(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Receiver: DispatchFromDyn<Receiver[Self => U]>
|
// Receiver: DispatchFromDyn<Receiver[Self => U]>
|
||||||
|
@ -27,7 +27,7 @@ use rustc_hir::lang_items::LangItem;
|
|||||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
use rustc_middle::ty::subst::Subst;
|
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 rustc_span::symbol::sym;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
@ -11,7 +11,7 @@ use rustc_infer::traits::TraitEngine;
|
|||||||
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
||||||
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
|
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
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 rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
@ -303,7 +303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
} else if lang_items.drop_trait() == Some(def_id)
|
} else if lang_items.drop_trait() == Some(def_id)
|
||||||
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
|
&& 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)?;
|
self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
|
||||||
} else {
|
} else {
|
||||||
debug!("passing ~const Drop bound; in non-const context");
|
debug!("passing ~const Drop bound; in non-const context");
|
||||||
@ -383,19 +383,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
.param_env
|
.param_env
|
||||||
.caller_bounds()
|
.caller_bounds()
|
||||||
.iter()
|
.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.
|
// Micro-optimization: filter out predicates relating to different traits.
|
||||||
let matching_bounds =
|
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.
|
// Keep only those bounds which may apply, and propagate overflow if it occurs.
|
||||||
for bound in matching_bounds {
|
for bound in matching_bounds {
|
||||||
// FIXME(oli-obk): it is suspicious that we are dropping the constness and
|
let wc = self.evaluate_where_clause(stack, bound.value)?;
|
||||||
// polarity here.
|
|
||||||
let wc = self.evaluate_where_clause(stack, bound.map_bound(|t| t.trait_ref))?;
|
|
||||||
if wc.may_apply() {
|
if wc.may_apply() {
|
||||||
candidates.vec.push(ParamCandidate(bound));
|
candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk;
|
|||||||
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
||||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::{self, Ty};
|
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 rustc_span::def_id::DefId;
|
||||||
|
|
||||||
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
|
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
|
||||||
@ -58,9 +58,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParamCandidate(param) => {
|
ParamCandidate(param) => {
|
||||||
let obligations =
|
let obligations = self.confirm_param_candidate(obligation, param.0.value);
|
||||||
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
|
Ok(ImplSource::Param(obligations, param.0.constness))
|
||||||
Ok(ImplSource::Param(obligations, param.skip_binder().constness))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImplCandidate(impl_def_id) => {
|
ImplCandidate(impl_def_id) => {
|
||||||
@ -140,7 +139,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
|
let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
|
||||||
let placeholder_trait_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_self_ty = placeholder_trait_predicate.self_ty();
|
||||||
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
|
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
|
||||||
let (def_id, substs) = match *placeholder_self_ty.kind() {
|
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_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs);
|
||||||
let candidate = candidate_predicate
|
let candidate = candidate_predicate
|
||||||
.to_opt_poly_trait_pred()
|
.to_opt_poly_trait_ref()
|
||||||
.expect("projection candidate is not a trait predicate")
|
.expect("projection candidate is not a trait predicate");
|
||||||
.map_bound(|t| t.trait_ref);
|
|
||||||
let mut obligations = Vec::new();
|
let mut obligations = Vec::new();
|
||||||
let candidate = normalize_with_depth_to(
|
let candidate = normalize_with_depth_to(
|
||||||
self,
|
self,
|
||||||
@ -167,7 +165,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
obligations.extend(self.infcx.commit_if_ok(|_| {
|
obligations.extend(self.infcx.commit_if_ok(|_| {
|
||||||
self.infcx
|
self.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.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(|InferOk { obligations, .. }| obligations)
|
||||||
.map_err(|_| Unimplemented)
|
.map_err(|_| Unimplemented)
|
||||||
})?);
|
})?);
|
||||||
|
@ -39,6 +39,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;
|
||||||
@ -127,6 +128,9 @@ pub struct SelectionContext<'cx, 'tcx> {
|
|||||||
/// and a negative impl
|
/// and a negative impl
|
||||||
allow_negative_impls: bool,
|
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
|
/// The mode that trait queries run in, which informs our error handling
|
||||||
/// policy. In essence, canonicalized queries need their errors propagated
|
/// policy. In essence, canonicalized queries need their errors propagated
|
||||||
/// rather than immediately reported because we do not have accurate spans.
|
/// rather than immediately reported because we do not have accurate spans.
|
||||||
@ -137,9 +141,9 @@ pub struct SelectionContext<'cx, 'tcx> {
|
|||||||
struct TraitObligationStack<'prev, 'tcx> {
|
struct TraitObligationStack<'prev, 'tcx> {
|
||||||
obligation: &'prev TraitObligation<'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.
|
/// 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
|
/// 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
|
||||||
@ -218,6 +222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
intercrate: false,
|
intercrate: false,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
|
is_in_const_context: false,
|
||||||
query_mode: TraitQueryMode::Standard,
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,6 +234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
intercrate: true,
|
intercrate: true,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
|
is_in_const_context: false,
|
||||||
query_mode: TraitQueryMode::Standard,
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,6 +250,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
intercrate: false,
|
intercrate: false,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls,
|
allow_negative_impls,
|
||||||
|
is_in_const_context: false,
|
||||||
query_mode: TraitQueryMode::Standard,
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,10 +266,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
intercrate: false,
|
intercrate: false,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
|
is_in_const_context: false,
|
||||||
query_mode,
|
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
|
/// Enables tracking of intercrate ambiguity causes. These are
|
||||||
/// used in coherence to give improved diagnostics. We don't do
|
/// used in coherence to give improved diagnostics. We don't do
|
||||||
/// this until we detect a coherence error because it can lead to
|
/// this until we detect a coherence error because it can lead to
|
||||||
@ -295,6 +318,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
self.intercrate
|
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
|
// Selection
|
||||||
//
|
//
|
||||||
@ -679,22 +716,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let stack = self.push_stack(previous_stack, &obligation);
|
let stack = self.push_stack(previous_stack, &obligation);
|
||||||
let mut fresh_trait_pred = stack.fresh_trait_pred;
|
let fresh_trait_ref = stack.fresh_trait_ref;
|
||||||
let mut param_env = obligation.param_env;
|
|
||||||
|
|
||||||
fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
|
debug!(?fresh_trait_ref);
|
||||||
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
|
|
||||||
pred
|
|
||||||
});
|
|
||||||
|
|
||||||
debug!(?fresh_trait_pred);
|
if let Some(result) = self.check_evaluation_cache(
|
||||||
|
obligation.param_env,
|
||||||
if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
|
fresh_trait_ref,
|
||||||
|
obligation.polarity(),
|
||||||
|
) {
|
||||||
debug!(?result, "CACHE HIT");
|
debug!(?result, "CACHE HIT");
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
|
if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
|
||||||
debug!(?result, "PROVISIONAL CACHE HIT");
|
debug!(?result, "PROVISIONAL CACHE HIT");
|
||||||
stack.update_reached_depth(result.reached_depth);
|
stack.update_reached_depth(result.reached_depth);
|
||||||
return Ok(result.result);
|
return Ok(result.result);
|
||||||
@ -719,12 +754,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
let reached_depth = stack.reached_depth.get();
|
let reached_depth = stack.reached_depth.get();
|
||||||
if reached_depth >= stack.depth {
|
if reached_depth >= stack.depth {
|
||||||
debug!(?result, "CACHE MISS");
|
debug!(?result, "CACHE MISS");
|
||||||
self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
|
|
||||||
|
|
||||||
stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
|
|
||||||
self.insert_evaluation_cache(
|
self.insert_evaluation_cache(
|
||||||
param_env,
|
obligation.param_env,
|
||||||
fresh_trait_pred,
|
fresh_trait_ref,
|
||||||
|
obligation.polarity(),
|
||||||
|
dep_node,
|
||||||
|
result,
|
||||||
|
);
|
||||||
|
|
||||||
|
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
|
||||||
|
self.insert_evaluation_cache(
|
||||||
|
obligation.param_env,
|
||||||
|
fresh_trait_ref,
|
||||||
|
obligation.polarity(),
|
||||||
dep_node,
|
dep_node,
|
||||||
provisional_result.max(result),
|
provisional_result.max(result),
|
||||||
);
|
);
|
||||||
@ -734,10 +776,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
debug!(
|
debug!(
|
||||||
"caching provisionally because {:?} \
|
"caching provisionally because {:?} \
|
||||||
is a cycle participant (at depth {}, reached depth {})",
|
is a cycle participant (at depth {}, reached depth {})",
|
||||||
fresh_trait_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)
|
Ok(result)
|
||||||
@ -771,7 +813,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
.skip(1) // Skip top-most frame.
|
.skip(1) // Skip top-most frame.
|
||||||
.find(|prev| {
|
.find(|prev| {
|
||||||
stack.obligation.param_env == prev.obligation.param_env
|
stack.obligation.param_env == prev.obligation.param_env
|
||||||
&& stack.fresh_trait_pred == prev.fresh_trait_pred
|
&& stack.fresh_trait_ref == prev.fresh_trait_ref
|
||||||
})
|
})
|
||||||
.map(|stack| stack.depth)
|
.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
|
// 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_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 {
|
if stack.obligation.polarity() != ty::ImplPolarity::Negative {
|
||||||
// This check was an imperfect workaround for a bug in the old
|
// This check was an imperfect workaround for a bug in the old
|
||||||
@ -872,8 +914,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
&& stack.iter().skip(1).any(|prev| {
|
&& stack.iter().skip(1).any(|prev| {
|
||||||
stack.obligation.param_env == prev.obligation.param_env
|
stack.obligation.param_env == prev.obligation.param_env
|
||||||
&& self.match_fresh_trait_refs(
|
&& self.match_fresh_trait_refs(
|
||||||
stack.fresh_trait_pred,
|
stack.fresh_trait_ref,
|
||||||
prev.fresh_trait_pred,
|
prev.fresh_trait_ref,
|
||||||
prev.obligation.param_env,
|
prev.obligation.param_env,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -951,7 +993,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// not just the lifetime choice for this particular (non-erased)
|
// not just the lifetime choice for this particular (non-erased)
|
||||||
// predicate.
|
// predicate.
|
||||||
// See issue #80691
|
// See issue #80691
|
||||||
if stack.fresh_trait_pred.has_erased_regions() {
|
if stack.fresh_trait_ref.has_erased_regions() {
|
||||||
result = result.max(EvaluatedToOkModuloRegions);
|
result = result.max(EvaluatedToOkModuloRegions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,7 +1004,8 @@ 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_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
|
polarity: ty::ImplPolarity,
|
||||||
) -> Option<EvaluationResult> {
|
) -> Option<EvaluationResult> {
|
||||||
// Neither the global nor local cache is aware of intercrate
|
// Neither the global nor local cache is aware of intercrate
|
||||||
// mode, so don't do any caching. In particular, we might
|
// mode, so don't do any caching. In particular, we might
|
||||||
@ -974,17 +1017,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_pred), tcx) {
|
if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
|
||||||
|
{
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx.evaluation_cache.get(¶m_env.and(trait_pred), tcx)
|
self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_evaluation_cache(
|
fn insert_evaluation_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
|
polarity: ty::ImplPolarity,
|
||||||
dep_node: DepNodeIndex,
|
dep_node: DepNodeIndex,
|
||||||
result: EvaluationResult,
|
result: EvaluationResult,
|
||||||
) {
|
) {
|
||||||
@ -1003,19 +1048,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if !trait_pred.needs_infer() {
|
if !trait_ref.needs_infer() {
|
||||||
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
|
debug!(?trait_ref, ?result, "insert_evaluation_cache global");
|
||||||
// This may overwrite the cache with the same value
|
// This may overwrite the cache with the same value
|
||||||
// FIXME: Due to #50507 this overwrites the different values
|
// FIXME: Due to #50507 this overwrites the different values
|
||||||
// This should be changed to use HashMapExt::insert_same
|
// This should be changed to use HashMapExt::insert_same
|
||||||
// when that is fixed
|
// when that is fixed
|
||||||
self.tcx().evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
|
self.tcx().evaluation_cache.insert(
|
||||||
|
(param_env.and(trait_ref), polarity),
|
||||||
|
dep_node,
|
||||||
|
result,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(?trait_pred, ?result, "insert_evaluation_cache");
|
debug!(?trait_ref, ?result, "insert_evaluation_cache");
|
||||||
self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
|
self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For various reasons, it's possible for a subobligation
|
/// For various reasons, it's possible for a subobligation
|
||||||
@ -1093,15 +1142,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
for candidate in candidates {
|
for candidate in candidates {
|
||||||
// Respect const trait obligations
|
// Respect const trait obligations
|
||||||
if obligation.is_const() {
|
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
|
||||||
match candidate {
|
match candidate {
|
||||||
// const impl
|
// const impl
|
||||||
ImplCandidate(def_id)
|
ImplCandidate(def_id)
|
||||||
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
||||||
// const param
|
// const param
|
||||||
ParamCandidate(trait_pred)
|
ParamCandidate((
|
||||||
if trait_pred.skip_binder().constness
|
ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
|
||||||
== ty::BoundConstness::ConstIfConst => {}
|
_,
|
||||||
|
)) => {}
|
||||||
// auto trait impl
|
// auto trait impl
|
||||||
AutoImplCandidate(..) => {}
|
AutoImplCandidate(..) => {}
|
||||||
// generator, this will raise error in other places
|
// generator, this will raise error in other places
|
||||||
@ -1210,7 +1260,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
fn check_candidate_cache(
|
fn check_candidate_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'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>>> {
|
||||||
// Neither the global nor local cache is aware of intercrate
|
// Neither the global nor local cache is aware of intercrate
|
||||||
@ -1221,15 +1271,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let mut pred = cache_fresh_trait_pred.skip_binder();
|
let pred = &cache_fresh_trait_pred.skip_binder();
|
||||||
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
|
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(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);
|
return Some(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx.selection_cache.get(¶m_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
|
/// Determines whether can we safely cache the result
|
||||||
@ -1267,36 +1321,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
fn insert_candidate_cache(
|
fn insert_candidate_cache(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
dep_node: DepNodeIndex,
|
dep_node: DepNodeIndex,
|
||||||
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let mut pred = cache_fresh_trait_pred.skip_binder();
|
let pred = cache_fresh_trait_pred.skip_binder();
|
||||||
|
let trait_ref = pred.trait_ref;
|
||||||
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
|
|
||||||
|
|
||||||
if !self.can_cache_candidate(&candidate) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
if let Err(Overflow) = candidate {
|
if let Err(Overflow) = candidate {
|
||||||
// Don't cache overflow globally; we only produce this in certain modes.
|
// 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() {
|
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.
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(?pred, ?candidate, "insert_candidate_cache local");
|
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
|
||||||
self.infcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
|
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.
|
/// 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
|
// Check if a bound would previously have been removed when normalizing
|
||||||
// the param_env so that it can be given the lowest priority. See
|
// the param_env so that it can be given the lowest priority. See
|
||||||
// #50825 for the motivation for this.
|
// #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()
|
cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1520,22 +1581,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
| ConstDropCandidate,
|
| ConstDropCandidate,
|
||||||
) => false,
|
) => false,
|
||||||
|
|
||||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
(
|
||||||
let same_except_bound_vars = other.skip_binder().trait_ref
|
ParamCandidate((other, other_polarity)),
|
||||||
== victim.skip_binder().trait_ref
|
ParamCandidate((victim, victim_polarity)),
|
||||||
&& other.skip_binder().constness == victim.skip_binder().constness
|
) => {
|
||||||
&& other.skip_binder().polarity == victim.skip_binder().polarity
|
let same_except_bound_vars = other.value.skip_binder()
|
||||||
&& !other.skip_binder().trait_ref.has_escaping_bound_vars();
|
== 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 {
|
if same_except_bound_vars {
|
||||||
// See issue #84398. In short, we can generate multiple ParamCandidates which are
|
// 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
|
// 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
|
// 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
|
// 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.
|
// best to *not* create essentially duplicate candidates in the first place.
|
||||||
other.bound_vars().len() <= victim.bound_vars().len()
|
other.value.bound_vars().len() <= victim.value.bound_vars().len()
|
||||||
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
|
} else if other.value == victim.value
|
||||||
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
|
&& victim.constness == ty::BoundConstness::NotConst
|
||||||
&& other.skip_binder().polarity == victim.skip_binder().polarity
|
&& other_polarity == victim_polarity
|
||||||
{
|
{
|
||||||
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
||||||
true
|
true
|
||||||
@ -1565,11 +1629,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
| TraitAliasCandidate(..)
|
| TraitAliasCandidate(..)
|
||||||
| ObjectCandidate(_)
|
| ObjectCandidate(_)
|
||||||
| ProjectionCandidate(_),
|
| ProjectionCandidate(_),
|
||||||
) => !is_global(cand),
|
) => !is_global(&cand.0.value),
|
||||||
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
|
||||||
// Prefer these to a global where-clause bound
|
// Prefer these to a global where-clause bound
|
||||||
// (see issue #50825).
|
// (see issue #50825).
|
||||||
is_global(cand)
|
is_global(&cand.0.value)
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
@ -1585,7 +1649,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
) => {
|
) => {
|
||||||
// Prefer these to a global where-clause bound
|
// Prefer these to a global where-clause bound
|
||||||
// (see issue #50825).
|
// (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))
|
(ProjectionCandidate(i), ProjectionCandidate(j))
|
||||||
@ -2145,8 +2209,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
fn match_fresh_trait_refs(
|
fn match_fresh_trait_refs(
|
||||||
&self,
|
&self,
|
||||||
previous: ty::PolyTraitPredicate<'tcx>,
|
previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
current: ty::PolyTraitPredicate<'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);
|
||||||
@ -2158,13 +2222,17 @@ 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_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 dfn = previous_stack.cache.next_dfn();
|
||||||
let depth = previous_stack.depth() + 1;
|
let depth = previous_stack.depth() + 1;
|
||||||
TraitObligationStack {
|
TraitObligationStack {
|
||||||
obligation,
|
obligation,
|
||||||
fresh_trait_pred,
|
fresh_trait_ref,
|
||||||
reached_depth: Cell::new(depth),
|
reached_depth: Cell::new(depth),
|
||||||
previous: previous_stack,
|
previous: previous_stack,
|
||||||
dfn,
|
dfn,
|
||||||
@ -2358,7 +2426,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
|
|||||||
debug!(reached_depth, "update_reached_depth");
|
debug!(reached_depth, "update_reached_depth");
|
||||||
let mut p = self;
|
let mut p = self;
|
||||||
while reached_depth < p.depth {
|
while reached_depth < p.depth {
|
||||||
debug!(?p.fresh_trait_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.reached_depth.set(p.reached_depth.get().min(reached_depth));
|
||||||
p = p.previous.head.unwrap();
|
p = p.previous.head.unwrap();
|
||||||
}
|
}
|
||||||
@ -2437,7 +2505,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::PolyTraitPredicate<'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
|
||||||
@ -2469,28 +2537,28 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
|
|||||||
/// `reached_depth` (from the returned value).
|
/// `reached_depth` (from the returned value).
|
||||||
fn get_provisional(
|
fn get_provisional(
|
||||||
&self,
|
&self,
|
||||||
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
) -> Option<ProvisionalEvaluation> {
|
) -> Option<ProvisionalEvaluation> {
|
||||||
debug!(
|
debug!(
|
||||||
?fresh_trait_pred,
|
?fresh_trait_ref,
|
||||||
"get_provisional = {:#?}",
|
"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
|
/// Insert a provisional result into the cache. The result came
|
||||||
/// from the node with the given DFN. It accessed a minimum depth
|
/// from the node with the given DFN. It accessed a minimum depth
|
||||||
/// of `reached_depth` to compute. It evaluated `fresh_trait_pred`
|
/// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
|
||||||
/// and resulted in `result`.
|
/// and resulted in `result`.
|
||||||
fn insert_provisional(
|
fn insert_provisional(
|
||||||
&self,
|
&self,
|
||||||
from_dfn: usize,
|
from_dfn: usize,
|
||||||
reached_depth: usize,
|
reached_depth: usize,
|
||||||
fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
|
||||||
result: EvaluationResult,
|
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();
|
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
|
/// Invoked when the node with dfn `dfn` does not get a successful
|
||||||
@ -2565,16 +2633,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
|
|||||||
fn on_completion(
|
fn on_completion(
|
||||||
&self,
|
&self,
|
||||||
dfn: usize,
|
dfn: usize,
|
||||||
mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
|
mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
|
||||||
) {
|
) {
|
||||||
debug!(?dfn, "on_completion");
|
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)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
|
||||||
|
|
||||||
for (p, _) in predicates {
|
for (p, _) in predicates {
|
||||||
if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
|
if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
|
||||||
if Some(poly_trait_ref.def_id()) == sized_trait {
|
if Some(poly_trait_ref.value.def_id()) == sized_trait {
|
||||||
types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
|
types_without_default_bounds.remove(poly_trait_ref.value.self_ty().skip_binder());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use smallvec::SmallVec;
|
|||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
|
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};
|
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
|
||||||
pub use rustc_infer::traits::{self, util::*};
|
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)| {
|
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
|
||||||
pred.subst_supertrait(tcx, &trait_ref)
|
pred.subst_supertrait(tcx, &trait_ref)
|
||||||
.to_opt_poly_trait_pred()
|
.to_opt_poly_trait_ref()
|
||||||
.map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
|
.map(|trait_ref| item.clone_and_push(trait_ref.value, *span))
|
||||||
});
|
});
|
||||||
debug!("expand_trait_aliases: items={:?}", items.clone());
|
debug!("expand_trait_aliases: items={:?}", items.clone());
|
||||||
|
|
||||||
@ -183,8 +183,8 @@ impl Iterator for SupertraitDefIds<'tcx> {
|
|||||||
predicates
|
predicates
|
||||||
.predicates
|
.predicates
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(pred, _)| pred.to_opt_poly_trait_pred())
|
.filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
|
||||||
.map(|trait_ref| trait_ref.def_id())
|
.map(|trait_ref| trait_ref.value.def_id())
|
||||||
.filter(|&super_def_id| visited.insert(super_def_id)),
|
.filter(|&super_def_id| visited.insert(super_def_id)),
|
||||||
);
|
);
|
||||||
Some(def_id)
|
Some(def_id)
|
||||||
|
@ -6,7 +6,7 @@ use rustc_hir as hir;
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
|
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 rustc_span::Span;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
@ -298,10 +298,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||||||
|
|
||||||
let extend = |obligation: traits::PredicateObligation<'tcx>| {
|
let extend = |obligation: traits::PredicateObligation<'tcx>| {
|
||||||
let mut cause = cause.clone();
|
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 {
|
let derived_cause = traits::DerivedObligationCause {
|
||||||
// FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
|
parent_trait_ref: parent_trait_ref.value,
|
||||||
parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
|
|
||||||
parent_code: Lrc::new(obligation.cause.code.clone()),
|
parent_code: Lrc::new(obligation.cause.code.clone()),
|
||||||
};
|
};
|
||||||
cause.make_mut().code =
|
cause.make_mut().code =
|
||||||
|
@ -2,7 +2,9 @@ use rustc_data_structures::fx::FxIndexSet;
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::Subst;
|
||||||
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
|
use rustc_middle::ty::{
|
||||||
|
self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
|
||||||
|
};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
@ -280,77 +282,14 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
|||||||
// issue #89334
|
// issue #89334
|
||||||
predicates = tcx.expose_default_const_substs(predicates);
|
predicates = tcx.expose_default_const_substs(predicates);
|
||||||
|
|
||||||
let local_did = def_id.as_local();
|
let unnormalized_env =
|
||||||
let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
|
ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
|
||||||
|
|
||||||
let constness = match hir_id {
|
debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds());
|
||||||
Some(hir_id) => match tcx.hir().get(hir_id) {
|
let body_id = def_id
|
||||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
|
.as_local()
|
||||||
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
|
.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
|
||||||
| hir::Node::TraitItem(hir::TraitItem {
|
.map_or(hir::CRATE_HIR_ID, |id| {
|
||||||
kind: hir::TraitItemKind::Const(..), ..
|
|
||||||
})
|
|
||||||
| hir::Node::AnonConst(_)
|
|
||||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
|
|
||||||
| hir::Node::ImplItem(hir::ImplItem {
|
|
||||||
kind:
|
|
||||||
hir::ImplItemKind::Fn(
|
|
||||||
hir::FnSig {
|
|
||||||
header: hir::FnHeader { constness: hir::Constness::Const, .. },
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..,
|
|
||||||
),
|
|
||||||
..
|
|
||||||
}) => hir::Constness::Const,
|
|
||||||
|
|
||||||
hir::Node::ImplItem(hir::ImplItem {
|
|
||||||
kind: hir::ImplItemKind::TyAlias(..) | hir::ImplItemKind::Fn(..),
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
let parent_hir_id = tcx.hir().get_parent_node(hir_id);
|
|
||||||
match tcx.hir().get(parent_hir_id) {
|
|
||||||
hir::Node::Item(hir::Item {
|
|
||||||
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
|
|
||||||
..
|
|
||||||
}) => *constness,
|
|
||||||
_ => span_bug!(
|
|
||||||
tcx.def_span(parent_hir_id.owner),
|
|
||||||
"impl item's parent node is not an impl",
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::Node::Item(hir::Item {
|
|
||||||
kind:
|
|
||||||
hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
| hir::Node::TraitItem(hir::TraitItem {
|
|
||||||
kind:
|
|
||||||
hir::TraitItemKind::Fn(
|
|
||||||
hir::FnSig { header: hir::FnHeader { constness, .. }, .. },
|
|
||||||
..,
|
|
||||||
),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
| hir::Node::Item(hir::Item {
|
|
||||||
kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
|
|
||||||
..
|
|
||||||
}) => *constness,
|
|
||||||
|
|
||||||
_ => hir::Constness::NotConst,
|
|
||||||
},
|
|
||||||
None => hir::Constness::NotConst,
|
|
||||||
};
|
|
||||||
|
|
||||||
let unnormalized_env = ty::ParamEnv::new(
|
|
||||||
tcx.intern_predicates(&predicates),
|
|
||||||
traits::Reveal::UserFacing,
|
|
||||||
constness,
|
|
||||||
);
|
|
||||||
|
|
||||||
let body_id = hir_id.map_or(hir::CRATE_HIR_ID, |id| {
|
|
||||||
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
|
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
|
||||||
});
|
});
|
||||||
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
|
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
|
||||||
|
@ -1588,7 +1588,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
traits::transitive_bounds_that_define_assoc_type(
|
traits::transitive_bounds_that_define_assoc_type(
|
||||||
tcx,
|
tcx,
|
||||||
predicates.iter().filter_map(|(p, _)| {
|
predicates.iter().filter_map(|(p, _)| {
|
||||||
Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
|
p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value)
|
||||||
}),
|
}),
|
||||||
assoc_name,
|
assoc_name,
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Bounds are restrictions applied to some types after they've been converted into the
|
//! Bounds are restrictions applied to some types after they've been converted into the
|
||||||
//! `ty` form from the HIR.
|
//! `ty` form from the HIR.
|
||||||
|
|
||||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
/// Collects together a list of type bounds. These lists of bounds occur in many places
|
/// Collects together a list of type bounds. These lists of bounds occur in many places
|
||||||
|
@ -208,11 +208,8 @@ fn compare_predicate_entailment<'tcx>(
|
|||||||
// The key step here is to update the caller_bounds's predicates to be
|
// The key step here is to update the caller_bounds's predicates to be
|
||||||
// the new hybrid bounds we computed.
|
// the new hybrid bounds we computed.
|
||||||
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
|
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
|
||||||
let param_env = ty::ParamEnv::new(
|
let param_env =
|
||||||
tcx.intern_predicates(&hybrid_preds.predicates),
|
ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
|
||||||
Reveal::UserFacing,
|
|
||||||
hir::Constness::NotConst,
|
|
||||||
);
|
|
||||||
let param_env =
|
let param_env =
|
||||||
traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause);
|
traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause);
|
||||||
|
|
||||||
@ -1168,11 +1165,8 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||||||
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
|
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
|
||||||
|
|
||||||
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
|
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
|
||||||
let param_env = ty::ParamEnv::new(
|
let param_env =
|
||||||
tcx.intern_predicates(&hybrid_preds.predicates),
|
ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
|
||||||
Reveal::UserFacing,
|
|
||||||
hir::Constness::NotConst,
|
|
||||||
);
|
|
||||||
let param_env = traits::normalize_param_env_or_error(
|
let param_env = traits::normalize_param_env_or_error(
|
||||||
tcx,
|
tcx,
|
||||||
impl_ty.def_id,
|
impl_ty.def_id,
|
||||||
@ -1357,11 +1351,7 @@ pub fn check_type_bounds<'tcx>(
|
|||||||
.to_predicate(tcx),
|
.to_predicate(tcx),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
ty::ParamEnv::new(
|
ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
|
||||||
tcx.intern_predicates(&predicates),
|
|
||||||
Reveal::UserFacing,
|
|
||||||
param_env.constness(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
debug!(?normalize_param_env);
|
debug!(?normalize_param_env);
|
||||||
|
|
||||||
@ -1370,7 +1360,13 @@ pub fn check_type_bounds<'tcx>(
|
|||||||
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
|
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
|
||||||
|
|
||||||
tcx.infer_ctxt().enter(move |infcx| {
|
tcx.infer_ctxt().enter(move |infcx| {
|
||||||
let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
|
let constness = impl_ty
|
||||||
|
.container
|
||||||
|
.impl_def_id()
|
||||||
|
.map(|did| tcx.impl_constness(did))
|
||||||
|
.unwrap_or(hir::Constness::NotConst);
|
||||||
|
|
||||||
|
let inh = Inherited::with_constness(infcx, impl_ty.def_id.expect_local(), constness);
|
||||||
let infcx = &inh.infcx;
|
let infcx = &inh.infcx;
|
||||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||||
|
|
||||||
@ -1414,7 +1410,8 @@ pub fn check_type_bounds<'tcx>(
|
|||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
// version.
|
// version.
|
||||||
let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
|
let errors =
|
||||||
|
inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.report_fulfillment_errors(&errors, None, false);
|
infcx.report_fulfillment_errors(&errors, None, false);
|
||||||
return Err(ErrorReported);
|
return Err(ErrorReported);
|
||||||
|
@ -616,7 +616,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
pub(in super::super) fn select_all_obligations_or_error(&self) {
|
pub(in super::super) fn select_all_obligations_or_error(&self) {
|
||||||
let errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self);
|
let errors = self
|
||||||
|
.fulfillment_cx
|
||||||
|
.borrow_mut()
|
||||||
|
.select_all_with_constness_or_error(&self, self.inh.constness);
|
||||||
|
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
|
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
|
||||||
@ -629,7 +632,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fallback_has_occurred: bool,
|
fallback_has_occurred: bool,
|
||||||
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
|
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
|
||||||
) {
|
) {
|
||||||
let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
|
let mut result = self
|
||||||
|
.fulfillment_cx
|
||||||
|
.borrow_mut()
|
||||||
|
.select_with_constness_where_possible(self, self.inh.constness);
|
||||||
if !result.is_empty() {
|
if !result.is_empty() {
|
||||||
mutate_fulfillment_errors(&mut result);
|
mutate_fulfillment_errors(&mut result);
|
||||||
self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
|
self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
|
||||||
|
@ -53,6 +53,9 @@ pub struct Inherited<'a, 'tcx> {
|
|||||||
pub(super) deferred_generator_interiors:
|
pub(super) deferred_generator_interiors:
|
||||||
RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
|
RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
|
||||||
|
|
||||||
|
/// Reports whether this is in a const context.
|
||||||
|
pub(super) constness: hir::Constness,
|
||||||
|
|
||||||
pub(super) body_id: Option<hir::BodyId>,
|
pub(super) body_id: Option<hir::BodyId>,
|
||||||
|
|
||||||
/// Whenever we introduce an adjustment from `!` into a type variable,
|
/// Whenever we introduce an adjustment from `!` into a type variable,
|
||||||
@ -99,6 +102,16 @@ impl<'tcx> InheritedBuilder<'tcx> {
|
|||||||
|
|
||||||
impl Inherited<'a, 'tcx> {
|
impl Inherited<'a, 'tcx> {
|
||||||
pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
|
pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
|
||||||
|
let tcx = infcx.tcx;
|
||||||
|
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
|
Self::with_constness(infcx, def_id, tcx.hir().get(item_id).constness_for_typeck())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn with_constness(
|
||||||
|
infcx: InferCtxt<'a, 'tcx>,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
constness: hir::Constness,
|
||||||
|
) -> Self {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
let body_id = tcx.hir().maybe_body_owned_by(item_id);
|
let body_id = tcx.hir().maybe_body_owned_by(item_id);
|
||||||
@ -115,6 +128,7 @@ impl Inherited<'a, 'tcx> {
|
|||||||
deferred_cast_checks: RefCell::new(Vec::new()),
|
deferred_cast_checks: RefCell::new(Vec::new()),
|
||||||
deferred_generator_interiors: RefCell::new(Vec::new()),
|
deferred_generator_interiors: RefCell::new(Vec::new()),
|
||||||
diverging_type_vars: RefCell::new(Default::default()),
|
diverging_type_vars: RefCell::new(Default::default()),
|
||||||
|
constness,
|
||||||
body_id,
|
body_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use rustc_infer::infer::{self, InferOk};
|
|||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::Subst;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
|
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
|
|||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
|
use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
|
||||||
|
@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath};
|
|||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_middle::ty::fast_reject::simplify_type;
|
use rustc_middle::ty::fast_reject::simplify_type;
|
||||||
use rustc_middle::ty::print::with_crate_prefix;
|
use rustc_middle::ty::print::with_crate_prefix;
|
||||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||||
use rustc_span::lev_distance;
|
use rustc_span::lev_distance;
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
|
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
|
||||||
|
@ -21,6 +21,7 @@ use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
|
|||||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
|
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
|
||||||
|
WithConstness,
|
||||||
};
|
};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
|
@ -41,7 +41,7 @@ use rustc_middle::ty::subst::InternalSubsts;
|
|||||||
use rustc_middle::ty::util::Discr;
|
use rustc_middle::ty::util::Discr;
|
||||||
use rustc_middle::ty::util::IntTypeExt;
|
use rustc_middle::ty::util::IntTypeExt;
|
||||||
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
|
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{ReprOptions, ToPredicate};
|
use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
|
@ -3,7 +3,7 @@ use rustc_hir as hir;
|
|||||||
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
|
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
|
||||||
use rustc_infer::traits;
|
use rustc_infer::traits;
|
||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::Subst;
|
||||||
use rustc_middle::ty::ToPredicate;
|
use rustc_middle::ty::{ToPredicate, WithConstness};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -66,8 +66,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(Some(
|
.chain(Some(
|
||||||
ty::Binder::dummy(trait_ref)
|
ty::Binder::dummy(trait_ref)
|
||||||
.to_poly_trait_predicate()
|
.without_const()
|
||||||
.map_bound(ty::PredicateKind::Trait)
|
|
||||||
.to_predicate(infcx.tcx),
|
.to_predicate(infcx.tcx),
|
||||||
));
|
));
|
||||||
for predicate in predicates {
|
for predicate in predicates {
|
||||||
|
@ -19,7 +19,7 @@ LL | struct Take(Take);
|
|||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: ...which immediately requires computing drop-check constraints for `Take` again
|
= note: ...which immediately requires computing drop-check constraints for `Take` again
|
||||||
= note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Take } }`
|
= note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil }
|
|||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: ...which immediately requires computing drop-check constraints for `MList` again
|
= note: ...which immediately requires computing drop-check constraints for `MList` again
|
||||||
= note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: MList } }`
|
= note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// FIXME(fee1-dead): this should have a better error message
|
// FIXME(fee1-dead): this should have a better error message
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
struct NonConstAdd(i32);
|
struct NonConstAdd(i32);
|
||||||
|
|
||||||
impl std::ops::Add for NonConstAdd {
|
impl std::ops::Add for NonConstAdd {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
|
error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
|
||||||
--> $DIR/assoc-type.rs:18:5
|
--> $DIR/assoc-type.rs:19:5
|
||||||
|
|
|
|
||||||
LL | type Bar = NonConstAdd;
|
LL | type Bar = NonConstAdd;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
|
||||||
|
|
|
|
||||||
= help: the trait `Add` is not implemented for `NonConstAdd`
|
= help: the trait `Add` is not implemented for `NonConstAdd`
|
||||||
note: required by a bound in `Foo::Bar`
|
note: required by a bound in `Foo::Bar`
|
||||||
--> $DIR/assoc-type.rs:14:15
|
--> $DIR/assoc-type.rs:15:15
|
||||||
|
|
|
|
||||||
LL | type Bar: ~const std::ops::Add;
|
LL | type Bar: ~const std::ops::Add;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
|
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
|
||||||
|
@ -67,8 +67,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
|||||||
let mut is_future = false;
|
let mut is_future = false;
|
||||||
for &(p, _span) in preds {
|
for &(p, _span) in preds {
|
||||||
let p = p.subst(cx.tcx, subst);
|
let p = p.subst(cx.tcx, subst);
|
||||||
if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
|
if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
|
||||||
if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
|
if Some(trait_ref.value.def_id()) == cx.tcx.lang_items().future_trait() {
|
||||||
is_future = true;
|
is_future = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user