diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6a263bd63ad..195ed13a027 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -31,7 +31,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::{ 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::{Span, DUMMY_SP}; diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 6d3a89c0a8a..c5412affafe 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,6 +7,7 @@ use crate::interpret::{ }; use rustc_errors::ErrorReported; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; @@ -215,6 +216,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'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 if key.param_env.reveal() == Reveal::All { let mut key = key; @@ -249,6 +251,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'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 // 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 diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index a7c08f225b0..67351aa3653 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -929,6 +929,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; + let param_env = param_env.with_const(); let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?; self.raw_const_to_mplace(val) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 4a02e059537..5a4aa06f3bb 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -817,8 +817,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { ); let implsrc = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = - SelectionContext::with_constness(&infcx, hir::Constness::Const); + let mut selcx = SelectionContext::new(&infcx); selcx.select(&obligation) }); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index abc5a3c6a52..43612292f52 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -3,7 +3,6 @@ //! See the `Qualif` trait for more info. use rustc_errors::ErrorReported; -use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; 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 mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const); + let mut selcx = SelectionContext::new(&infcx); selcx.select(&obligation) }); !matches!( diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs index d63bcdb3c2b..e1d3e0bd35a 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -94,9 +94,11 @@ where // SAFETY: pointer_raw returns the original pointer unsafe { std::mem::transmute_copy(&self.pointer_raw()) } } + #[inline] pub fn tag(&self) -> T { unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) } } + #[inline] pub fn set_tag(&mut self, tag: T) { let mut packed = self.packed.get(); let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 60e4864874d..fdf7a8102a0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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> { match self { Node::Item(i) => Some(OwnerNode::Item(i)), diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 152a395c871..822f2365e02 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,9 +1,8 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; 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::{ObligationCause, PredicateObligation}; @@ -48,26 +47,9 @@ pub trait TraitEngine<'tcx>: 'tcx { fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec>; - fn select_all_with_constness_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - _constness: hir::Constness, - ) -> Vec> { - self.select_all_or_error(infcx) - } - fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec>; - // 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> { - self.select_where_possible(infcx) - } - fn pending_obligations(&self) -> Vec>; fn relationships(&mut self) -> &mut FxHashMap; diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index e8622b3c819..7e30f859dae 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -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. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(PredicateObligation<'_>, 32); diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 92f74af4eb3..61588147364 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -3,7 +3,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; 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::Span; @@ -328,8 +328,8 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>( )); for (super_predicate, _) in super_predicates.predicates { let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref); - if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { - stack.push(binder.value); + if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() { + stack.push(binder.map_bound(|t| t.trait_ref)); } } @@ -362,8 +362,8 @@ impl<'tcx, I: Iterator>> Iterator for FilterToT fn next(&mut self) -> Option> { while let Some(obligation) = self.base_iterator.next() { - if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() { - return Some(data.value); + if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() { + return Some(data.map_bound(|t| t.trait_ref)); } } None diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 6dbba274360..478159147ac 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -58,6 +58,9 @@ enum QueryModifier { /// Use a separate query provider for local and extern crates SeparateProvideExtern(Ident), + + /// Always remap the ParamEnv's constness before hashing and passing to the query provider + RemapEnvConstness(Ident), } impl Parse for QueryModifier { @@ -123,6 +126,8 @@ impl Parse for QueryModifier { Ok(QueryModifier::EvalAlways(modifier)) } else if modifier == "separate_provide_extern" { Ok(QueryModifier::SeparateProvideExtern(modifier)) + } else if modifier == "remap_env_constness" { + Ok(QueryModifier::RemapEnvConstness(modifier)) } else { Err(Error::new(modifier.span(), "unknown query modifier")) } @@ -222,6 +227,9 @@ struct QueryModifiers { /// Use a separate query provider for local and extern crates separate_provide_extern: Option, + + /// Always remap the ParamEnv's constness before hashing. + remap_env_constness: Option, } /// 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 eval_always = None; let mut separate_provide_extern = None; + let mut remap_env_constness = None; for modifier in query.modifiers.0.drain(..) { match modifier { QueryModifier::LoadCached(tcx, id, block) => { @@ -335,6 +344,12 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { } 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(|| { @@ -351,6 +366,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { anon, eval_always, 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 { 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, // which can be important if we later encounter any ambiguity diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5c4c2eee21f..394a1fc2270 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -474,7 +474,8 @@ impl<'hir> Map<'hir> { /// Panics if `LocalDefId` does not have an associated body. /// /// 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 { let hir_id = self.local_def_id_to_hir_id(did); let ccx = match self.body_owner_kind(hir_id) { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index d764d45ba7e..14cff60475a 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -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> { /// Allows you to map the `value` of a canonical while keeping the /// same set of bound variables. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index c63613ae3af..f9831855633 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -64,6 +64,7 @@ impl<'tcx> TyCtxt<'tcx> { cid: GlobalId<'tcx>, span: Option, ) -> 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 // improve caching of queries. let inputs = self.erase_regions(param_env.and(cid)); @@ -92,6 +93,7 @@ impl<'tcx> TyCtxt<'tcx> { gid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Result<&'tcx mir::Allocation, ErrorHandled> { + let param_env = param_env.with_const(); trace!("eval_to_allocation: Need to compute {:?}", gid); let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8667a6bea11..58f584d65d5 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -880,6 +880,7 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>> ) -> Option> { desc { "destructure constant" } + remap_env_constness } /// 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>> ) -> mir::DestructuredConst<'tcx> { desc { "destructure constant" } + remap_env_constness } /// 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>> ) -> &'tcx ty::Const<'tcx> { desc { "deref constant" } + remap_env_constness } 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. query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Copy`", env.value } + remap_env_constness } /// Query backing `TyS::is_sized`. query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } + remap_env_constness } /// Query backing `TyS::is_freeze`. query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is freeze", env.value } + remap_env_constness } /// Query backing `TyS::is_unpin`. query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Unpin`", env.value } + remap_env_constness } /// Query backing `TyS::needs_drop`. query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` needs drop", env.value } + remap_env_constness } /// Query backing `TyS::has_significant_drop_raw`. query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` has a significant drop", env.value } + remap_env_constness } /// Query backing `TyS::is_structural_eq_shallow`. @@ -1158,6 +1167,7 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> ) -> Result, ty::layout::LayoutError<'tcx>> { desc { "computing layout of `{}`", key.value } + remap_env_constness } /// 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>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { 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 @@ -1179,6 +1190,7 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { desc { "computing call ABI of `{}`", key.value.0 } + remap_env_constness } query dylib_dependency_formats(_: CrateNum) @@ -1463,6 +1475,7 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> ) -> ty::inhabitedness::DefIdForest { desc { "computing the inhabitedness of `{:?}`", key } + remap_env_constness } query dep_kind(_: CrateNum) -> CrateDepKind { @@ -1642,6 +1655,7 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal } + remap_env_constness } // FIXME: Implement `normalize_generic_arg_after_erasing_regions` and @@ -1654,6 +1668,7 @@ rustc_queries! { goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> ) -> GenericArg<'tcx> { desc { "normalizing `{}`", goal.value } + remap_env_constness } /// Do not call this query directly: invoke `normalize_erasing_regions` instead. @@ -1661,6 +1676,7 @@ rustc_queries! { goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> ) -> mir::ConstantKind<'tcx> { desc { "normalizing `{}`", goal.value } + remap_env_constness } /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead. @@ -1668,6 +1684,7 @@ rustc_queries! { goal: ParamEnvAnd<'tcx, GenericArg<'tcx>> ) -> Result, NoSolution> { desc { "normalizing `{}`", goal.value } + remap_env_constness } /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead. @@ -1675,6 +1692,7 @@ rustc_queries! { goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> ) -> Result, NoSolution> { desc { "normalizing `{}`", goal.value } + remap_env_constness } query implied_outlives_bounds( @@ -1684,6 +1702,7 @@ rustc_queries! { NoSolution, > { desc { "computing implied outlives bounds for `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. @@ -1694,6 +1713,7 @@ rustc_queries! { NoSolution, > { desc { "computing dropck types for `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or @@ -1721,6 +1741,7 @@ rustc_queries! { NoSolution, > { desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: part of the `Eq` type-op @@ -1731,6 +1752,7 @@ rustc_queries! { NoSolution, > { desc { "evaluating `type_op_eq` `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: part of the `Subtype` type-op @@ -1741,6 +1763,7 @@ rustc_queries! { NoSolution, > { desc { "evaluating `type_op_subtype` `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: part of the `ProvePredicate` type-op @@ -1761,6 +1784,7 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: part of the `Normalize` type-op @@ -1771,6 +1795,7 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: part of the `Normalize` type-op @@ -1781,6 +1806,7 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal } + remap_env_constness } /// Do not call this query directly: part of the `Normalize` type-op @@ -1791,6 +1817,7 @@ rustc_queries! { NoSolution, > { desc { "normalizing `{:?}`", goal } + remap_env_constness } query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { @@ -1804,6 +1831,7 @@ rustc_queries! { goal: CanonicalTyGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { desc { "computing autoderef types for `{:?}`", goal } + remap_env_constness } query supported_target_features(_: CrateNum) -> FxHashMap> { @@ -1836,6 +1864,7 @@ rustc_queries! { key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)> ) -> Result>, ErrorReported> { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } + remap_env_constness } query resolve_instance_of_const_arg( @@ -1845,6 +1874,7 @@ rustc_queries! { "resolving instance of the const argument `{}`", ty::Instance::new(key.value.0.to_def_id(), key.value.2), } + remap_env_constness } query normalize_opaque_types(key: &'tcx ty::List>) -> &'tcx ty::List> { @@ -1859,6 +1889,7 @@ rustc_queries! { /// size, to account for partial initialisation. See #49298 for details.) query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "conservatively checking if {:?} is privately uninhabited", key } + remap_env_constness } query limits(key: ()) -> Limits { diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 560660517f3..71ee00c602a 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -12,14 +12,12 @@ use rustc_hir::def_id::DefId; use rustc_query_system::cache::Cache; pub type SelectionCache<'tcx> = Cache< - (ty::ConstnessAnd>>, ty::ImplPolarity), + ty::ParamEnvAnd<'tcx, ty::TraitPredicate<'tcx>>, SelectionResult<'tcx, SelectionCandidate<'tcx>>, >; -pub type EvaluationCache<'tcx> = Cache< - (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd>>, ty::ImplPolarity), - EvaluationResult, ->; +pub type EvaluationCache<'tcx> = + Cache>, EvaluationResult>; /// The selection process begins by considering all impls, where /// 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. has_nested: bool, }, - ParamCandidate((ty::ConstnessAnd>, ty::ImplPolarity)), + ParamCandidate(ty::PolyTraitPredicate<'tcx>), ImplCandidate(DefId), AutoImplCandidate(DefId), diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index 3490c688170..815f4824bc1 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -26,9 +26,9 @@ impl<'tcx> Elaborator<'tcx> { .predicates .into_iter() .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)); self.stack.extend(supertrait_refs); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fd1409949f0..d0d2a46fc4c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -230,6 +230,19 @@ pub enum BoundConstness { 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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -846,20 +859,6 @@ impl ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { } } -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - 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> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> 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> { - pub fn to_opt_poly_trait_ref(self) -> Option>> { + pub fn to_opt_poly_trait_pred(self) -> Option> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Trait(t) => { - Some(ConstnessAnd { constness: t.constness, value: predicate.rebind(t.trait_ref) }) - } + PredicateKind::Trait(t) => Some(predicate.rebind(t)), PredicateKind::Projection(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) @@ -1221,23 +1218,33 @@ pub struct ParamEnv<'tcx> { /// want `Reveal::All`. /// /// Note: This is packed, use the reveal() method to access it. - packed: CopyTaggedPtr<&'tcx List>, traits::Reveal, true>, + packed: CopyTaggedPtr<&'tcx List>, ParamTag, true>, } -unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { - const BITS: usize = 1; +#[derive(Copy, Clone)] +struct ParamTag { + reveal: traits::Reveal, + constness: hir::Constness, +} + +unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag { + const BITS: usize = 2; #[inline] fn into_usize(self) -> usize { match self { - traits::Reveal::UserFacing => 0, - traits::Reveal::All => 1, + Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0, + 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] unsafe fn from_usize(ptr: usize) -> Self { match ptr { - 0 => traits::Reveal::UserFacing, - 1 => traits::Reveal::All, + 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, + 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(), } } @@ -1248,6 +1255,7 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> { f.debug_struct("ParamEnv") .field("caller_bounds", &self.caller_bounds()) .field("reveal", &self.reveal()) + .field("constness", &self.constness()) .finish() } } @@ -1256,6 +1264,7 @@ impl<'a, 'tcx> HashStable> for ParamEnv<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.caller_bounds().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( self.caller_bounds().try_fold_with(folder)?, self.reveal().try_fold_with(folder)?, + self.constness().try_fold_with(folder)?, )) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { 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. #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing) + Self::new(List::empty(), Reveal::UserFacing, hir::Constness::NotConst) } #[inline] @@ -1293,7 +1304,12 @@ impl<'tcx> ParamEnv<'tcx> { #[inline] 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 @@ -1305,20 +1321,47 @@ impl<'tcx> ParamEnv<'tcx> { /// or invoke `param_env.with_reveal_all()`. #[inline] 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. #[inline] - pub fn new(caller_bounds: &'tcx List>, reveal: Reveal) -> Self { - ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) } + pub fn new( + caller_bounds: &'tcx List>, + reveal: Reveal, + constness: hir::Constness, + ) -> Self { + ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal, constness }) } } 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 } + #[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 /// which "reveals" the true results of projections in all cases /// (even for associated types that are specializable). This is @@ -1329,17 +1372,21 @@ impl<'tcx> ParamEnv<'tcx> { /// will be normalized to their underlying types. /// See PR #65989 and issue #65918 for more details 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; } - 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. #[inline] 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 @@ -1369,33 +1416,23 @@ impl<'tcx> ParamEnv<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] -pub struct ConstnessAnd { - pub constness: BoundConstness, - pub value: T, -} - // FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that // the constness of trait bounds is being propagated correctly. -pub trait WithConstness: Sized { +impl PolyTraitRef<'tcx> { #[inline] - fn with_constness(self, constness: BoundConstness) -> ConstnessAnd { - ConstnessAnd { constness, value: self } + pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> { + self.map_bound(|trait_ref| ty::TraitPredicate { + trait_ref, + constness, + polarity: ty::ImplPolarity::Positive, + }) } - #[inline] - fn with_const_if_const(self) -> ConstnessAnd { - self.with_constness(BoundConstness::ConstIfConst) - } - - #[inline] - fn without_const(self) -> ConstnessAnd { + pub fn without_const(self) -> PolyTraitPredicate<'tcx> { self.with_constness(BoundConstness::NotConst) } } -impl WithConstness for T {} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, @@ -1406,6 +1443,12 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> { pub fn into_parts(self) -> (ParamEnv<'tcx>, T) { (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> for ParamEnvAnd<'tcx, T> diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 34f80627197..f18517eee04 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -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 { (<$tcx:tt> $($(#[$attr:meta])* @@ -202,6 +212,8 @@ macro_rules! define_callbacks { #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { 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 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> { 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 lookup = match cached { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index c7d8bec506f..b6aadf27bb0 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -218,19 +218,6 @@ impl<'tcx> Relate<'tcx> for ty::BoundConstness { } } -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::ConstnessAnd { - fn relate>( - relation: &mut R, - a: ty::ConstnessAnd, - b: ty::ConstnessAnd, - ) -> RelateResult<'tcx, ty::ConstnessAnd> { - Ok(ty::ConstnessAnd { - constness: relation.relate(a.constness, b.constness)?, - value: relation.relate(a.value, b.value)?, - }) - } -} - impl<'tcx> Relate<'tcx> for ast::Unsafety { fn relate>( relation: &mut R, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 16a6c586358..30ed008a5de 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -480,7 +480,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { 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())) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 6bd761d61e2..a80fe6a3362 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -8,9 +8,7 @@ use crate::infer::canonical::Canonical; use crate::ty::fold::ValidateBoundVars; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::InferTy::{self, *}; -use crate::ty::{ - self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness, -}; +use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable}; use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS}; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 81a36e0d59e..2854ba5158b 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -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 { (<$tcx:tt> $($(#[$attr:meta])* @@ -247,6 +257,7 @@ macro_rules! define_queries { // Create an eponymous constructor for each query. $(#[allow(nonstandard_style)] $(#[$attr])* 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 name = stringify!($name); // Disable visible paths printing for performance reasons. @@ -521,6 +532,7 @@ macro_rules! define_queries_struct { lookup: QueryLookup, mode: QueryMode, ) -> Option> { + opt_remap_env_constness!([$($modifiers)*][key]); let qcx = QueryCtxt { tcx, queries: self }; get_query::, _>(qcx, span, key, lookup, mode) })* diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 4c80483fc1f..46c74660f86 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -3,7 +3,7 @@ use crate::traits::{self, TraitEngine}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; use rustc_middle::ty::{ToPredicate, TypeFoldable}; use rustc_session::{DiagnosticMessageId, Limit}; use rustc_span::def_id::LOCAL_CRATE; diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 70816b5722b..f135f0c1b13 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -9,7 +9,6 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, Quer use rustc_middle::traits::query::Fallible; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; -use rustc_middle::ty::WithConstness; use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_span::{Span, DUMMY_SP}; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 54f7b91080d..3642aebaec2 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -370,12 +370,17 @@ impl AutoTraitFinder<'tcx> { computed_preds.clone().chain(user_computed_preds.iter().cloned()), ) .map(|o| o.predicate); - new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal()); + new_env = ty::ParamEnv::new( + tcx.mk_predicates(normalized_preds), + param_env.reveal(), + param_env.constness(), + ); } let final_user_env = ty::ParamEnv::new( tcx.mk_predicates(user_computed_preds.into_iter()), user_env.reveal(), + user_env.constness(), ); debug!( "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 645295d4839..310eecc6e85 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{ self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, - TypeFoldable, WithConstness, + TypeFoldable, }; use rustc_session::DiagnosticMessageId; use rustc_span::symbol::{kw, sym}; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index db76ade296b..286c9c9900b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -21,7 +21,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, - Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, + Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_session::Limit; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e121837c987..8a60f9b8602 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -4,7 +4,6 @@ use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_errors::ErrorReported; -use rustc_hir as hir; use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::abstract_const::NotConstEvaluatable; @@ -231,21 +230,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() } - fn select_all_with_constness_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - constness: rustc_hir::Constness, - ) -> Vec> { - { - let errors = self.select_with_constness_where_possible(infcx, constness); - if !errors.is_empty() { - return errors; - } - } - - self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() - } - fn select_where_possible( &mut self, infcx: &InferCtxt<'_, 'tcx>, @@ -254,15 +238,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.select(&mut selcx) } - fn select_with_constness_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - constness: hir::Constness, - ) -> Vec> { - let mut selcx = SelectionContext::with_constness(infcx, constness); - self.select(&mut selcx) - } - fn pending_obligations(&self) -> Vec> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } @@ -679,12 +654,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { if obligation.predicate.is_known_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - // - // If the predicate is considered const, then we cannot use this because - // it will cause false negatives in the ui tests. - if !self.selcx.is_predicate_const(obligation.predicate) - && infcx.predicate_must_hold_considering_regions(obligation) - { + if infcx.predicate_must_hold_considering_regions(obligation) { debug!( "selecting trait at depth {} evaluated to holds", obligation.recursion_depth @@ -738,12 +708,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { if obligation.predicate.is_global(tcx) { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - // - // If the predicate is considered const, then we cannot use this because - // it will cause false negatives in the ui tests. - if !self.selcx.is_predicate_const(obligation.predicate) - && self.selcx.infcx().predicate_must_hold_considering_regions(obligation) - { + if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) { return ProcessResult::Changed(vec![]); } else { tracing::debug!("Does NOT hold: {:?}", obligation); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4bc22d5d735..d81b6949cae 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -33,8 +33,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{ - self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness, - COMMON_VTABLE_ENTRIES, + self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, COMMON_VTABLE_ENTRIES, }; use rustc_span::{sym, Span}; use smallvec::SmallVec; @@ -307,8 +306,11 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = - ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()); + let elaborated_env = ty::ParamEnv::new( + tcx.intern_predicates(&predicates), + unnormalized_env.reveal(), + unnormalized_env.constness(), + ); // HACK: we are trying to normalize the param-env inside *itself*. The problem is that // normalization expects its param-env to be already normalized, which means we have @@ -360,8 +362,11 @@ pub fn normalize_param_env_or_error<'tcx>( // predicates here anyway. Keeping them here anyway because it seems safer. let outlives_env: Vec<_> = non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); - let outlives_env = - ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal()); + let outlives_env = ty::ParamEnv::new( + tcx.intern_predicates(&outlives_env), + unnormalized_env.reveal(), + unnormalized_env.constness(), + ); let outlives_predicates = match do_normalize_predicates( tcx, region_context, @@ -381,7 +386,11 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates = non_outlives_predicates; predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()) + ty::ParamEnv::new( + tcx.intern_predicates(&predicates), + unnormalized_env.reveal(), + unnormalized_env.constness(), + ) } pub fn fully_normalize<'a, 'tcx, T>( @@ -564,14 +573,17 @@ fn prepare_vtable_segments<'tcx, T>( .predicates .into_iter() .filter_map(move |(pred, _)| { - pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_ref() + pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred() }); 'diving_in_skip_visited_traits: loop { if let Some(next_super_trait) = direct_super_traits_iter.next() { if visited.insert(next_super_trait.to_predicate(tcx)) { + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref); stack.push(( - next_super_trait.value, + next_super_trait, emit_vptr_on_new_entry, Some(direct_super_traits_iter), )); @@ -603,7 +615,11 @@ fn prepare_vtable_segments<'tcx, T>( if let Some(siblings) = siblings_opt { if let Some(next_inner_most_trait_ref) = siblings.next() { if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) { - *inner_most_trait_ref = next_inner_most_trait_ref.value; + // We're throwing away potential constness of super traits here. + // FIXME: handle ~const super traits + let next_inner_most_trait_ref = + next_inner_most_trait_ref.map_bound(|t| t.trait_ref); + *inner_most_trait_ref = next_inner_most_trait_ref; *emit_vptr = emit_vptr_on_new_entry; break 'exiting_out; } else { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 2ad8dc82a84..c9afd93af71 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -18,7 +18,7 @@ use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; @@ -694,7 +694,11 @@ fn receiver_is_dispatchable<'tcx>( let caller_bounds: Vec> = 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 U]> diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 4a23206402e..2ebbfa5aa11 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -28,7 +28,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 2fa6c0c0259..4874ba6f58c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,3 +1,5 @@ +use rustc_middle::ty; + use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::{ @@ -64,10 +66,21 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { let mut _orig_values = OriginalQueryValues::default(); - let c_pred = self.canonicalize_query_keep_static( - obligation.param_env.and(obligation.predicate), - &mut _orig_values, - ); + + let param_env = match obligation.predicate.kind().skip_binder() { + 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 // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 02e9b4d0f0e..081308ac73e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -30,8 +30,14 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { fn perform_query( tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, + mut canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, ) -> Fallible> { + 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) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 4d9559c96af..017f47d4357 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -11,7 +11,7 @@ use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable}; use rustc_target::spec::abi::Abi; use crate::traits; @@ -303,7 +303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if lang_items.drop_trait() == Some(def_id) && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst { - if self.is_in_const_context { + if obligation.param_env.constness() == hir::Constness::Const { self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?; } else { debug!("passing ~const Drop bound; in non-const context"); @@ -381,17 +381,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .param_env .caller_bounds() .iter() - .filter_map(|o| o.to_opt_poly_trait_ref()); + .filter_map(|o| o.to_opt_poly_trait_pred()); // Micro-optimization: filter out predicates relating to different traits. let matching_bounds = - all_bounds.filter(|p| p.value.def_id() == stack.obligation.predicate.def_id()); + all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); // Keep only those bounds which may apply, and propagate overflow if it occurs. for bound in matching_bounds { - let wc = self.evaluate_where_clause(stack, bound.value)?; + // FIXME(oli-obk): it is suspicious that we are dropping the constness and + // polarity here. + let wc = self.evaluate_where_clause(stack, bound.map_bound(|t| t.trait_ref))?; if wc.may_apply() { - candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity()))); + candidates.vec.push(ParamCandidate(bound)); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2f1f7971a79..e9b368f683e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{self, Ty}; -use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness}; +use rustc_middle::ty::{ToPolyTraitRef, ToPredicate}; use rustc_span::def_id::DefId; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; @@ -58,8 +58,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param.0.value); - Ok(ImplSource::Param(obligations, param.0.constness)) + let obligations = + self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); + Ok(ImplSource::Param(obligations, param.skip_binder().constness)) } ImplCandidate(impl_def_id) => { @@ -139,7 +140,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); let placeholder_trait_predicate = - self.infcx().replace_bound_vars_with_placeholders(trait_predicate); + self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref; let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { @@ -150,8 +151,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs); let candidate = candidate_predicate - .to_opt_poly_trait_ref() - .expect("projection candidate is not a trait predicate"); + .to_opt_poly_trait_pred() + .expect("projection candidate is not a trait predicate") + .map_bound(|t| t.trait_ref); let mut obligations = Vec::new(); let candidate = normalize_with_depth_to( self, @@ -165,7 +167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value) + .sup(placeholder_trait_predicate, candidate) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 32d04b55754..2b120e855eb 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -39,7 +39,6 @@ use rustc_middle::ty::fast_reject; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; -use rustc_middle::ty::WithConstness; use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::sym; @@ -128,9 +127,6 @@ pub struct SelectionContext<'cx, 'tcx> { /// and a negative impl allow_negative_impls: bool, - /// Are we in a const context that needs `~const` bounds to be const? - is_in_const_context: bool, - /// The mode that trait queries run in, which informs our error handling /// policy. In essence, canonicalized queries need their errors propagated /// rather than immediately reported because we do not have accurate spans. @@ -141,9 +137,9 @@ pub struct SelectionContext<'cx, 'tcx> { struct TraitObligationStack<'prev, 'tcx> { obligation: &'prev TraitObligation<'tcx>, - /// The trait ref from `obligation` but "freshened" with the + /// The trait predicate from `obligation` but "freshened" with the /// selection-context's freshener. Used to check for recursion. - fresh_trait_ref: ty::ConstnessAnd>, + fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, /// Starts out equal to `depth` -- if, during evaluation, we /// encounter a cycle, then we will set this flag to the minimum @@ -222,7 +218,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { intercrate: false, intercrate_ambiguity_causes: None, allow_negative_impls: false, - is_in_const_context: false, query_mode: TraitQueryMode::Standard, } } @@ -234,7 +229,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { intercrate: true, intercrate_ambiguity_causes: None, allow_negative_impls: false, - is_in_const_context: false, query_mode: TraitQueryMode::Standard, } } @@ -250,7 +244,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { intercrate: false, intercrate_ambiguity_causes: None, allow_negative_impls, - is_in_const_context: false, query_mode: TraitQueryMode::Standard, } } @@ -266,26 +259,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { intercrate: false, intercrate_ambiguity_causes: None, allow_negative_impls: false, - is_in_const_context: false, query_mode, } } - pub fn with_constness( - infcx: &'cx InferCtxt<'cx, 'tcx>, - constness: hir::Constness, - ) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx, - freshener: infcx.freshener_keep_static(), - intercrate: false, - intercrate_ambiguity_causes: None, - allow_negative_impls: false, - is_in_const_context: matches!(constness, hir::Constness::Const), - query_mode: TraitQueryMode::Standard, - } - } - /// Enables tracking of intercrate ambiguity causes. These are /// used in coherence to give improved diagnostics. We don't do /// this until we detect a coherence error because it can lead to @@ -318,20 +295,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.intercrate } - /// Returns `true` if the trait predicate is considerd `const` to this selection context. - pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool { - matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context - } - - /// Returns `true` if the predicate is considered `const` to - /// this selection context. - pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool { - match pred.kind().skip_binder() { - ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred), - _ => false, - } - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -716,20 +679,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let stack = self.push_stack(previous_stack, &obligation); - let fresh_trait_ref = stack.fresh_trait_ref; + let mut fresh_trait_pred = stack.fresh_trait_pred; + let mut param_env = obligation.param_env; - debug!(?fresh_trait_ref); + fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { + param_env = param_env.with_constness(pred.constness.and(param_env.constness())); + pred + }); - if let Some(result) = self.check_evaluation_cache( - obligation.param_env, - fresh_trait_ref, - obligation.polarity(), - ) { + debug!(?fresh_trait_pred); + + if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) { debug!(?result, "CACHE HIT"); return Ok(result); } - if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) { + if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) { debug!(?result, "PROVISIONAL CACHE HIT"); stack.update_reached_depth(result.reached_depth); return Ok(result.result); @@ -754,19 +719,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let reached_depth = stack.reached_depth.get(); if reached_depth >= stack.depth { debug!(?result, "CACHE MISS"); - self.insert_evaluation_cache( - obligation.param_env, - fresh_trait_ref, - obligation.polarity(), - dep_node, - result, - ); + self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); - stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| { + stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| { self.insert_evaluation_cache( - obligation.param_env, - fresh_trait_ref, - obligation.polarity(), + param_env, + fresh_trait_pred, dep_node, provisional_result.max(result), ); @@ -776,10 +734,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!( "caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", - fresh_trait_ref, stack.depth, reached_depth, + fresh_trait_pred, stack.depth, reached_depth, ); - stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result); + stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result); } Ok(result) @@ -813,7 +771,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .skip(1) // Skip top-most frame. .find(|prev| { stack.obligation.param_env == prev.obligation.param_env - && stack.fresh_trait_ref == prev.fresh_trait_ref + && stack.fresh_trait_pred == prev.fresh_trait_pred }) .map(|stack| stack.depth) { @@ -876,7 +834,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // terms of `Fn` etc, but we could probably make this more // precise still. let unbound_input_types = - stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh()); + stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh()); if stack.obligation.polarity() != ty::ImplPolarity::Negative { // This check was an imperfect workaround for a bug in the old @@ -914,8 +872,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { && stack.iter().skip(1).any(|prev| { stack.obligation.param_env == prev.obligation.param_env && self.match_fresh_trait_refs( - stack.fresh_trait_ref, - prev.fresh_trait_ref, + stack.fresh_trait_pred, + prev.fresh_trait_pred, prev.obligation.param_env, ) }) @@ -993,7 +951,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // not just the lifetime choice for this particular (non-erased) // predicate. // See issue #80691 - if stack.fresh_trait_ref.has_erased_regions() { + if stack.fresh_trait_pred.has_erased_regions() { result = result.max(EvaluatedToOkModuloRegions); } @@ -1004,8 +962,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn check_evaluation_cache( &self, param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::ConstnessAnd>, - polarity: ty::ImplPolarity, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option { // Neither the global nor local cache is aware of intercrate // 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(); 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(¶m_env.and(trait_pred), tcx) { return Some(res); } } - self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx) + self.infcx.evaluation_cache.get(¶m_env.and(trait_pred), tcx) } fn insert_evaluation_cache( &mut self, param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::ConstnessAnd>, - polarity: ty::ImplPolarity, + trait_pred: ty::PolyTraitPredicate<'tcx>, dep_node: DepNodeIndex, result: EvaluationResult, ) { @@ -1048,23 +1003,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if self.can_use_global_caches(param_env) { - if !trait_ref.needs_infer() { - debug!(?trait_ref, ?result, "insert_evaluation_cache global"); + if !trait_pred.needs_infer() { + debug!(?trait_pred, ?result, "insert_evaluation_cache global"); // This may overwrite the cache with the same value // FIXME: Due to #50507 this overwrites the different values // This should be changed to use HashMapExt::insert_same // when that is fixed - self.tcx().evaluation_cache.insert( - (param_env.and(trait_ref), polarity), - dep_node, - result, - ); + self.tcx().evaluation_cache.insert(param_env.and(trait_pred), dep_node, result); return; } } - debug!(?trait_ref, ?result, "insert_evaluation_cache"); - self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result); + debug!(?trait_pred, ?result, "insert_evaluation_cache"); + self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result); } /// For various reasons, it's possible for a subobligation @@ -1142,16 +1093,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for candidate in candidates { // Respect const trait obligations - if self.is_trait_predicate_const(obligation.predicate.skip_binder()) { + if obligation.is_const() { match candidate { // const impl ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {} // const param - ParamCandidate(( - ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. }, - _, - )) => {} + ParamCandidate(trait_pred) + if trait_pred.skip_binder().constness + == ty::BoundConstness::ConstIfConst => {} // auto trait impl AutoImplCandidate(..) => {} // generator, this will raise error in other places @@ -1260,7 +1210,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn check_candidate_cache( &mut self, - param_env: ty::ParamEnv<'tcx>, + mut param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option>> { // Neither the global nor local cache is aware of intercrate @@ -1271,19 +1221,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return None; } let tcx = self.tcx(); - let pred = &cache_fresh_trait_pred.skip_binder(); - let trait_ref = pred.trait_ref; + let mut pred = cache_fresh_trait_pred.skip_binder(); + param_env = param_env.with_constness(pred.constness.and(param_env.constness())); + if self.can_use_global_caches(param_env) { - if let Some(res) = tcx - .selection_cache - .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx) - { + if let Some(res) = tcx.selection_cache.get(¶m_env.and(pred), tcx) { return Some(res); } } - self.infcx - .selection_cache - .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx) + self.infcx.selection_cache.get(¶m_env.and(pred), tcx) } /// Determines whether can we safely cache the result @@ -1321,43 +1267,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn insert_candidate_cache( &mut self, - param_env: ty::ParamEnv<'tcx>, + mut param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, dep_node: DepNodeIndex, candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) { let tcx = self.tcx(); - let pred = cache_fresh_trait_pred.skip_binder(); - let trait_ref = pred.trait_ref; + let mut pred = cache_fresh_trait_pred.skip_binder(); + + param_env = param_env.with_constness(pred.constness.and(param_env.constness())); if !self.can_cache_candidate(&candidate) { - debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable"); + debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); return; } if self.can_use_global_caches(param_env) { if let Err(Overflow) = candidate { // Don't cache overflow globally; we only produce this in certain modes. - } else if !trait_ref.needs_infer() { + } else if !pred.needs_infer() { if !candidate.needs_infer() { - debug!(?trait_ref, ?candidate, "insert_candidate_cache global"); + debug!(?pred, ?candidate, "insert_candidate_cache global"); // This may overwrite the cache with the same value. - tcx.selection_cache.insert( - (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), - dep_node, - candidate, - ); + tcx.selection_cache.insert(param_env.and(pred), dep_node, candidate); return; } } } - debug!(?trait_ref, ?candidate, "insert_candidate_cache local"); - self.infcx.selection_cache.insert( - (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), - dep_node, - candidate, - ); + debug!(?pred, ?candidate, "insert_candidate_cache local"); + self.infcx.selection_cache.insert(param_env.and(pred), dep_node, candidate); } /// Matches a predicate against the bounds of its self type. @@ -1548,7 +1487,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check if a bound would previously have been removed when normalizing // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. - let is_global = |cand: &ty::PolyTraitRef<'tcx>| { + let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| { cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions() }; @@ -1581,25 +1520,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ConstDropCandidate, ) => false, - ( - ParamCandidate((other, other_polarity)), - ParamCandidate((victim, victim_polarity)), - ) => { - let same_except_bound_vars = other.value.skip_binder() - == victim.value.skip_binder() - && other.constness == victim.constness - && other_polarity == victim_polarity - && !other.value.skip_binder().has_escaping_bound_vars(); + (ParamCandidate(other), ParamCandidate(victim)) => { + let same_except_bound_vars = other.skip_binder().trait_ref + == victim.skip_binder().trait_ref + && other.skip_binder().constness == victim.skip_binder().constness + && other.skip_binder().polarity == victim.skip_binder().polarity + && !other.skip_binder().trait_ref.has_escaping_bound_vars(); if same_except_bound_vars { // See issue #84398. In short, we can generate multiple ParamCandidates which are // the same except for unused bound vars. Just pick the one with the fewest bound vars // or the current one if tied (they should both evaluate to the same answer). This is // probably best characterized as a "hack", since we might prefer to just do our // best to *not* create essentially duplicate candidates in the first place. - other.value.bound_vars().len() <= victim.value.bound_vars().len() - } else if other.value == victim.value - && victim.constness == ty::BoundConstness::NotConst - && other_polarity == victim_polarity + other.bound_vars().len() <= victim.bound_vars().len() + } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref + && victim.skip_binder().constness == ty::BoundConstness::NotConst + && other.skip_binder().polarity == victim.skip_binder().polarity { // Drop otherwise equivalent non-const candidates in favor of const candidates. true @@ -1629,11 +1565,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitAliasCandidate(..) | ObjectCandidate(_) | ProjectionCandidate(_), - ) => !is_global(&cand.0.value), + ) => !is_global(cand), (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(&cand.0.value) + is_global(cand) } ( ImplCandidate(_) @@ -1649,7 +1585,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions() + is_global(cand) && other.evaluation.must_apply_modulo_regions() } (ProjectionCandidate(i), ProjectionCandidate(j)) @@ -2209,8 +2145,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_fresh_trait_refs( &self, - previous: ty::ConstnessAnd>, - current: ty::ConstnessAnd>, + previous: ty::PolyTraitPredicate<'tcx>, + current: ty::PolyTraitPredicate<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> bool { let mut matcher = ty::_match::Match::new(self.tcx(), param_env); @@ -2222,17 +2158,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &'o TraitObligation<'tcx>, ) -> TraitObligationStack<'o, 'tcx> { - let fresh_trait_ref = obligation - .predicate - .to_poly_trait_ref() - .fold_with(&mut self.freshener) - .with_constness(obligation.predicate.skip_binder().constness); + let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener); let dfn = previous_stack.cache.next_dfn(); let depth = previous_stack.depth() + 1; TraitObligationStack { obligation, - fresh_trait_ref, + fresh_trait_pred, reached_depth: Cell::new(depth), previous: previous_stack, dfn, @@ -2426,7 +2358,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { debug!(reached_depth, "update_reached_depth"); let mut p = self; while reached_depth < p.depth { - debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant"); + debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant"); p.reached_depth.set(p.reached_depth.get().min(reached_depth)); p = p.previous.head.unwrap(); } @@ -2505,7 +2437,7 @@ struct ProvisionalEvaluationCache<'tcx> { /// - then we determine that `E` is in error -- we will then clear /// all cache values whose DFN is >= 4 -- in this case, that /// means the cached value for `F`. - map: RefCell>, ProvisionalEvaluation>>, + map: RefCell, ProvisionalEvaluation>>, } /// 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). fn get_provisional( &self, - fresh_trait_ref: ty::ConstnessAnd>, + fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option { debug!( - ?fresh_trait_ref, + ?fresh_trait_pred, "get_provisional = {:#?}", - self.map.borrow().get(&fresh_trait_ref), + self.map.borrow().get(&fresh_trait_pred), ); - Some(*self.map.borrow().get(&fresh_trait_ref)?) + Some(*self.map.borrow().get(&fresh_trait_pred)?) } /// Insert a provisional result into the cache. The result came /// from the node with the given DFN. It accessed a minimum depth - /// of `reached_depth` to compute. It evaluated `fresh_trait_ref` + /// of `reached_depth` to compute. It evaluated `fresh_trait_pred` /// and resulted in `result`. fn insert_provisional( &self, from_dfn: usize, reached_depth: usize, - fresh_trait_ref: ty::ConstnessAnd>, + fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, result: EvaluationResult, ) { - debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional"); + debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional"); let mut map = self.map.borrow_mut(); @@ -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 @@ -2633,16 +2565,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { fn on_completion( &self, dfn: usize, - mut op: impl FnMut(ty::ConstnessAnd>, EvaluationResult), + mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult), ) { debug!(?dfn, "on_completion"); - for (fresh_trait_ref, eval) in + for (fresh_trait_pred, eval) in self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn) { - debug!(?fresh_trait_ref, ?eval, "on_completion"); + debug!(?fresh_trait_pred, ?eval, "on_completion"); - op(fresh_trait_ref, eval.result); + op(fresh_trait_pred, eval.result); } } } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b64c5559227..ab732f510ff 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -508,9 +508,9 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option TraitAliasExpander<'tcx> { let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { pred.subst_supertrait(tcx, &trait_ref) - .to_opt_poly_trait_ref() - .map(|trait_ref| item.clone_and_push(trait_ref.value, *span)) + .to_opt_poly_trait_pred() + .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) }); debug!("expand_trait_aliases: items={:?}", items.clone()); @@ -183,8 +183,8 @@ impl Iterator for SupertraitDefIds<'tcx> { predicates .predicates .iter() - .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref()) - .map(|trait_ref| trait_ref.value.def_id()) + .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred()) + .map(|trait_ref| trait_ref.def_id()) .filter(|&super_def_id| visited.insert(super_def_id)), ); Some(def_id) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 2a66684e2a2..5875b764e9f 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use std::iter; @@ -298,9 +298,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let extend = |obligation: traits::PredicateObligation<'tcx>| { let mut cause = cause.clone(); - if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() { + if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() { let derived_cause = traits::DerivedObligationCause { - parent_trait_ref: parent_trait_ref.value, + // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate + parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref), parent_code: Lrc::new(obligation.cause.code.clone()), }; cause.make_mut().code = diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 74a015d4c34..a2d14545916 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -2,9 +2,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{ - self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness, -}; +use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits; @@ -282,16 +280,79 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // issue #89334 predicates = tcx.expose_default_const_substs(predicates); - let unnormalized_env = - ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing); + let local_did = def_id.as_local(); + 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 body_id = def_id - .as_local() - .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) - .map_or(hir::CRATE_HIR_ID, |id| { - tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id) - }); + let constness = match hir_id { + Some(hir_id) => match tcx.hir().get(hir_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + 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); traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index dc52c49499a..752183365d6 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1587,7 +1587,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { traits::transitive_bounds_that_define_assoc_type( tcx, 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, ) diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 24474e163b9..8bc3a48e5b5 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -1,7 +1,7 @@ //! Bounds are restrictions applied to some types after they've been converted into the //! `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; /// Collects together a list of type bounds. These lists of bounds occur in many places diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 4e06608be5d..5a6bac9ec03 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -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 }); } -pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_item_well_formed(tcx, def_id); -} +pub(super) use wfcheck::check_item_well_formed; -pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_trait_item(tcx, def_id); -} +pub(super) use wfcheck::check_trait_item as check_trait_item_well_formed; -pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_impl_item(tcx, def_id); -} +pub(super) use wfcheck::check_impl_item as check_impl_item_well_formed; 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") diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 4a41552a5fb..c87ab0d410c 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generator_types = check_fn( self, - self.param_env, + self.param_env.without_const(), liberated_sig, decl, expr.hir_id, diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 6af0312f313..11560f51822 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -208,8 +208,11 @@ fn compare_predicate_entailment<'tcx>( // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id); - let param_env = - ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); + let param_env = ty::ParamEnv::new( + tcx.intern_predicates(&hybrid_preds.predicates), + Reveal::UserFacing, + hir::Constness::NotConst, + ); let param_env = 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); let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); - let param_env = - ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); + let param_env = ty::ParamEnv::new( + tcx.intern_predicates(&hybrid_preds.predicates), + Reveal::UserFacing, + hir::Constness::NotConst, + ); let param_env = traits::normalize_param_env_or_error( tcx, impl_ty.def_id, @@ -1353,7 +1359,11 @@ pub fn check_type_bounds<'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); @@ -1362,13 +1372,7 @@ pub fn check_type_bounds<'tcx>( impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); tcx.infer_ctxt().enter(move |infcx| { - let constness = impl_ty - .container - .impl_def_id() - .map(|did| tcx.impl_constness(did)) - .unwrap_or(hir::Constness::NotConst); - - let inh = Inherited::with_constness(infcx, impl_ty.def_id.expect_local(), constness); + let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); let infcx = &inh.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 // version. - let errors = - inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness); + let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); return Err(ErrorReported); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e82ff9cf2dd..280a39e7b3e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -616,10 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(in super::super) fn select_all_obligations_or_error(&self) { - let errors = self - .fulfillment_cx - .borrow_mut() - .select_all_with_constness_or_error(&self, self.inh.constness); + let errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self); if !errors.is_empty() { self.report_fulfillment_errors(&errors, self.inh.body_id, false); @@ -632,10 +629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fallback_has_occurred: bool, mutate_fulfillment_errors: impl Fn(&mut Vec>), ) { - let mut result = self - .fulfillment_cx - .borrow_mut() - .select_with_constness_where_possible(self, self.inh.constness); + let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self); if !result.is_empty() { mutate_fulfillment_errors(&mut result); self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred); diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index f7552c1f4eb..bf52e775043 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -53,9 +53,6 @@ pub struct Inherited<'a, 'tcx> { pub(super) deferred_generator_interiors: RefCell, hir::GeneratorKind)>>, - /// Reports whether this is in a const context. - pub(super) constness: hir::Constness, - pub(super) body_id: Option, /// Whenever we introduce an adjustment from `!` into a type variable, @@ -102,16 +99,6 @@ impl<'tcx> InheritedBuilder<'tcx> { impl Inherited<'a, 'tcx> { 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 item_id = tcx.hir().local_def_id_to_hir_id(def_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_generator_interiors: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), - constness, body_id, } } diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index dbc1d4ec193..03518dc8d12 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -22,7 +22,7 @@ use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; 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::Span; use rustc_trait_selection::traits; diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 9ccf354db73..dc724396094 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; 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_span::def_id::LocalDefId; use rustc_span::lev_distance::{find_best_match_for_name, lev_distance}; diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index e9ec0674cb7..45b8e13d328 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::fast_reject::simplify_type; 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::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol}; diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 10fa9e0cff5..3fd3284d8b1 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -21,7 +21,6 @@ use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, - WithConstness, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 1334328f4e2..ea86bafffb3 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -41,7 +41,7 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; 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::parse::feature_err; use rustc_span::symbol::{kw, sym, Ident, Symbol}; diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 5aa53deee34..1c2e673d604 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -534,9 +534,10 @@ where // From implies Into #[stable(feature = "rust1", since = "1.0.0")] -impl Into for T +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] +impl const Into for T where - U: From, + U: ~const From, { fn into(self) -> U { U::from(self) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d9a40a9b2ec..04996368064 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -112,6 +112,7 @@ #![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] #![feature(const_heap)] +#![feature(const_convert)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] #![feature(const_intrinsic_copy)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index a6e7257448c..381e2d6eed3 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2077,7 +2077,8 @@ impl> FromIterator> for Option { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::Try for Option { +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] +impl const ops::Try for Option { type Output = T; type Residual = Option; @@ -2096,6 +2097,7 @@ impl ops::Try for Option { } #[unstable(feature = "try_trait_v2", issue = "84277")] +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const ops::FromResidual for Option { #[inline] fn from_residual(residual: Option) -> Self { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index ab067d57d08..8ef5ffb962b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1945,7 +1945,8 @@ impl> FromIterator> for Result { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::Try for Result { +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] +impl const ops::Try for Result { type Output = T; type Residual = Result; @@ -1964,7 +1965,10 @@ impl ops::Try for Result { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl> ops::FromResidual> for Result { +#[rustc_const_unstable(feature = "const_convert", issue = "88674")] +impl> const ops::FromResidual> + for Result +{ #[inline] fn from_residual(residual: Result) -> Self { match residual { diff --git a/library/core/tests/convert.rs b/library/core/tests/convert.rs new file mode 100644 index 00000000000..f1048f4cf09 --- /dev/null +++ b/library/core/tests/convert.rs @@ -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) -> Vec { + x.into() + } + + const BAR: Vec = into(Vec::new()); + assert_eq!(BAR, Vec::::new()); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 012e6e5b57a..b41d3e09df8 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -12,11 +12,11 @@ #![feature(const_convert)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_num_from_num)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_ptr_offset)] #![feature(const_trait_impl)] -#![feature(const_num_from_num)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -96,6 +96,7 @@ mod char; mod clone; mod cmp; mod const_ptr; +mod convert; mod fmt; mod future; mod hash; diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 80e3bb5c662..dca02cb25bd 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_infer::infer::{InferOk, TyCtxtInferExt}; use rustc_infer::traits; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{ToPredicate, WithConstness}; +use rustc_middle::ty::ToPredicate; use rustc_span::DUMMY_SP; use super::*; @@ -66,7 +66,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .into_iter() .chain(Some( ty::Binder::dummy(trait_ref) - .without_const() + .to_poly_trait_predicate() + .map_bound(ty::PredicateKind::Trait) .to_predicate(infcx.tcx), )); for predicate in predicates { diff --git a/src/test/ui/consts/not_const_clusure_in_const.rs b/src/test/ui/consts/not_const_clusure_in_const.rs deleted file mode 100644 index fd2cfa442d3..00000000000 --- a/src/test/ui/consts/not_const_clusure_in_const.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - -const _FOO: fn() -> String = || "foo".into(); - -pub fn bar() -> fn() -> String { - || "bar".into() -} - -fn main(){} diff --git a/src/test/ui/consts/try-operator.rs b/src/test/ui/consts/try-operator.rs new file mode 100644 index 00000000000..fe43b132cbd --- /dev/null +++ b/src/test/ui/consts/try-operator.rs @@ -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 { + Err(())?; + Ok(true) + } + + const FOO: Result = result(); + assert_eq!(Err(()), FOO); + + const fn option() -> Option<()> { + None?; + Some(()) + } + const BAR: Option<()> = option(); + assert_eq!(None, BAR); +} diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr index 369645f9030..383e13fd4b0 100644 --- a/src/test/ui/infinite/infinite-struct.stderr +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -19,7 +19,7 @@ LL | struct Take(Take); | ^^^^^^^^^^^^^^^^^^ | = 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 diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 61b5e946775..1802c7599a3 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | = 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 diff --git a/src/test/ui/issues/issue-91489.rs b/src/test/ui/issues/issue-91489.rs new file mode 100644 index 00000000000..f028a4a3c6a --- /dev/null +++ b/src/test/ui/issues/issue-91489.rs @@ -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 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() +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs index 228b5ed71e8..7b012083c5a 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs @@ -1,6 +1,5 @@ // FIXME(fee1-dead): this should have a better error message #![feature(const_trait_impl)] - struct NonConstAdd(i32); impl std::ops::Add for NonConstAdd { diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr index 842b99edbe7..4a4b4de4758 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr @@ -1,12 +1,12 @@ error[E0277]: cannot add `NonConstAdd` to `NonConstAdd` - --> $DIR/assoc-type.rs:19:16 + --> $DIR/assoc-type.rs:18:16 | LL | type Bar = NonConstAdd; | ^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd` | = help: the trait `Add` is not implemented for `NonConstAdd` 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; | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar` diff --git a/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs b/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs new file mode 100644 index 00000000000..ef74ef8e426 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +trait Convert { + fn to(self) -> T; +} + +impl const Convert for A where B: ~const From { + fn to(self) -> B { + B::from(self) + } +} + +const FOO: fn() -> String = || "foo".to(); + +fn main() {} diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index fefdcfed42f..43911a313d5 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -68,8 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let mut is_future = false; for &(p, _span) in preds { let p = p.subst(cx.tcx, subst); - if let Some(trait_ref) = p.to_opt_poly_trait_ref() { - if Some(trait_ref.value.def_id()) == cx.tcx.lang_items().future_trait() { + if let Some(trait_pred) = p.to_opt_poly_trait_pred() { + if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; break; }