Auto merge of #118189 - compiler-errors:cache-flags-for-const, r=nnethercote
Cache flags for `ty::Const` Not sure if this has been attempted yet, but worth a shot. It does make the code simpler in `rustc_type_ir`, since we can assume that consts have a `flags` method that is no-cost. r? `@ghost`
This commit is contained in:
commit
41fe75ec6b
9 changed files with 92 additions and 43 deletions
|
@ -9,7 +9,6 @@ use crate::infer::canonical::{
|
||||||
Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
|
Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
|
||||||
};
|
};
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use rustc_middle::ty::flags::FlagComputation;
|
|
||||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||||
use rustc_middle::ty::GenericArg;
|
use rustc_middle::ty::GenericArg;
|
||||||
use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
|
use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
|
||||||
|
@ -550,8 +549,11 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let flags = FlagComputation::for_const(ct);
|
if ct.flags().intersects(self.needs_canonical_flags) {
|
||||||
if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
|
ct.super_fold_with(self)
|
||||||
|
} else {
|
||||||
|
ct
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ macro_rules! arena_types {
|
||||||
|
|
||||||
// Interned types
|
// Interned types
|
||||||
[] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
|
[] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
|
||||||
[] consts: rustc_middle::ty::ConstData<'tcx>,
|
[] consts: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::ConstData<'tcx>>,
|
||||||
|
|
||||||
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
||||||
// since we need to allocate this type on both the `rustc_hir` arena
|
// since we need to allocate this type on both the `rustc_hir` arena
|
||||||
|
|
|
@ -7,6 +7,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
use rustc_type_ir::{TypeFlags, WithCachedTypeInfo};
|
||||||
|
|
||||||
mod int;
|
mod int;
|
||||||
mod kind;
|
mod kind;
|
||||||
|
@ -23,7 +24,7 @@ use super::sty::ConstKind;
|
||||||
/// Use this rather than `ConstData`, whenever possible.
|
/// Use this rather than `ConstData`, whenever possible.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
||||||
#[rustc_pass_by_value]
|
#[rustc_pass_by_value]
|
||||||
pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>);
|
pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>);
|
||||||
|
|
||||||
/// Typed constant value.
|
/// Typed constant value.
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||||
|
@ -46,6 +47,16 @@ impl<'tcx> Const<'tcx> {
|
||||||
self.0.kind.clone()
|
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]
|
#[inline]
|
||||||
pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||||
tcx.mk_ct_from_kind(kind, ty)
|
tcx.mk_ct_from_kind(kind, ty)
|
||||||
|
|
|
@ -151,7 +151,7 @@ pub struct CtxtInterners<'tcx> {
|
||||||
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
|
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
|
||||||
projs: InternedSet<'tcx, List<ProjectionKind>>,
|
projs: InternedSet<'tcx, List<ProjectionKind>>,
|
||||||
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
|
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
|
||||||
const_: InternedSet<'tcx, ConstData<'tcx>>,
|
const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
|
||||||
const_allocation: InternedSet<'tcx, Allocation>,
|
const_allocation: InternedSet<'tcx, Allocation>,
|
||||||
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
|
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
|
||||||
layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
|
layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
|
||||||
|
@ -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<StableHashingContext<'a>>>(
|
fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
|
||||||
&self,
|
&self,
|
||||||
flags: &ty::flags::FlagComputation,
|
flags: &ty::flags::FlagComputation,
|
||||||
|
@ -418,11 +444,17 @@ impl<'tcx> CommonLifetimes<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> CommonConsts<'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| {
|
let mk_const = |c| {
|
||||||
Const(Interned::new_unchecked(
|
interners.intern_const(
|
||||||
interners.const_.intern(c, |c| InternedInSet(interners.arena.alloc(c))).0,
|
c, sess, // This is only used to create a stable hashing context.
|
||||||
))
|
untracked,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
CommonConsts {
|
CommonConsts {
|
||||||
|
@ -714,7 +746,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
let interners = CtxtInterners::new(arena);
|
let interners = CtxtInterners::new(arena);
|
||||||
let common_types = CommonTypes::new(&interners, s, &untracked);
|
let common_types = CommonTypes::new(&interners, s, &untracked);
|
||||||
let common_lifetimes = CommonLifetimes::new(&interners);
|
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 {
|
GlobalCtxt {
|
||||||
sess: s,
|
sess: s,
|
||||||
|
@ -1533,7 +1565,6 @@ macro_rules! direct_interners {
|
||||||
// crate only, and have a corresponding `mk_` function.
|
// crate only, and have a corresponding `mk_` function.
|
||||||
direct_interners! {
|
direct_interners! {
|
||||||
region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
|
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>,
|
const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
|
||||||
layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
|
layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
|
||||||
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
|
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
|
||||||
|
@ -1710,7 +1741,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
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.
|
// Avoid this in favour of more specific `Ty::new_*` methods, where possible.
|
||||||
|
|
|
@ -28,10 +28,11 @@ impl FlagComputation {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_const(c: ty::Const<'_>) -> TypeFlags {
|
pub fn for_const(c: &ty::ConstKind<'_>, t: Ty<'_>) -> FlagComputation {
|
||||||
let mut result = FlagComputation::new();
|
let mut result = FlagComputation::new();
|
||||||
result.add_const(c);
|
result.add_const_kind(c);
|
||||||
result.flags
|
result.add_ty(t);
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_flags(&mut self, flags: TypeFlags) {
|
fn add_flags(&mut self, flags: TypeFlags) {
|
||||||
|
@ -297,8 +298,12 @@ impl FlagComputation {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_const(&mut self, c: ty::Const<'_>) {
|
fn add_const(&mut self, c: ty::Const<'_>) {
|
||||||
self.add_ty(c.ty());
|
self.add_flags(c.flags());
|
||||||
match c.kind() {
|
self.add_exclusive_binder(c.outer_exclusive_binder());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) {
|
||||||
|
match *c {
|
||||||
ty::ConstKind::Unevaluated(uv) => {
|
ty::ConstKind::Unevaluated(uv) => {
|
||||||
self.add_args(uv.args);
|
self.add_args(uv.args);
|
||||||
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
|
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
|
||||||
|
|
|
@ -70,7 +70,7 @@ impl<'tcx> GenericArgKind<'tcx> {
|
||||||
GenericArgKind::Const(ct) => {
|
GenericArgKind::Const(ct) => {
|
||||||
// Ensure we can use the tag bits.
|
// Ensure we can use the tag bits.
|
||||||
assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
|
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<ty::ConstData<'tcx>> as usize)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ impl<'tcx> GenericArg<'tcx> {
|
||||||
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
||||||
))),
|
))),
|
||||||
CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
|
CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
|
||||||
&*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>),
|
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::ConstData<'tcx>>),
|
||||||
))),
|
))),
|
||||||
_ => intrinsics::unreachable(),
|
_ => intrinsics::unreachable(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -900,7 +900,7 @@ impl<'tcx> Term<'tcx> {
|
||||||
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
||||||
))),
|
))),
|
||||||
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
|
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
|
||||||
&*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>),
|
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::ConstData<'tcx>>),
|
||||||
))),
|
))),
|
||||||
_ => core::intrinsics::unreachable(),
|
_ => core::intrinsics::unreachable(),
|
||||||
}
|
}
|
||||||
|
@ -967,7 +967,7 @@ impl<'tcx> TermKind<'tcx> {
|
||||||
TermKind::Const(ct) => {
|
TermKind::Const(ct) => {
|
||||||
// Ensure we can use the tag bits.
|
// Ensure we can use the tag bits.
|
||||||
assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
|
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<ty::ConstData<'tcx>> as usize)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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_errors::ErrorGuaranteed;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
@ -440,16 +440,15 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
// we don't have a `visit_infer_const` callback, so we have to
|
// If the outer-exclusive-binder is *strictly greater* than
|
||||||
// hook in here to catch this case (annoying...), but
|
// `outer_index`, that means that `ct` contains some content
|
||||||
// otherwise we do want to remember to visit the rest of the
|
// bound at `outer_index` or above (because
|
||||||
// const, as it has types/regions embedded in a lot of other
|
// `outer_exclusive_binder` is always 1 higher than the
|
||||||
// places.
|
// content in `t`). Therefore, `t` has some escaping vars.
|
||||||
match ct.kind() {
|
if ct.outer_exclusive_binder() > self.outer_index {
|
||||||
ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
|
ControlFlow::Break(FoundEscapingVars)
|
||||||
ControlFlow::Break(FoundEscapingVars)
|
} else {
|
||||||
}
|
ControlFlow::Continue(())
|
||||||
_ => ct.super_visit_with(self),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,9 +528,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
// Note: no `super_visit_with` call.
|
// Note: no `super_visit_with` call.
|
||||||
let flags = FlagComputation::for_const(c);
|
if c.flags().intersects(self.flags) {
|
||||||
trace!(r.flags=?flags);
|
|
||||||
if flags.intersects(self.flags) {
|
|
||||||
ControlFlow::Break(FoundFlags)
|
ControlFlow::Break(FoundFlags)
|
||||||
} else {
|
} else {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
|
|
|
@ -160,14 +160,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
match ct.kind() {
|
if ct.outer_exclusive_binder() > self.outer_index {
|
||||||
ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
|
self.escaping = self
|
||||||
self.escaping =
|
.escaping
|
||||||
self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
|
.max(ct.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
_ => ct.super_visit_with(self),
|
|
||||||
}
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue