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

Eliminate ConstnessAnd again

Closes #91489.
Closes #89432.

Reverts #91491.
Reverts #89450.

r? `@spastorino`
This commit is contained in:
bors 2021-12-12 22:15:32 +00:00
commit 22f8bde876
69 changed files with 622 additions and 458 deletions

View file

@ -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, WithConstness, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
}; };
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};

View file

@ -7,6 +7,7 @@ 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;
@ -215,6 +216,7 @@ 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;
@ -249,6 +251,7 @@ 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

View file

@ -929,6 +929,7 @@ 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)
} }

View file

@ -817,8 +817,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
); );
let implsrc = tcx.infer_ctxt().enter(|infcx| { let implsrc = tcx.infer_ctxt().enter(|infcx| {
let mut selcx = let mut selcx = SelectionContext::new(&infcx);
SelectionContext::with_constness(&infcx, hir::Constness::Const);
selcx.select(&obligation) selcx.select(&obligation)
}); });

View file

@ -3,7 +3,6 @@
//! 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};
@ -167,7 +166,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::with_constness(&infcx, hir::Constness::Const); let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation) selcx.select(&obligation)
}); });
!matches!( !matches!(

View file

@ -94,9 +94,11 @@ where
// SAFETY: pointer_raw returns the original pointer // SAFETY: pointer_raw returns the original pointer
unsafe { std::mem::transmute_copy(&self.pointer_raw()) } unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
} }
#[inline]
pub fn tag(&self) -> T { pub fn tag(&self) -> T {
unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) } unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) }
} }
#[inline]
pub fn set_tag(&mut self, tag: T) { pub fn set_tag(&mut self, tag: T) {
let mut packed = self.packed.get(); let mut packed = self.packed.get();
let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT; let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT;

View file

@ -3208,31 +3208,6 @@ 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)),

View file

@ -1,9 +1,8 @@
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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty};
use super::FulfillmentError; use super::FulfillmentError;
use super::{ObligationCause, PredicateObligation}; use super::{ObligationCause, PredicateObligation};
@ -48,26 +47,9 @@ 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>;

View file

@ -69,6 +69,16 @@ 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);

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, TyCtxt};
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_ref() { if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
stack.push(binder.value); stack.push(binder.map_bound(|t| t.trait_ref));
} }
} }
@ -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_ref() { if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() {
return Some(data.value); return Some(data.map_bound(|t| t.trait_ref));
} }
} }
None None

View file

@ -58,6 +58,9 @@ enum QueryModifier {
/// Use a separate query provider for local and extern crates /// Use a separate query provider for local and extern crates
SeparateProvideExtern(Ident), SeparateProvideExtern(Ident),
/// Always remap the ParamEnv's constness before hashing and passing to the query provider
RemapEnvConstness(Ident),
} }
impl Parse for QueryModifier { impl Parse for QueryModifier {
@ -123,6 +126,8 @@ impl Parse for QueryModifier {
Ok(QueryModifier::EvalAlways(modifier)) Ok(QueryModifier::EvalAlways(modifier))
} else if modifier == "separate_provide_extern" { } else if modifier == "separate_provide_extern" {
Ok(QueryModifier::SeparateProvideExtern(modifier)) Ok(QueryModifier::SeparateProvideExtern(modifier))
} else if modifier == "remap_env_constness" {
Ok(QueryModifier::RemapEnvConstness(modifier))
} else { } else {
Err(Error::new(modifier.span(), "unknown query modifier")) Err(Error::new(modifier.span(), "unknown query modifier"))
} }
@ -222,6 +227,9 @@ struct QueryModifiers {
/// Use a separate query provider for local and extern crates /// Use a separate query provider for local and extern crates
separate_provide_extern: Option<Ident>, separate_provide_extern: Option<Ident>,
/// Always remap the ParamEnv's constness before hashing.
remap_env_constness: Option<Ident>,
} }
/// Process query modifiers into a struct, erroring on duplicates /// Process query modifiers into a struct, erroring on duplicates
@ -236,6 +244,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
let mut anon = None; let mut anon = None;
let mut eval_always = None; let mut eval_always = None;
let mut separate_provide_extern = None; let mut separate_provide_extern = None;
let mut remap_env_constness = None;
for modifier in query.modifiers.0.drain(..) { for modifier in query.modifiers.0.drain(..) {
match modifier { match modifier {
QueryModifier::LoadCached(tcx, id, block) => { QueryModifier::LoadCached(tcx, id, block) => {
@ -335,6 +344,12 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
} }
separate_provide_extern = Some(ident); separate_provide_extern = Some(ident);
} }
QueryModifier::RemapEnvConstness(ident) => {
if remap_env_constness.is_some() {
panic!("duplicate modifier `remap_env_constness` for query `{}`", query.name);
}
remap_env_constness = Some(ident)
}
} }
} }
let desc = desc.unwrap_or_else(|| { let desc = desc.unwrap_or_else(|| {
@ -351,6 +366,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
anon, anon,
eval_always, eval_always,
separate_provide_extern, separate_provide_extern,
remap_env_constness,
} }
} }
@ -485,6 +501,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
if let Some(separate_provide_extern) = &modifiers.separate_provide_extern { if let Some(separate_provide_extern) = &modifiers.separate_provide_extern {
attributes.push(quote! { (#separate_provide_extern) }); attributes.push(quote! { (#separate_provide_extern) });
} }
// Pass on the remap_env_constness modifier
if let Some(remap_env_constness) = &modifiers.remap_env_constness {
attributes.push(quote! { (#remap_env_constness) });
}
// This uses the span of the query definition for the commas, // This uses the span of the query definition for the commas,
// which can be important if we later encounter any ambiguity // which can be important if we later encounter any ambiguity

View file

@ -474,7 +474,8 @@ 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) {

View file

@ -246,6 +246,14 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
} }
} }
impl<'tcx, R> Canonical<'tcx, ty::ParamEnvAnd<'tcx, R>> {
#[inline]
pub fn without_const(mut self) -> Self {
self.value = self.value.without_const();
self
}
}
impl<'tcx, V> Canonical<'tcx, V> { impl<'tcx, V> Canonical<'tcx, V> {
/// Allows you to map the `value` of a canonical while keeping the /// Allows you to map the `value` of a canonical while keeping the
/// same set of bound variables. /// same set of bound variables.

View file

@ -64,6 +64,7 @@ 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));
@ -92,6 +93,7 @@ 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())

View file

@ -880,6 +880,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>> key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>>
) -> Option<ty::ValTree<'tcx>> { ) -> Option<ty::ValTree<'tcx>> {
desc { "destructure constant" } desc { "destructure constant" }
remap_env_constness
} }
/// Destructure a constant ADT or array into its variant index and its /// Destructure a constant ADT or array into its variant index and its
@ -888,6 +889,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
) -> mir::DestructuredConst<'tcx> { ) -> mir::DestructuredConst<'tcx> {
desc { "destructure constant" } desc { "destructure constant" }
remap_env_constness
} }
/// Dereference a constant reference or raw pointer and turn the result into a constant /// Dereference a constant reference or raw pointer and turn the result into a constant
@ -896,6 +898,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
) -> &'tcx ty::Const<'tcx> { ) -> &'tcx ty::Const<'tcx> {
desc { "deref constant" } desc { "deref constant" }
remap_env_constness
} }
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
@ -1100,26 +1103,32 @@ rustc_queries! {
/// `ty.is_copy()`, etc, since that will prune the environment where possible. /// `ty.is_copy()`, etc, since that will prune the environment where possible.
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Copy`", env.value } desc { "computing whether `{}` is `Copy`", env.value }
remap_env_constness
} }
/// Query backing `TyS::is_sized`. /// Query backing `TyS::is_sized`.
query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Sized`", env.value } desc { "computing whether `{}` is `Sized`", env.value }
remap_env_constness
} }
/// Query backing `TyS::is_freeze`. /// Query backing `TyS::is_freeze`.
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is freeze", env.value } desc { "computing whether `{}` is freeze", env.value }
remap_env_constness
} }
/// Query backing `TyS::is_unpin`. /// Query backing `TyS::is_unpin`.
query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Unpin`", env.value } desc { "computing whether `{}` is `Unpin`", env.value }
remap_env_constness
} }
/// Query backing `TyS::needs_drop`. /// Query backing `TyS::needs_drop`.
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` needs drop", env.value } desc { "computing whether `{}` needs drop", env.value }
remap_env_constness
} }
/// Query backing `TyS::has_significant_drop_raw`. /// Query backing `TyS::has_significant_drop_raw`.
query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` has a significant drop", env.value } desc { "computing whether `{}` has a significant drop", env.value }
remap_env_constness
} }
/// Query backing `TyS::is_structural_eq_shallow`. /// Query backing `TyS::is_structural_eq_shallow`.
@ -1158,6 +1167,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> { ) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
desc { "computing layout of `{}`", key.value } desc { "computing layout of `{}`", key.value }
remap_env_constness
} }
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
@ -1168,6 +1178,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)> key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}` function pointers", key.value.0 } desc { "computing call ABI of `{}` function pointers", key.value.0 }
remap_env_constness
} }
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
@ -1179,6 +1190,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)> key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}`", key.value.0 } desc { "computing call ABI of `{}`", key.value.0 }
remap_env_constness
} }
query dylib_dependency_formats(_: CrateNum) query dylib_dependency_formats(_: CrateNum)
@ -1463,6 +1475,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
) -> ty::inhabitedness::DefIdForest { ) -> ty::inhabitedness::DefIdForest {
desc { "computing the inhabitedness of `{:?}`", key } desc { "computing the inhabitedness of `{:?}`", key }
remap_env_constness
} }
query dep_kind(_: CrateNum) -> CrateDepKind { query dep_kind(_: CrateNum) -> CrateDepKind {
@ -1642,6 +1655,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "normalizing `{:?}`", goal } desc { "normalizing `{:?}`", goal }
remap_env_constness
} }
// FIXME: Implement `normalize_generic_arg_after_erasing_regions` and // FIXME: Implement `normalize_generic_arg_after_erasing_regions` and
@ -1654,6 +1668,7 @@ rustc_queries! {
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
) -> GenericArg<'tcx> { ) -> GenericArg<'tcx> {
desc { "normalizing `{}`", goal.value } desc { "normalizing `{}`", goal.value }
remap_env_constness
} }
/// Do not call this query directly: invoke `normalize_erasing_regions` instead. /// Do not call this query directly: invoke `normalize_erasing_regions` instead.
@ -1661,6 +1676,7 @@ rustc_queries! {
goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> { ) -> mir::ConstantKind<'tcx> {
desc { "normalizing `{}`", goal.value } desc { "normalizing `{}`", goal.value }
remap_env_constness
} }
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead. /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
@ -1668,6 +1684,7 @@ rustc_queries! {
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
) -> Result<GenericArg<'tcx>, NoSolution> { ) -> Result<GenericArg<'tcx>, NoSolution> {
desc { "normalizing `{}`", goal.value } desc { "normalizing `{}`", goal.value }
remap_env_constness
} }
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead. /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
@ -1675,6 +1692,7 @@ rustc_queries! {
goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> Result<mir::ConstantKind<'tcx>, NoSolution> { ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
desc { "normalizing `{}`", goal.value } desc { "normalizing `{}`", goal.value }
remap_env_constness
} }
query implied_outlives_bounds( query implied_outlives_bounds(
@ -1684,6 +1702,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "computing implied outlives bounds for `{:?}`", goal } desc { "computing implied outlives bounds for `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
@ -1694,6 +1713,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "computing dropck types for `{:?}`", goal } desc { "computing dropck types for `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
@ -1721,6 +1741,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal } desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: part of the `Eq` type-op /// Do not call this query directly: part of the `Eq` type-op
@ -1731,6 +1752,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "evaluating `type_op_eq` `{:?}`", goal } desc { "evaluating `type_op_eq` `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: part of the `Subtype` type-op /// Do not call this query directly: part of the `Subtype` type-op
@ -1741,6 +1763,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "evaluating `type_op_subtype` `{:?}`", goal } desc { "evaluating `type_op_subtype` `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: part of the `ProvePredicate` type-op /// Do not call this query directly: part of the `ProvePredicate` type-op
@ -1761,6 +1784,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "normalizing `{:?}`", goal } desc { "normalizing `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: part of the `Normalize` type-op /// Do not call this query directly: part of the `Normalize` type-op
@ -1771,6 +1795,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "normalizing `{:?}`", goal } desc { "normalizing `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: part of the `Normalize` type-op /// Do not call this query directly: part of the `Normalize` type-op
@ -1781,6 +1806,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "normalizing `{:?}`", goal } desc { "normalizing `{:?}`", goal }
remap_env_constness
} }
/// Do not call this query directly: part of the `Normalize` type-op /// Do not call this query directly: part of the `Normalize` type-op
@ -1791,6 +1817,7 @@ rustc_queries! {
NoSolution, NoSolution,
> { > {
desc { "normalizing `{:?}`", goal } desc { "normalizing `{:?}`", goal }
remap_env_constness
} }
query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
@ -1804,6 +1831,7 @@ rustc_queries! {
goal: CanonicalTyGoal<'tcx> goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> { ) -> MethodAutoderefStepsResult<'tcx> {
desc { "computing autoderef types for `{:?}`", goal } desc { "computing autoderef types for `{:?}`", goal }
remap_env_constness
} }
query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> { query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
@ -1836,6 +1864,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)> key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> { ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
remap_env_constness
} }
query resolve_instance_of_const_arg( query resolve_instance_of_const_arg(
@ -1845,6 +1874,7 @@ rustc_queries! {
"resolving instance of the const argument `{}`", "resolving instance of the const argument `{}`",
ty::Instance::new(key.value.0.to_def_id(), key.value.2), ty::Instance::new(key.value.0.to_def_id(), key.value.2),
} }
remap_env_constness
} }
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> { query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
@ -1859,6 +1889,7 @@ rustc_queries! {
/// size, to account for partial initialisation. See #49298 for details.) /// size, to account for partial initialisation. See #49298 for details.)
query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "conservatively checking if {:?} is privately uninhabited", key } desc { "conservatively checking if {:?} is privately uninhabited", key }
remap_env_constness
} }
query limits(key: ()) -> Limits { query limits(key: ()) -> Limits {

View file

@ -12,14 +12,12 @@ use rustc_hir::def_id::DefId;
use rustc_query_system::cache::Cache; use rustc_query_system::cache::Cache;
pub type SelectionCache<'tcx> = Cache< pub type SelectionCache<'tcx> = Cache<
(ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity), ty::ParamEnvAnd<'tcx, ty::TraitPredicate<'tcx>>,
SelectionResult<'tcx, SelectionCandidate<'tcx>>, SelectionResult<'tcx, SelectionCandidate<'tcx>>,
>; >;
pub type EvaluationCache<'tcx> = Cache< pub type EvaluationCache<'tcx> =
(ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity), Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitPredicate<'tcx>>, EvaluationResult>;
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
@ -103,7 +101,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::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)), ParamCandidate(ty::PolyTraitPredicate<'tcx>),
ImplCandidate(DefId), ImplCandidate(DefId),
AutoImplCandidate(DefId), AutoImplCandidate(DefId),

View file

@ -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_ref() pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
}) })
.map(|t| t.value) .map(|t| t.map_bound(|pred| pred.trait_ref))
.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);

View file

@ -230,6 +230,19 @@ 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 {
@ -846,20 +859,6 @@ 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)
@ -885,12 +884,10 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
} }
impl<'tcx> Predicate<'tcx> { impl<'tcx> Predicate<'tcx> {
pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> { pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
let predicate = self.kind(); let predicate = self.kind();
match predicate.skip_binder() { match predicate.skip_binder() {
PredicateKind::Trait(t) => { PredicateKind::Trait(t) => Some(predicate.rebind(t)),
Some(ConstnessAnd { constness: t.constness, value: predicate.rebind(t.trait_ref) })
}
PredicateKind::Projection(..) PredicateKind::Projection(..)
| PredicateKind::Subtype(..) | PredicateKind::Subtype(..)
| PredicateKind::Coerce(..) | PredicateKind::Coerce(..)
@ -1221,23 +1218,33 @@ 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>>, traits::Reveal, true>, packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>,
} }
unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { #[derive(Copy, Clone)]
const BITS: usize = 1; struct ParamTag {
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 {
traits::Reveal::UserFacing => 0, Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
traits::Reveal::All => 1, Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 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 => traits::Reveal::UserFacing, 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
1 => traits::Reveal::All, 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
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(),
} }
} }
@ -1248,6 +1255,7 @@ 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()
} }
} }
@ -1256,6 +1264,7 @@ 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);
} }
} }
@ -1267,12 +1276,14 @@ 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)
} }
} }
@ -1283,7 +1294,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) Self::new(List::empty(), Reveal::UserFacing, hir::Constness::NotConst)
} }
#[inline] #[inline]
@ -1293,7 +1304,12 @@ impl<'tcx> ParamEnv<'tcx> {
#[inline] #[inline]
pub fn reveal(self) -> traits::Reveal { pub fn reveal(self) -> traits::Reveal {
self.packed.tag() self.packed.tag().reveal
}
#[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
@ -1305,20 +1321,47 @@ 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) Self::new(List::empty(), Reveal::All, hir::Constness::NotConst)
} }
/// 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(caller_bounds: &'tcx List<Predicate<'tcx>>, reveal: Reveal) -> Self { pub fn new(
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) } caller_bounds: &'tcx List<Predicate<'tcx>>,
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(Reveal::UserFacing); self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
self self
} }
#[inline]
pub fn with_constness(mut self, constness: hir::Constness) -> Self {
self.packed.set_tag(ParamTag { constness, ..self.packed.tag() });
self
}
#[inline]
pub fn with_const(mut self) -> Self {
self.packed.set_tag(ParamTag { constness: hir::Constness::Const, ..self.packed.tag() });
self
}
#[inline]
pub fn without_const(mut self) -> Self {
self.packed.set_tag(ParamTag { constness: hir::Constness::NotConst, ..self.packed.tag() });
self
}
#[inline]
pub fn remap_constness_with(&mut self, mut constness: ty::BoundConstness) {
*self = self.with_constness(constness.and(self.constness()))
}
/// Returns a new parameter environment with the same clauses, but /// Returns a new parameter environment with the same clauses, but
/// which "reveals" the true results of projections in all cases /// which "reveals" the true results of projections in all cases
/// (even for associated types that are specializable). This is /// (even for associated types that are specializable). This is
@ -1329,17 +1372,21 @@ 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() == traits::Reveal::All { if self.packed.tag().reveal == traits::Reveal::All {
return self; return self;
} }
ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All) ParamEnv::new(
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::new(List::empty(), self.reveal(), self.constness())
} }
/// Creates a suitable environment in which to perform trait /// Creates a suitable environment in which to perform trait
@ -1369,33 +1416,23 @@ 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.
pub trait WithConstness: Sized { impl PolyTraitRef<'tcx> {
#[inline] #[inline]
fn with_constness(self, constness: BoundConstness) -> ConstnessAnd<Self> { pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> {
ConstnessAnd { constness, value: self } self.map_bound(|trait_ref| ty::TraitPredicate {
trait_ref,
constness,
polarity: ty::ImplPolarity::Positive,
})
} }
#[inline] #[inline]
fn with_const_if_const(self) -> ConstnessAnd<Self> { pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
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>,
@ -1406,6 +1443,12 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> {
pub fn into_parts(self) -> (ParamEnv<'tcx>, T) { pub fn into_parts(self) -> (ParamEnv<'tcx>, T) {
(self.param_env, self.value) (self.param_env, self.value)
} }
#[inline]
pub fn without_const(mut self) -> Self {
self.param_env = self.param_env.without_const();
self
}
} }
impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for ParamEnvAnd<'tcx, T> impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for ParamEnvAnd<'tcx, T>

View file

@ -156,6 +156,16 @@ macro_rules! separate_provide_extern_default {
}; };
} }
macro_rules! opt_remap_env_constness {
([][$name:ident]) => {};
([(remap_env_constness) $($rest:tt)*][$name:ident]) => {
let $name = $name.without_const();
};
([$other:tt $($modifiers:tt)*][$name:ident]) => {
opt_remap_env_constness!([$($modifiers)*][$name])
};
}
macro_rules! define_callbacks { macro_rules! define_callbacks {
(<$tcx:tt> (<$tcx:tt>
$($(#[$attr:meta])* $($(#[$attr:meta])*
@ -202,6 +212,8 @@ macro_rules! define_callbacks {
#[inline(always)] #[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) { pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
let key = key.into_query_param(); let key = key.into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop); let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
let lookup = match cached { let lookup = match cached {
@ -229,6 +241,8 @@ macro_rules! define_callbacks {
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx> pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
{ {
let key = key.into_query_param(); let key = key.into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone); let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone);
let lookup = match cached { let lookup = match cached {

View file

@ -218,19 +218,6 @@ 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,

View file

@ -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())) .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.constness()))
} }
} }

View file

@ -8,9 +8,7 @@ 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::{ use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
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;

View file

@ -231,6 +231,16 @@ macro_rules! get_provider {
}; };
} }
macro_rules! opt_remap_env_constness {
([][$name:ident]) => {};
([(remap_env_constness) $($rest:tt)*][$name:ident]) => {
let $name = $name.without_const();
};
([$other:tt $($modifiers:tt)*][$name:ident]) => {
opt_remap_env_constness!([$($modifiers)*][$name])
};
}
macro_rules! define_queries { macro_rules! define_queries {
(<$tcx:tt> (<$tcx:tt>
$($(#[$attr:meta])* $($(#[$attr:meta])*
@ -247,6 +257,7 @@ macro_rules! define_queries {
// Create an eponymous constructor for each query. // Create an eponymous constructor for each query.
$(#[allow(nonstandard_style)] $(#[$attr])* $(#[allow(nonstandard_style)] $(#[$attr])*
pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame { pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame {
opt_remap_env_constness!([$($modifiers)*][key]);
let kind = dep_graph::DepKind::$name; let kind = dep_graph::DepKind::$name;
let name = stringify!($name); let name = stringify!($name);
// Disable visible paths printing for performance reasons. // Disable visible paths printing for performance reasons.
@ -521,6 +532,7 @@ macro_rules! define_queries_struct {
lookup: QueryLookup, lookup: QueryLookup,
mode: QueryMode, mode: QueryMode,
) -> Option<query_stored::$name<$tcx>> { ) -> Option<query_stored::$name<$tcx>> {
opt_remap_env_constness!([$($modifiers)*][key]);
let qcx = QueryCtxt { tcx, queries: self }; let qcx = QueryCtxt { tcx, queries: self };
get_query::<queries::$name<$tcx>, _>(qcx, span, key, lookup, mode) get_query::<queries::$name<$tcx>, _>(qcx, span, key, lookup, mode)
})* })*

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
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;

View file

@ -9,7 +9,6 @@ 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};

View file

@ -370,12 +370,17 @@ 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(tcx.mk_predicates(normalized_preds), param_env.reveal()); new_env = ty::ParamEnv::new(
tcx.mk_predicates(normalized_preds),
param_env.reveal(),
param_env.constness(),
);
} }
let final_user_env = ty::ParamEnv::new( 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 '{:?}' \

View file

@ -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, WithConstness, TypeFoldable,
}; };
use rustc_session::DiagnosticMessageId; use rustc_session::DiagnosticMessageId;
use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{kw, sym};

View file

@ -21,7 +21,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_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, WithConstness, Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
}; };
use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_session::Limit; use rustc_session::Limit;

View file

@ -4,7 +4,6 @@ use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{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;
@ -231,21 +230,6 @@ 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>,
@ -254,15 +238,6 @@ 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())
} }
@ -679,12 +654,7 @@ 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
@ -738,12 +708,7 @@ 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);

View file

@ -33,8 +33,7 @@ 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, WithConstness, self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, COMMON_VTABLE_ENTRIES,
COMMON_VTABLE_ENTRIES,
}; };
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -307,8 +306,11 @@ 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 = let elaborated_env = ty::ParamEnv::new(
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()); tcx.intern_predicates(&predicates),
unnormalized_env.reveal(),
unnormalized_env.constness(),
);
// HACK: we are trying to normalize the param-env inside *itself*. The problem is that // 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
@ -360,8 +362,11 @@ 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 = let outlives_env = ty::ParamEnv::new(
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal()); tcx.intern_predicates(&outlives_env),
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,
@ -381,7 +386,11 @@ 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(tcx.intern_predicates(&predicates), unnormalized_env.reveal()) ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
unnormalized_env.reveal(),
unnormalized_env.constness(),
)
} }
pub fn fully_normalize<'a, 'tcx, T>( pub fn fully_normalize<'a, 'tcx, T>(
@ -564,14 +573,17 @@ 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_ref() pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
}); });
'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.value, next_super_trait,
emit_vptr_on_new_entry, emit_vptr_on_new_entry,
Some(direct_super_traits_iter), Some(direct_super_traits_iter),
)); ));
@ -603,7 +615,11 @@ 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)) {
*inner_most_trait_ref = next_inner_most_trait_ref.value; // We're throwing away potential constness of super traits here.
// FIXME: handle ~const super traits
let next_inner_most_trait_ref =
next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
*inner_most_trait_ref = next_inner_most_trait_ref;
*emit_vptr = emit_vptr_on_new_entry; *emit_vptr = emit_vptr_on_new_entry;
break 'exiting_out; break 'exiting_out;
} else { } else {

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
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;
@ -694,7 +694,11 @@ fn receiver_is_dispatchable<'tcx>(
let caller_bounds: Vec<Predicate<'tcx>> = let caller_bounds: Vec<Predicate<'tcx>> =
param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect(); param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect();
ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal()) ty::ParamEnv::new(
tcx.intern_predicates(&caller_bounds),
param_env.reveal(),
param_env.constness(),
)
}; };
// Receiver: DispatchFromDyn<Receiver[Self => U]> // Receiver: DispatchFromDyn<Receiver[Self => U]>

View file

@ -28,7 +28,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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use std::collections::BTreeMap; use std::collections::BTreeMap;

View file

@ -1,3 +1,5 @@
use rustc_middle::ty;
use crate::infer::canonical::OriginalQueryValues; use crate::infer::canonical::OriginalQueryValues;
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::traits::{ use crate::traits::{
@ -64,10 +66,21 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> { ) -> Result<EvaluationResult, OverflowError> {
let mut _orig_values = OriginalQueryValues::default(); let mut _orig_values = OriginalQueryValues::default();
let c_pred = self.canonicalize_query_keep_static(
obligation.param_env.and(obligation.predicate), let param_env = match obligation.predicate.kind().skip_binder() {
&mut _orig_values, ty::PredicateKind::Trait(pred) => {
); // we ignore the value set to it.
let mut _constness = pred.constness;
obligation
.param_env
.with_constness(_constness.and(obligation.param_env.constness()))
}
// constness has no effect on the given predicate.
_ => obligation.param_env.without_const(),
};
let c_pred = self
.canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
// Run canonical query. If overflow occurs, rerun from scratch but this time // Run canonical query. If overflow occurs, rerun from scratch but this time
// in standard trait query mode so that overflow is handled appropriately // in standard trait query mode so that overflow is handled appropriately
// within `SelectionContext`. // within `SelectionContext`.

View file

@ -30,8 +30,14 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
fn perform_query( fn perform_query(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, mut canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
match canonicalized.value.value.predicate.kind().skip_binder() {
ty::PredicateKind::Trait(pred) => {
canonicalized.value.param_env.remap_constness_with(pred.constness);
}
_ => canonicalized.value.param_env = canonicalized.value.param_env.without_const(),
}
tcx.type_op_prove_predicate(canonicalized) tcx.type_op_prove_predicate(canonicalized)
} }
} }

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
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 self.is_in_const_context { if obligation.param_env.constness() == hir::Constness::Const {
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");
@ -381,17 +381,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.param_env .param_env
.caller_bounds() .caller_bounds()
.iter() .iter()
.filter_map(|o| o.to_opt_poly_trait_ref()); .filter_map(|o| o.to_opt_poly_trait_pred());
// Micro-optimization: filter out predicates relating to different traits. // Micro-optimization: filter out predicates relating to different traits.
let matching_bounds = let matching_bounds =
all_bounds.filter(|p| p.value.def_id() == stack.obligation.predicate.def_id()); all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
// Keep only those bounds which may apply, and propagate overflow if it occurs. // Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in matching_bounds { for bound in matching_bounds {
let wc = self.evaluate_where_clause(stack, bound.value)?; // FIXME(oli-obk): it is suspicious that we are dropping the constness and
// polarity here.
let wc = self.evaluate_where_clause(stack, bound.map_bound(|t| t.trait_ref))?;
if wc.may_apply() { if wc.may_apply() {
candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity()))); candidates.vec.push(ParamCandidate(bound));
} }
} }

View file

@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_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, WithConstness}; use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
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,8 +58,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
ParamCandidate(param) => { ParamCandidate(param) => {
let obligations = self.confirm_param_candidate(obligation, param.0.value); let obligations =
Ok(ImplSource::Param(obligations, param.0.constness)) self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
Ok(ImplSource::Param(obligations, param.skip_binder().constness))
} }
ImplCandidate(impl_def_id) => { ImplCandidate(impl_def_id) => {
@ -139,7 +140,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); self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
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() {
@ -150,8 +151,9 @@ 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_ref() .to_opt_poly_trait_pred()
.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,
@ -165,7 +167,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.to_poly_trait_ref(), candidate.value) .sup(placeholder_trait_predicate, candidate)
.map(|InferOk { obligations, .. }| obligations) .map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented) .map_err(|_| Unimplemented)
})?); })?);

View file

@ -39,7 +39,6 @@ use rustc_middle::ty::fast_reject;
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::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;
@ -128,9 +127,6 @@ 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.
@ -141,9 +137,9 @@ pub struct SelectionContext<'cx, 'tcx> {
struct TraitObligationStack<'prev, 'tcx> { struct TraitObligationStack<'prev, 'tcx> {
obligation: &'prev TraitObligation<'tcx>, obligation: &'prev TraitObligation<'tcx>,
/// The trait ref from `obligation` but "freshened" with the /// The trait predicate from `obligation` but "freshened" with the
/// selection-context's freshener. Used to check for recursion. /// selection-context's freshener. Used to check for recursion.
fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
/// Starts out equal to `depth` -- if, during evaluation, we /// 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
@ -222,7 +218,6 @@ 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,
} }
} }
@ -234,7 +229,6 @@ 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,
} }
} }
@ -250,7 +244,6 @@ 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,
} }
} }
@ -266,26 +259,10 @@ 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
@ -318,20 +295,6 @@ 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
// //
@ -716,20 +679,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
let stack = self.push_stack(previous_stack, &obligation); let stack = self.push_stack(previous_stack, &obligation);
let fresh_trait_ref = stack.fresh_trait_ref; let mut fresh_trait_pred = stack.fresh_trait_pred;
let mut param_env = obligation.param_env;
debug!(?fresh_trait_ref); fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
pred
});
if let Some(result) = self.check_evaluation_cache( debug!(?fresh_trait_pred);
obligation.param_env,
fresh_trait_ref, if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
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_ref) { if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
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);
@ -754,19 +719,12 @@ 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( self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
obligation.param_env,
fresh_trait_ref,
obligation.polarity(),
dep_node,
result,
);
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| { stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
self.insert_evaluation_cache( self.insert_evaluation_cache(
obligation.param_env, param_env,
fresh_trait_ref, fresh_trait_pred,
obligation.polarity(),
dep_node, dep_node,
provisional_result.max(result), provisional_result.max(result),
); );
@ -776,10 +734,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_ref, stack.depth, reached_depth, fresh_trait_pred, stack.depth, reached_depth,
); );
stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result); stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
} }
Ok(result) Ok(result)
@ -813,7 +771,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_ref == prev.fresh_trait_ref && stack.fresh_trait_pred == prev.fresh_trait_pred
}) })
.map(|stack| stack.depth) .map(|stack| stack.depth)
{ {
@ -876,7 +834,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// terms of `Fn` etc, but we could probably make this more // terms of `Fn` etc, but we could probably make this more
// precise still. // precise still.
let unbound_input_types = let unbound_input_types =
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh()); stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
if stack.obligation.polarity() != ty::ImplPolarity::Negative { 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
@ -914,8 +872,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_ref, stack.fresh_trait_pred,
prev.fresh_trait_ref, prev.fresh_trait_pred,
prev.obligation.param_env, prev.obligation.param_env,
) )
}) })
@ -993,7 +951,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_ref.has_erased_regions() { if stack.fresh_trait_pred.has_erased_regions() {
result = result.max(EvaluatedToOkModuloRegions); result = result.max(EvaluatedToOkModuloRegions);
} }
@ -1004,8 +962,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_evaluation_cache( fn check_evaluation_cache(
&self, &self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, trait_pred: ty::PolyTraitPredicate<'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
@ -1017,19 +974,17 @@ 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(&(param_env.and(trait_ref), polarity), tcx) if let Some(res) = tcx.evaluation_cache.get(&param_env.and(trait_pred), tcx) {
{
return Some(res); return Some(res);
} }
} }
self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx) self.infcx.evaluation_cache.get(&param_env.and(trait_pred), tcx)
} }
fn insert_evaluation_cache( fn insert_evaluation_cache(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, trait_pred: ty::PolyTraitPredicate<'tcx>,
polarity: ty::ImplPolarity,
dep_node: DepNodeIndex, dep_node: DepNodeIndex,
result: EvaluationResult, result: EvaluationResult,
) { ) {
@ -1048,23 +1003,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
if self.can_use_global_caches(param_env) { if self.can_use_global_caches(param_env) {
if !trait_ref.needs_infer() { if !trait_pred.needs_infer() {
debug!(?trait_ref, ?result, "insert_evaluation_cache global"); debug!(?trait_pred, ?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( self.tcx().evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
(param_env.and(trait_ref), polarity),
dep_node,
result,
);
return; return;
} }
} }
debug!(?trait_ref, ?result, "insert_evaluation_cache"); debug!(?trait_pred, ?result, "insert_evaluation_cache");
self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result); self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
} }
/// For various reasons, it's possible for a subobligation /// For various reasons, it's possible for a subobligation
@ -1142,16 +1093,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
for candidate in candidates { for candidate in candidates {
// Respect const trait obligations // Respect const trait obligations
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) { if obligation.is_const() {
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(( ParamCandidate(trait_pred)
ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. }, if trait_pred.skip_binder().constness
_, == 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
@ -1260,7 +1210,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_candidate_cache( fn check_candidate_cache(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, mut 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
@ -1271,19 +1221,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return None; return None;
} }
let tcx = self.tcx(); let tcx = self.tcx();
let pred = &cache_fresh_trait_pred.skip_binder(); let mut 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_use_global_caches(param_env) { if self.can_use_global_caches(param_env) {
if let Some(res) = tcx if let Some(res) = tcx.selection_cache.get(&param_env.and(pred), tcx) {
.selection_cache
.get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
{
return Some(res); return Some(res);
} }
} }
self.infcx self.infcx.selection_cache.get(&param_env.and(pred), tcx)
.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
@ -1321,43 +1267,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn insert_candidate_cache( fn insert_candidate_cache(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, mut 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 pred = cache_fresh_trait_pred.skip_binder(); let mut 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!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable"); debug!(?pred, ?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 !trait_ref.needs_infer() { } else if !pred.needs_infer() {
if !candidate.needs_infer() { if !candidate.needs_infer() {
debug!(?trait_ref, ?candidate, "insert_candidate_cache global"); debug!(?pred, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value. // This may overwrite the cache with the same value.
tcx.selection_cache.insert( tcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
return; return;
} }
} }
} }
debug!(?trait_ref, ?candidate, "insert_candidate_cache local"); debug!(?pred, ?candidate, "insert_candidate_cache local");
self.infcx.selection_cache.insert( self.infcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
(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.
@ -1548,7 +1487,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::PolyTraitRef<'tcx>| { let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions() cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
}; };
@ -1581,25 +1520,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ConstDropCandidate, | ConstDropCandidate,
) => false, ) => false,
( (ParamCandidate(other), ParamCandidate(victim)) => {
ParamCandidate((other, other_polarity)), let same_except_bound_vars = other.skip_binder().trait_ref
ParamCandidate((victim, victim_polarity)), == victim.skip_binder().trait_ref
) => { && other.skip_binder().constness == victim.skip_binder().constness
let same_except_bound_vars = other.value.skip_binder() && other.skip_binder().polarity == victim.skip_binder().polarity
== victim.value.skip_binder() && !other.skip_binder().trait_ref.has_escaping_bound_vars();
&& 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.value.bound_vars().len() <= victim.value.bound_vars().len() other.bound_vars().len() <= victim.bound_vars().len()
} else if other.value == victim.value } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
&& victim.constness == ty::BoundConstness::NotConst && victim.skip_binder().constness == ty::BoundConstness::NotConst
&& other_polarity == victim_polarity && other.skip_binder().polarity == victim.skip_binder().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
@ -1629,11 +1565,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitAliasCandidate(..) | TraitAliasCandidate(..)
| ObjectCandidate(_) | ObjectCandidate(_)
| ProjectionCandidate(_), | ProjectionCandidate(_),
) => !is_global(&cand.0.value), ) => !is_global(cand),
(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.0.value) is_global(cand)
} }
( (
ImplCandidate(_) ImplCandidate(_)
@ -1649,7 +1585,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.0.value) && other.evaluation.must_apply_modulo_regions() is_global(cand) && other.evaluation.must_apply_modulo_regions()
} }
(ProjectionCandidate(i), ProjectionCandidate(j)) (ProjectionCandidate(i), ProjectionCandidate(j))
@ -2209,8 +2145,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn match_fresh_trait_refs( fn match_fresh_trait_refs(
&self, &self,
previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, previous: ty::PolyTraitPredicate<'tcx>,
current: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, current: ty::PolyTraitPredicate<'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);
@ -2222,17 +2158,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
previous_stack: TraitObligationStackList<'o, 'tcx>, previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &'o TraitObligation<'tcx>, obligation: &'o TraitObligation<'tcx>,
) -> TraitObligationStack<'o, 'tcx> { ) -> TraitObligationStack<'o, 'tcx> {
let fresh_trait_ref = obligation let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener);
.predicate
.to_poly_trait_ref()
.fold_with(&mut self.freshener)
.with_constness(obligation.predicate.skip_binder().constness);
let dfn = previous_stack.cache.next_dfn(); let dfn = previous_stack.cache.next_dfn();
let depth = previous_stack.depth() + 1; let depth = previous_stack.depth() + 1;
TraitObligationStack { TraitObligationStack {
obligation, obligation,
fresh_trait_ref, fresh_trait_pred,
reached_depth: Cell::new(depth), reached_depth: Cell::new(depth),
previous: previous_stack, previous: previous_stack,
dfn, dfn,
@ -2426,7 +2358,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_ref, "update_reached_depth: marking as cycle participant"); debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant");
p.reached_depth.set(p.reached_depth.get().min(reached_depth)); p.reached_depth.set(p.reached_depth.get().min(reached_depth));
p = p.previous.head.unwrap(); p = p.previous.head.unwrap();
} }
@ -2505,7 +2437,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::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ProvisionalEvaluation>>, map: RefCell<FxHashMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
} }
/// A cache value for the provisional cache: contains the depth-first /// A cache value for the provisional cache: contains the depth-first
@ -2537,28 +2469,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_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<ProvisionalEvaluation> { ) -> Option<ProvisionalEvaluation> {
debug!( debug!(
?fresh_trait_ref, ?fresh_trait_pred,
"get_provisional = {:#?}", "get_provisional = {:#?}",
self.map.borrow().get(&fresh_trait_ref), self.map.borrow().get(&fresh_trait_pred),
); );
Some(*self.map.borrow().get(&fresh_trait_ref)?) Some(*self.map.borrow().get(&fresh_trait_pred)?)
} }
/// Insert a provisional result into the cache. The result came /// 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_ref` /// of `reached_depth` to compute. It evaluated `fresh_trait_pred`
/// 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_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
result: EvaluationResult, result: EvaluationResult,
) { ) {
debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional"); debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
let mut map = self.map.borrow_mut(); let mut map = self.map.borrow_mut();
@ -2582,7 +2514,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
} }
} }
map.insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, reached_depth, result }); map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
} }
/// Invoked when the node with dfn `dfn` does not get a successful /// Invoked when the node with dfn `dfn` does not get a successful
@ -2633,16 +2565,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
fn on_completion( fn on_completion(
&self, &self,
dfn: usize, dfn: usize,
mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult), mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
) { ) {
debug!(?dfn, "on_completion"); debug!(?dfn, "on_completion");
for (fresh_trait_ref, eval) in for (fresh_trait_pred, eval) in
self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn) self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
{ {
debug!(?fresh_trait_ref, ?eval, "on_completion"); debug!(?fresh_trait_pred, ?eval, "on_completion");
op(fresh_trait_ref, eval.result); op(fresh_trait_pred, eval.result);
} }
} }
} }

View file

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

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
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_ref() .to_opt_poly_trait_pred()
.map(|trait_ref| item.clone_and_push(trait_ref.value, *span)) .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *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_ref()) .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred())
.map(|trait_ref| trait_ref.value.def_id()) .map(|trait_ref| trait_ref.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)

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span; use rustc_span::Span;
use std::iter; use std::iter;
@ -298,9 +298,10 @@ 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_ref() { if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() {
let derived_cause = traits::DerivedObligationCause { let derived_cause = traits::DerivedObligationCause {
parent_trait_ref: parent_trait_ref.value, // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
parent_code: Lrc::new(obligation.cause.code.clone()), parent_code: Lrc::new(obligation.cause.code.clone()),
}; };
cause.make_mut().code = cause.make_mut().code =

View file

@ -2,9 +2,7 @@ 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::{ use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
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;
@ -282,16 +280,79 @@ 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 unnormalized_env = let local_did = def_id.as_local();
ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing); let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds()); let constness = match hir_id {
let body_id = def_id Some(hir_id) => match tcx.hir().get(hir_id) {
.as_local() hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
.map_or(hir::CRATE_HIR_ID, |id| { | hir::Node::TraitItem(hir::TraitItem {
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_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)
});
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
} }

View file

@ -1587,7 +1587,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, _)| {
p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
}), }),
assoc_name, assoc_name,
) )

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
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

View file

@ -1506,17 +1506,11 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
} }
pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(super) use wfcheck::check_item_well_formed;
wfcheck::check_item_well_formed(tcx, def_id);
}
pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(super) use wfcheck::check_trait_item as check_trait_item_well_formed;
wfcheck::check_trait_item(tcx, def_id);
}
pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(super) use wfcheck::check_impl_item as check_impl_item_well_formed;
wfcheck::check_impl_item(tcx, def_id);
}
fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")

View file

@ -80,7 +80,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let generator_types = check_fn( let generator_types = check_fn(
self, self,
self.param_env, self.param_env.without_const(),
liberated_sig, liberated_sig,
decl, decl,
expr.hir_id, expr.hir_id,

View file

@ -208,8 +208,11 @@ 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 = let param_env = ty::ParamEnv::new(
ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); tcx.intern_predicates(&hybrid_preds.predicates),
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);
@ -1167,8 +1170,11 @@ 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 = let param_env = ty::ParamEnv::new(
ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); tcx.intern_predicates(&hybrid_preds.predicates),
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,
@ -1353,7 +1359,11 @@ pub fn check_type_bounds<'tcx>(
.to_predicate(tcx), .to_predicate(tcx),
), ),
}; };
ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing) ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
Reveal::UserFacing,
param_env.constness(),
)
}; };
debug!(?normalize_param_env); debug!(?normalize_param_env);
@ -1362,13 +1372,7 @@ 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 constness = impl_ty let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
.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);
@ -1412,8 +1416,7 @@ 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 = let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
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);

View file

@ -616,10 +616,7 @@ 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 let errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&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);
@ -632,10 +629,7 @@ 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 let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(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);

View file

@ -53,9 +53,6 @@ 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,
@ -102,16 +99,6 @@ 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);
@ -128,7 +115,6 @@ 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,
} }
} }

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
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;

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
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};

View file

@ -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, WithConstness}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
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};

View file

@ -21,7 +21,6 @@ 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};

View file

@ -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, TypeFoldable, WithConstness}; use rustc_middle::ty::{ReprOptions, ToPredicate, TypeFoldable};
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};

View file

@ -534,9 +534,10 @@ where
// From implies Into // From implies Into
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T, U> const Into<U> for T
where where
U: From<T>, U: ~const From<T>,
{ {
fn into(self) -> U { fn into(self) -> U {
U::from(self) U::from(self)

View file

@ -112,6 +112,7 @@
#![feature(const_float_classify)] #![feature(const_float_classify)]
#![feature(const_fmt_arguments_new)] #![feature(const_fmt_arguments_new)]
#![feature(const_heap)] #![feature(const_heap)]
#![feature(const_convert)]
#![feature(const_inherent_unchecked_arith)] #![feature(const_inherent_unchecked_arith)]
#![feature(const_int_unchecked_arith)] #![feature(const_int_unchecked_arith)]
#![feature(const_intrinsic_copy)] #![feature(const_intrinsic_copy)]

View file

@ -2077,7 +2077,8 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T> ops::Try for Option<T> { #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const ops::Try for Option<T> {
type Output = T; type Output = T;
type Residual = Option<convert::Infallible>; type Residual = Option<convert::Infallible>;
@ -2096,6 +2097,7 @@ impl<T> ops::Try for Option<T> {
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const ops::FromResidual for Option<T> { impl<T> const ops::FromResidual for Option<T> {
#[inline] #[inline]
fn from_residual(residual: Option<convert::Infallible>) -> Self { fn from_residual(residual: Option<convert::Infallible>) -> Self {

View file

@ -1945,7 +1945,8 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E> ops::Try for Result<T, E> { #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T, E> const ops::Try for Result<T, E> {
type Output = T; type Output = T;
type Residual = Result<convert::Infallible, E>; type Residual = Result<convert::Infallible, E>;
@ -1964,7 +1965,10 @@ impl<T, E> ops::Try for Result<T, E> {
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> { #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T, E, F: ~const From<E>> const ops::FromResidual<Result<convert::Infallible, E>>
for Result<T, F>
{
#[inline] #[inline]
fn from_residual(residual: Result<convert::Infallible, E>) -> Self { fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
match residual { match residual {

View file

@ -0,0 +1,16 @@
#[test]
fn convert() {
const fn from(x: i32) -> i32 {
i32::from(x)
}
const FOO: i32 = from(42);
assert_eq!(FOO, 42);
const fn into(x: Vec<String>) -> Vec<String> {
x.into()
}
const BAR: Vec<String> = into(Vec::new());
assert_eq!(BAR, Vec::<String>::new());
}

View file

@ -12,11 +12,11 @@
#![feature(const_convert)] #![feature(const_convert)]
#![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)] #![feature(const_maybe_uninit_assume_init)]
#![feature(const_num_from_num)]
#![feature(const_ptr_read)] #![feature(const_ptr_read)]
#![feature(const_ptr_write)] #![feature(const_ptr_write)]
#![feature(const_ptr_offset)] #![feature(const_ptr_offset)]
#![feature(const_trait_impl)] #![feature(const_trait_impl)]
#![feature(const_num_from_num)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(core_private_bignum)] #![feature(core_private_bignum)]
#![feature(core_private_diy_float)] #![feature(core_private_diy_float)]
@ -96,6 +96,7 @@ mod char;
mod clone; mod clone;
mod cmp; mod cmp;
mod const_ptr; mod const_ptr;
mod convert;
mod fmt; mod fmt;
mod future; mod future;
mod hash; mod hash;

View file

@ -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, WithConstness}; use rustc_middle::ty::ToPredicate;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use super::*; use super::*;
@ -66,7 +66,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
.into_iter() .into_iter()
.chain(Some( .chain(Some(
ty::Binder::dummy(trait_ref) ty::Binder::dummy(trait_ref)
.without_const() .to_poly_trait_predicate()
.map_bound(ty::PredicateKind::Trait)
.to_predicate(infcx.tcx), .to_predicate(infcx.tcx),
)); ));
for predicate in predicates { for predicate in predicates {

View file

@ -1,9 +0,0 @@
// run-pass
const _FOO: fn() -> String = || "foo".into();
pub fn bar() -> fn() -> String {
|| "bar".into()
}
fn main(){}

View file

@ -0,0 +1,23 @@
// run-pass
#![feature(try_trait_v2)]
#![feature(const_trait_impl)]
#![feature(const_try)]
#![feature(const_convert)]
fn main() {
const fn result() -> Result<bool, ()> {
Err(())?;
Ok(true)
}
const FOO: Result<bool, ()> = result();
assert_eq!(Err(()), FOO);
const fn option() -> Option<()> {
None?;
Some(())
}
const BAR: Option<()> = option();
assert_eq!(None, BAR);
}

View file

@ -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 }, value: Take } }` = 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 } }`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -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 }, value: MList } }` = 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 } }`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -0,0 +1,40 @@
// check-pass
// regression test for #91489
use std::borrow::Borrow;
use std::borrow::Cow;
pub struct VariantType {}
pub struct VariantTy {}
impl Borrow<VariantTy> for VariantType {
fn borrow(&self) -> &VariantTy {
unimplemented!()
}
}
impl ToOwned for VariantTy {
type Owned = VariantType;
fn to_owned(&self) -> VariantType {
unimplemented!()
}
}
impl VariantTy {
pub fn as_str(&self) -> () {}
}
// the presence of this was causing all attempts to call `as_str` on
// `Cow<'_, VariantTy>, including in itself, to not find the method
static _TYP: () = {
let _ = || {
// should be found
Cow::Borrowed(&VariantTy {}).as_str();
};
};
fn main() {
// should be found
Cow::Borrowed(&VariantTy {}).as_str()
}

View file

@ -1,6 +1,5 @@
// 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 {

View file

@ -1,12 +1,12 @@
error[E0277]: cannot add `NonConstAdd` to `NonConstAdd` error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
--> $DIR/assoc-type.rs:19:16 --> $DIR/assoc-type.rs:18:16
| |
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:15:15 --> $DIR/assoc-type.rs:14: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`

View file

@ -0,0 +1,18 @@
// check-pass
#![feature(const_trait_impl)]
#![feature(const_fn_trait_bound)]
trait Convert<T> {
fn to(self) -> T;
}
impl<A, B> const Convert<B> for A where B: ~const From<A> {
fn to(self) -> B {
B::from(self)
}
}
const FOO: fn() -> String = || "foo".to();
fn main() {}

View file

@ -68,8 +68,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_ref) = p.to_opt_poly_trait_ref() { if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
if Some(trait_ref.value.def_id()) == cx.tcx.lang_items().future_trait() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
is_future = true; is_future = true;
break; break;
} }