diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index b502590c1bfb9..6fbab0ef29907 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -9,7 +9,6 @@ use crate::infer::canonical::{ Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues, }; use crate::infer::InferCtxt; -use rustc_middle::ty::flags::FlagComputation; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; @@ -550,8 +549,11 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { _ => {} } - let flags = FlagComputation::for_const(ct); - if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct } + if ct.flags().intersects(self.needs_canonical_flags) { + ct.super_fold_with(self) + } else { + ct + } } } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 5735c5568f79f..9b41b77928e67 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -94,7 +94,7 @@ macro_rules! arena_types { // Interned types [] tys: rustc_type_ir::WithCachedTypeInfo>, - [] consts: rustc_middle::ty::ConstData<'tcx>, + [] consts: rustc_type_ir::WithCachedTypeInfo>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index c46ab99235927..0f5817c78e0a6 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -7,6 +7,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_macros::HashStable; +use rustc_type_ir::{TypeFlags, WithCachedTypeInfo}; mod int; mod kind; @@ -23,7 +24,7 @@ use super::sty::ConstKind; /// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>); +pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo>>); /// Typed constant value. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)] @@ -46,6 +47,16 @@ impl<'tcx> Const<'tcx> { self.0.kind.clone() } + #[inline] + pub fn flags(self) -> TypeFlags { + self.0.flags + } + + #[inline] + pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { + self.0.outer_exclusive_binder + } + #[inline] pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { tcx.mk_ct_from_kind(kind, ty) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 62b0536dabee6..3e24b7cce867c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -151,7 +151,7 @@ pub struct CtxtInterners<'tcx> { clauses: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, - const_: InternedSet<'tcx, ConstData<'tcx>>, + const_: InternedSet<'tcx, WithCachedTypeInfo>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List>, layout: InternedSet<'tcx, LayoutS>, @@ -212,6 +212,32 @@ impl<'tcx> CtxtInterners<'tcx> { )) } + /// Interns a const. (Use `mk_*` functions instead, where possible.) + #[allow(rustc::usage_of_ty_tykind)] + #[inline(never)] + fn intern_const( + &self, + data: ty::ConstData<'tcx>, + sess: &Session, + untracked: &Untracked, + ) -> Const<'tcx> { + Const(Interned::new_unchecked( + self.const_ + .intern(data, |data: ConstData<'_>| { + let flags = super::flags::FlagComputation::for_const(&data.kind, data.ty); + let stable_hash = self.stable_hash(&flags, sess, untracked, &data); + + InternedInSet(self.arena.alloc(WithCachedTypeInfo { + internee: data, + stable_hash, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + })) + }) + .0, + )) + } + fn stable_hash<'a, T: HashStable>>( &self, flags: &ty::flags::FlagComputation, @@ -418,11 +444,17 @@ impl<'tcx> CommonLifetimes<'tcx> { } impl<'tcx> CommonConsts<'tcx> { - fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> { + fn new( + interners: &CtxtInterners<'tcx>, + types: &CommonTypes<'tcx>, + sess: &Session, + untracked: &Untracked, + ) -> CommonConsts<'tcx> { let mk_const = |c| { - Const(Interned::new_unchecked( - interners.const_.intern(c, |c| InternedInSet(interners.arena.alloc(c))).0, - )) + interners.intern_const( + c, sess, // This is only used to create a stable hashing context. + untracked, + ) }; CommonConsts { @@ -714,7 +746,7 @@ impl<'tcx> TyCtxt<'tcx> { let interners = CtxtInterners::new(arena); let common_types = CommonTypes::new(&interners, s, &untracked); let common_lifetimes = CommonLifetimes::new(&interners); - let common_consts = CommonConsts::new(&interners, &common_types); + let common_consts = CommonConsts::new(&interners, &common_types, s, &untracked); GlobalCtxt { sess: s, @@ -1533,7 +1565,6 @@ macro_rules! direct_interners { // crate only, and have a corresponding `mk_` function. direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, - const_: intern_const(ConstData<'tcx>): Const -> Const<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, @@ -1710,7 +1741,12 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - self.intern_const(ty::ConstData { kind, ty }) + self.interners.intern_const( + ty::ConstData { kind, ty }, + self.sess, + // This is only used to create a stable hashing context. + &self.untracked, + ) } // Avoid this in favour of more specific `Ty::new_*` methods, where possible. diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index cd9b429ec56c7..5084fc9891349 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -28,10 +28,11 @@ impl FlagComputation { result } - pub fn for_const(c: ty::Const<'_>) -> TypeFlags { + pub fn for_const(c: &ty::ConstKind<'_>, t: Ty<'_>) -> FlagComputation { let mut result = FlagComputation::new(); - result.add_const(c); - result.flags + result.add_const_kind(c); + result.add_ty(t); + result } fn add_flags(&mut self, flags: TypeFlags) { @@ -297,8 +298,12 @@ impl FlagComputation { } fn add_const(&mut self, c: ty::Const<'_>) { - self.add_ty(c.ty()); - match c.kind() { + self.add_flags(c.flags()); + self.add_exclusive_binder(c.outer_exclusive_binder()); + } + + fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) { + match *c { ty::ConstKind::Unevaluated(uv) => { self.add_args(uv.args); self.add_flags(TypeFlags::HAS_CT_PROJECTION); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 0c658fa1c80f6..c1063d6a5f008 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -70,7 +70,7 @@ impl<'tcx> GenericArgKind<'tcx> { GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); - (CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize) + (CONST_TAG, ct.0.0 as *const WithCachedTypeInfo> as usize) } }; @@ -136,7 +136,7 @@ impl<'tcx> GenericArg<'tcx> { &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>), + &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), ))), _ => intrinsics::unreachable(), } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 56739ce96c306..90cc6f1fb921c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -900,7 +900,7 @@ impl<'tcx> Term<'tcx> { &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), ))), CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>), + &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), ))), _ => core::intrinsics::unreachable(), } @@ -967,7 +967,7 @@ impl<'tcx> TermKind<'tcx> { TermKind::Const(ct) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); - (CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize) + (CONST_TAG, ct.0.0 as *const WithCachedTypeInfo> as usize) } }; diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index f14232d34352b..e1ce941256c95 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,4 +1,4 @@ -use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; +use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use rustc_errors::ErrorGuaranteed; use rustc_data_structures::fx::FxHashSet; @@ -440,16 +440,15 @@ impl<'tcx> TypeVisitor> for HasEscapingVarsVisitor { } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { - // we don't have a `visit_infer_const` callback, so we have to - // hook in here to catch this case (annoying...), but - // otherwise we do want to remember to visit the rest of the - // const, as it has types/regions embedded in a lot of other - // places. - match ct.kind() { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { - ControlFlow::Break(FoundEscapingVars) - } - _ => ct.super_visit_with(self), + // If the outer-exclusive-binder is *strictly greater* than + // `outer_index`, that means that `ct` contains some content + // bound at `outer_index` or above (because + // `outer_exclusive_binder` is always 1 higher than the + // content in `t`). Therefore, `t` has some escaping vars. + if ct.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::Continue(()) } } @@ -529,9 +528,7 @@ impl<'tcx> TypeVisitor> for HasTypeFlagsVisitor { #[inline] fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { // Note: no `super_visit_with` call. - let flags = FlagComputation::for_const(c); - trace!(r.flags=?flags); - if flags.intersects(self.flags) { + if c.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { ControlFlow::Continue(()) diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index dba00ce0154bd..8faaa6be9f569 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -160,14 +160,12 @@ impl<'tcx> TypeVisitor> for MaxEscapingBoundVarVisitor { } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { - match ct.kind() { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { - self.escaping = - self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); - ControlFlow::Continue(()) - } - _ => ct.super_visit_with(self), + if ct.outer_exclusive_binder() > self.outer_index { + self.escaping = self + .escaping + .max(ct.outer_exclusive_binder().as_usize() - self.outer_index.as_usize()); } + ControlFlow::Continue(()) } }