Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 087ae97

Browse files
committedApr 7, 2024
Auto merge of rust-lang#123058 - lukas-code:clauses, r=lcnr
[perf] cache type info for ParamEnv This is an attempt to mitigate some of the perf regressions in rust-lang#122553 (comment), but seems worth to test and land separately, since it is mostly unrelated to that PR.
2 parents 6f83750 + 94d61d8 commit 087ae97

File tree

14 files changed

+284
-110
lines changed

14 files changed

+284
-110
lines changed
 

‎compiler/rustc_hir_analysis/src/collect/item_bounds.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,7 @@ pub(super) fn explicit_item_bounds_with_filter(
165165
ty::EarlyBinder::bind(bounds)
166166
}
167167

168-
pub(super) fn item_bounds(
169-
tcx: TyCtxt<'_>,
170-
def_id: DefId,
171-
) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
168+
pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> {
172169
tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
173170
tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
174171
})
@@ -177,7 +174,7 @@ pub(super) fn item_bounds(
177174
pub(super) fn item_super_predicates(
178175
tcx: TyCtxt<'_>,
179176
def_id: DefId,
180-
) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
177+
) -> ty::EarlyBinder<ty::Clauses<'_>> {
181178
tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
182179
tcx.mk_clauses_from_iter(
183180
util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
@@ -188,12 +185,12 @@ pub(super) fn item_super_predicates(
188185
pub(super) fn item_non_self_assumptions(
189186
tcx: TyCtxt<'_>,
190187
def_id: DefId,
191-
) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
188+
) -> ty::EarlyBinder<ty::Clauses<'_>> {
192189
let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
193190
let own_bounds: FxIndexSet<_> =
194191
tcx.item_super_predicates(def_id).skip_binder().iter().collect();
195192
if all_bounds.len() == own_bounds.len() {
196-
ty::EarlyBinder::bind(ty::List::empty())
193+
ty::EarlyBinder::bind(ty::ListWithCachedTypeInfo::empty())
197194
} else {
198195
ty::EarlyBinder::bind(tcx.mk_clauses_from_iter(all_bounds.difference(&own_bounds).copied()))
199196
}

‎compiler/rustc_middle/src/query/erase.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ impl<T> EraseType for &'_ ty::List<T> {
6767
type Result = [u8; size_of::<&'static ty::List<()>>()];
6868
}
6969

70+
impl<T> EraseType for &'_ ty::ListWithCachedTypeInfo<T> {
71+
type Result = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()];
72+
}
73+
7074
impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> {
7175
type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()];
7276
}

‎compiler/rustc_middle/src/query/keys.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
432432
}
433433
}
434434

435-
impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> {
435+
impl<'tcx> Key for ty::Clauses<'tcx> {
436436
type Cache<V> = DefaultCache<Self, V>;
437437

438438
fn default_span(&self, _: TyCtxt<'_>) -> Span {

‎compiler/rustc_middle/src/query/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,15 +398,15 @@ rustc_queries! {
398398
/// ```
399399
///
400400
/// Bounds from the parent (e.g. with nested impl trait) are not included.
401-
query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
401+
query item_bounds(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
402402
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
403403
}
404404

405-
query item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
405+
query item_super_predicates(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
406406
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
407407
}
408408

409-
query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
409+
query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
410410
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
411411
}
412412

@@ -2156,7 +2156,7 @@ rustc_queries! {
21562156
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
21572157
}
21582158

2159-
query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Clause<'tcx>>) -> &'tcx ty::List<ty::Clause<'tcx>> {
2159+
query reveal_opaque_types_in_bounds(key: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
21602160
desc { "revealing opaque types in `{:?}`", key }
21612161
}
21622162

‎compiler/rustc_middle/src/ty/codec.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty
414414
}
415415
}
416416

417-
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Clause<'tcx>> {
417+
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
418+
for ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>
419+
{
418420
fn decode(decoder: &mut D) -> &'tcx Self {
419421
let len = decoder.read_usize();
420422
decoder.interner().mk_clauses_from_iter(
@@ -461,7 +463,7 @@ impl_decodable_via_ref! {
461463
&'tcx mir::BorrowCheckResult<'tcx>,
462464
&'tcx mir::coverage::CodeRegion,
463465
&'tcx ty::List<ty::BoundVariableKind>,
464-
&'tcx ty::List<ty::Clause<'tcx>>,
466+
&'tcx ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>,
465467
&'tcx ty::List<FieldIdx>,
466468
&'tcx ty::List<(VariantIdx, FieldIdx)>,
467469
}

‎compiler/rustc_middle/src/ty/context.rs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ use crate::traits::solve::{
2525
ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
2626
};
2727
use crate::ty::{
28-
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind,
29-
ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate,
30-
PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty,
31-
TyKind, TyVid, TypeVisitable, Visibility,
28+
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
29+
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy,
30+
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region,
31+
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, Visibility,
3232
};
3333
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
3434
use rustc_ast::{self as ast, attr};
@@ -130,6 +130,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
130130
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
131131
type CoercePredicate = ty::CoercePredicate<'tcx>;
132132
type ClosureKind = ty::ClosureKind;
133+
type Clauses = ty::Clauses<'tcx>;
133134

134135
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
135136
self.mk_canonical_var_infos(infos)
@@ -152,7 +153,7 @@ pub struct CtxtInterners<'tcx> {
152153
region: InternedSet<'tcx, RegionKind<'tcx>>,
153154
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
154155
predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
155-
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
156+
clauses: InternedSet<'tcx, ListWithCachedTypeInfo<Clause<'tcx>>>,
156157
projs: InternedSet<'tcx, List<ProjectionKind>>,
157158
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
158159
const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
@@ -286,6 +287,24 @@ impl<'tcx> CtxtInterners<'tcx> {
286287
.0,
287288
))
288289
}
290+
291+
fn intern_clauses(&self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> {
292+
if clauses.is_empty() {
293+
ListWithCachedTypeInfo::empty()
294+
} else {
295+
self.clauses
296+
.intern_ref(clauses, || {
297+
let flags = super::flags::FlagComputation::for_clauses(clauses);
298+
299+
InternedInSet(ListWithCachedTypeInfo::from_arena(
300+
&*self.arena,
301+
flags.into(),
302+
clauses,
303+
))
304+
})
305+
.0
306+
}
307+
}
289308
}
290309

291310
// For these preinterned values, an alternative would be to have
@@ -1783,6 +1802,29 @@ impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> {
17831802
}
17841803
}
17851804

1805+
impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {
1806+
fn borrow(&self) -> &[T] {
1807+
&self.0[..]
1808+
}
1809+
}
1810+
1811+
impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {
1812+
fn eq(&self, other: &InternedInSet<'tcx, ListWithCachedTypeInfo<T>>) -> bool {
1813+
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
1814+
// `x == y`.
1815+
self.0[..] == other.0[..]
1816+
}
1817+
}
1818+
1819+
impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {}
1820+
1821+
impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {
1822+
fn hash<H: Hasher>(&self, s: &mut H) {
1823+
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
1824+
self.0[..].hash(s)
1825+
}
1826+
}
1827+
17861828
macro_rules! direct_interners {
17871829
($($name:ident: $vis:vis $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
17881830
$(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
@@ -1841,7 +1883,7 @@ macro_rules! slice_interners {
18411883
List::empty()
18421884
} else {
18431885
self.interners.$field.intern_ref(v, || {
1844-
InternedInSet(List::from_arena(&*self.arena, v))
1886+
InternedInSet(List::from_arena(&*self.arena, (), v))
18451887
}).0
18461888
}
18471889
})+
@@ -1858,7 +1900,6 @@ slice_interners!(
18581900
type_lists: pub mk_type_list(Ty<'tcx>),
18591901
canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
18601902
poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
1861-
clauses: intern_clauses(Clause<'tcx>),
18621903
projs: pub mk_projs(ProjectionKind),
18631904
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
18641905
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
@@ -2163,11 +2204,11 @@ impl<'tcx> TyCtxt<'tcx> {
21632204
self.intern_poly_existential_predicates(eps)
21642205
}
21652206

2166-
pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> {
2207+
pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> {
21672208
// FIXME consider asking the input slice to be sorted to avoid
21682209
// re-interning permutations, in which case that would be asserted
21692210
// here.
2170-
self.intern_clauses(clauses)
2211+
self.interners.intern_clauses(clauses)
21712212
}
21722213

21732214
pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> {
@@ -2231,7 +2272,7 @@ impl<'tcx> TyCtxt<'tcx> {
22312272
pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output
22322273
where
22332274
I: Iterator<Item = T>,
2234-
T: CollectAndApply<Clause<'tcx>, &'tcx List<Clause<'tcx>>>,
2275+
T: CollectAndApply<Clause<'tcx>, Clauses<'tcx>>,
22352276
{
22362277
T::collect_and_apply(iter, |xs| self.mk_clauses(xs))
22372278
}

‎compiler/rustc_middle/src/ty/flags.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ impl FlagComputation {
3535
result
3636
}
3737

38+
pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation {
39+
let mut result = FlagComputation::new();
40+
for c in clauses {
41+
result.add_flags(c.as_predicate().flags());
42+
result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
43+
}
44+
result
45+
}
46+
3847
fn add_flags(&mut self, flags: TypeFlags) {
3948
self.flags = self.flags | flags;
4049
}

‎compiler/rustc_middle/src/ty/impls_ty.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,20 @@ use rustc_data_structures::stable_hasher::HashingControls;
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
1212
use rustc_query_system::ich::StableHashingContext;
1313
use std::cell::RefCell;
14+
use std::ptr;
1415

15-
impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T>
16+
impl<'a, 'tcx, H, T> HashStable<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T>
1617
where
1718
T: HashStable<StableHashingContext<'a>>,
1819
{
1920
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
2021
thread_local! {
21-
static CACHE: RefCell<FxHashMap<(usize, usize, HashingControls), Fingerprint>> =
22+
static CACHE: RefCell<FxHashMap<(*const (), HashingControls), Fingerprint>> =
2223
RefCell::new(Default::default());
2324
}
2425

2526
let hash = CACHE.with(|cache| {
26-
let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls());
27+
let key = (ptr::from_ref(*self).cast::<()>(), hcx.hashing_controls());
2728
if let Some(&hash) = cache.borrow().get(&key) {
2829
return hash;
2930
}
@@ -40,7 +41,7 @@ where
4041
}
4142
}
4243

43-
impl<'a, 'tcx, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::List<T>
44+
impl<'a, 'tcx, H, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T>
4445
where
4546
T: HashStable<StableHashingContext<'a>>,
4647
{

‎compiler/rustc_middle/src/ty/list.rs

Lines changed: 135 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use super::flags::FlagComputation;
2+
use super::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, TyCtxt, TypeFlags, WithInfcx};
13
use crate::arena::Arena;
24
use rustc_data_structures::aligned::{align_of, Aligned};
35
use rustc_serialize::{Encodable, Encoder};
4-
use rustc_type_ir::{InferCtxtLike, WithInfcx};
56
use std::alloc::Layout;
67
use std::cmp::Ordering;
78
use std::fmt;
@@ -12,6 +13,9 @@ use std::ops::Deref;
1213
use std::ptr;
1314
use std::slice;
1415

16+
#[cfg(parallel_compiler)]
17+
use rustc_data_structures::sync::DynSync;
18+
1519
/// `List<T>` is a bit like `&[T]`, but with some critical differences.
1620
/// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The
1721
/// type's correctness relies on this, *but it does not enforce it*.
@@ -28,15 +32,27 @@ use std::slice;
2832
/// - `T` must be `Copy`. This lets `List<T>` be stored in a dropless arena and
2933
/// iterators return a `T` rather than a `&T`.
3034
/// - `T` must not be zero-sized.
35+
pub type List<T> = RawList<(), T>;
36+
37+
/// A generic type that can be used to prepend a [`List`] with some header.
38+
///
39+
/// The header will be ignored for value-based operations like [`PartialEq`],
40+
/// [`Hash`] and [`Encodable`].
3141
#[repr(C)]
32-
pub struct List<T> {
33-
len: usize,
42+
pub struct RawList<H, T> {
43+
skel: ListSkeleton<H, T>,
44+
opaque: OpaqueListContents,
45+
}
3446

47+
/// A [`RawList`] without the unsized tail. This type is used for layout computation
48+
/// and constructing empty lists.
49+
#[repr(C)]
50+
struct ListSkeleton<H, T> {
51+
header: H,
52+
len: usize,
3553
/// Although this claims to be a zero-length array, in practice `len`
3654
/// elements are actually present.
3755
data: [T; 0],
38-
39-
opaque: OpaqueListContents,
4056
}
4157

4258
extern "C" {
@@ -45,35 +61,17 @@ extern "C" {
4561
type OpaqueListContents;
4662
}
4763

48-
impl<T> List<T> {
49-
/// Returns a reference to the (unique, static) empty list.
64+
impl<H, T> RawList<H, T> {
5065
#[inline(always)]
51-
pub fn empty<'a>() -> &'a List<T> {
52-
#[repr(align(64))]
53-
struct MaxAlign;
54-
55-
assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>());
56-
57-
#[repr(C)]
58-
struct InOrder<T, U>(T, U);
59-
60-
// The empty slice is static and contains a single `0` usize (for the
61-
// length) that is 64-byte aligned, thus featuring the necessary
62-
// trailing padding for elements with up to 64-byte alignment.
63-
static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign);
64-
unsafe { &*(std::ptr::addr_of!(EMPTY_SLICE) as *const List<T>) }
65-
}
66-
6766
pub fn len(&self) -> usize {
68-
self.len
67+
self.skel.len
6968
}
7069

70+
#[inline(always)]
7171
pub fn as_slice(&self) -> &[T] {
7272
self
7373
}
74-
}
7574

76-
impl<T: Copy> List<T> {
7775
/// Allocates a list from `arena` and copies the contents of `slice` into it.
7876
///
7977
/// WARNING: the contents *must be unique*, such that no list with these
@@ -84,20 +82,31 @@ impl<T: Copy> List<T> {
8482
/// (because the empty list exists statically, and is available via
8583
/// `empty()`).
8684
#[inline]
87-
pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> {
85+
pub(super) fn from_arena<'tcx>(
86+
arena: &'tcx Arena<'tcx>,
87+
header: H,
88+
slice: &[T],
89+
) -> &'tcx RawList<H, T>
90+
where
91+
T: Copy,
92+
{
8893
assert!(!mem::needs_drop::<T>());
8994
assert!(mem::size_of::<T>() != 0);
9095
assert!(!slice.is_empty());
9196

9297
let (layout, _offset) =
93-
Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap();
94-
let mem = arena.dropless.alloc_raw(layout) as *mut List<T>;
98+
Layout::new::<ListSkeleton<H, T>>().extend(Layout::for_value::<[T]>(slice)).unwrap();
99+
100+
let mem = arena.dropless.alloc_raw(layout) as *mut RawList<H, T>;
95101
unsafe {
102+
// Write the header
103+
ptr::addr_of_mut!((*mem).skel.header).write(header);
104+
96105
// Write the length
97-
ptr::addr_of_mut!((*mem).len).write(slice.len());
106+
ptr::addr_of_mut!((*mem).skel.len).write(slice.len());
98107

99108
// Write the elements
100-
ptr::addr_of_mut!((*mem).data)
109+
ptr::addr_of_mut!((*mem).skel.data)
101110
.cast::<T>()
102111
.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
103112

@@ -110,17 +119,44 @@ impl<T: Copy> List<T> {
110119
//
111120
// This would be weird, as `self.into_iter` iterates over `T` directly.
112121
#[inline(always)]
113-
pub fn iter(&self) -> <&'_ List<T> as IntoIterator>::IntoIter {
122+
pub fn iter(&self) -> <&'_ RawList<H, T> as IntoIterator>::IntoIter
123+
where
124+
T: Copy,
125+
{
114126
self.into_iter()
115127
}
116128
}
117129

118-
impl<T: fmt::Debug> fmt::Debug for List<T> {
130+
macro_rules! impl_list_empty {
131+
($header_ty:ty, $header_init:expr) => {
132+
impl<T> RawList<$header_ty, T> {
133+
/// Returns a reference to the (per header unique, static) empty list.
134+
#[inline(always)]
135+
pub fn empty<'a>() -> &'a RawList<$header_ty, T> {
136+
#[repr(align(64))]
137+
struct MaxAlign;
138+
139+
static EMPTY: ListSkeleton<$header_ty, MaxAlign> =
140+
ListSkeleton { header: $header_init, len: 0, data: [] };
141+
142+
assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>());
143+
144+
// SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all
145+
// types with `align_of(T) <= align_of(MaxAlign)`, which we checked above.
146+
unsafe { &*(std::ptr::addr_of!(EMPTY) as *const RawList<$header_ty, T>) }
147+
}
148+
}
149+
};
150+
}
151+
152+
impl_list_empty!((), ());
153+
154+
impl<H, T: fmt::Debug> fmt::Debug for RawList<H, T> {
119155
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120156
(**self).fmt(f)
121157
}
122158
}
123-
impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> {
159+
impl<'tcx, H, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for RawList<H, T> {
124160
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
125161
this: WithInfcx<'_, Infcx, &Self>,
126162
f: &mut core::fmt::Formatter<'_>,
@@ -129,40 +165,40 @@ impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<
129165
}
130166
}
131167

132-
impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> {
168+
impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> {
133169
#[inline]
134170
fn encode(&self, s: &mut S) {
135171
(**self).encode(s);
136172
}
137173
}
138174

139-
impl<T: PartialEq> PartialEq for List<T> {
175+
impl<H, T: PartialEq> PartialEq for RawList<H, T> {
140176
#[inline]
141-
fn eq(&self, other: &List<T>) -> bool {
177+
fn eq(&self, other: &RawList<H, T>) -> bool {
142178
// Pointer equality implies list equality (due to the unique contents
143179
// assumption).
144180
ptr::eq(self, other)
145181
}
146182
}
147183

148-
impl<T: Eq> Eq for List<T> {}
184+
impl<H, T: Eq> Eq for RawList<H, T> {}
149185

150-
impl<T> Ord for List<T>
186+
impl<H, T> Ord for RawList<H, T>
151187
where
152188
T: Ord,
153189
{
154-
fn cmp(&self, other: &List<T>) -> Ordering {
190+
fn cmp(&self, other: &RawList<H, T>) -> Ordering {
155191
// Pointer equality implies list equality (due to the unique contents
156192
// assumption), but the contents must be compared otherwise.
157193
if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
158194
}
159195
}
160196

161-
impl<T> PartialOrd for List<T>
197+
impl<H, T> PartialOrd for RawList<H, T>
162198
where
163199
T: PartialOrd,
164200
{
165-
fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> {
201+
fn partial_cmp(&self, other: &RawList<H, T>) -> Option<Ordering> {
166202
// Pointer equality implies list equality (due to the unique contents
167203
// assumption), but the contents must be compared otherwise.
168204
if self == other {
@@ -173,31 +209,36 @@ where
173209
}
174210
}
175211

176-
impl<T> Hash for List<T> {
212+
impl<Hdr, T> Hash for RawList<Hdr, T> {
177213
#[inline]
178214
fn hash<H: Hasher>(&self, s: &mut H) {
179215
// Pointer hashing is sufficient (due to the unique contents
180216
// assumption).
181-
(self as *const List<T>).hash(s)
217+
ptr::from_ref(self).hash(s)
182218
}
183219
}
184220

185-
impl<T> Deref for List<T> {
221+
impl<H, T> Deref for RawList<H, T> {
186222
type Target = [T];
187223
#[inline(always)]
188224
fn deref(&self) -> &[T] {
189225
self.as_ref()
190226
}
191227
}
192228

193-
impl<T> AsRef<[T]> for List<T> {
229+
impl<H, T> AsRef<[T]> for RawList<H, T> {
194230
#[inline(always)]
195231
fn as_ref(&self) -> &[T] {
196-
unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
232+
let data_ptr = ptr::addr_of!(self.skel.data).cast::<T>();
233+
// SAFETY: `data_ptr` has the same provenance as `self` and can therefore
234+
// access the `self.skel.len` elements stored at `self.skel.data`.
235+
// Note that we specifically don't reborrow `&self.skel.data`, because that
236+
// would give us a pointer with provenance over 0 bytes.
237+
unsafe { slice::from_raw_parts(data_ptr, self.skel.len) }
197238
}
198239
}
199240

200-
impl<'a, T: Copy> IntoIterator for &'a List<T> {
241+
impl<'a, H, T: Copy> IntoIterator for &'a RawList<H, T> {
201242
type Item = T;
202243
type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>;
203244
#[inline(always)]
@@ -206,27 +247,56 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> {
206247
}
207248
}
208249

209-
unsafe impl<T: Sync> Sync for List<T> {}
250+
unsafe impl<H: Sync, T: Sync> Sync for RawList<H, T> {}
210251

211252
// We need this since `List` uses extern type `OpaqueListContents`.
212253
#[cfg(parallel_compiler)]
213-
use rustc_data_structures::sync::DynSync;
214-
215-
use super::TyCtxt;
216-
#[cfg(parallel_compiler)]
217-
unsafe impl<T: DynSync> DynSync for List<T> {}
254+
unsafe impl<H: DynSync, T: DynSync> DynSync for RawList<H, T> {}
218255

219256
// Safety:
220-
// Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail,
221-
// thus aligns of `Equivalent<T>` and `List<T>` must be the same.
222-
unsafe impl<T> Aligned for List<T> {
223-
const ALIGN: ptr::Alignment = {
224-
#[repr(C)]
225-
struct Equivalent<T> {
226-
_len: usize,
227-
_data: [T; 0],
228-
}
257+
// Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo opaque tail,
258+
// thus aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same.
259+
unsafe impl<H, T> Aligned for RawList<H, T> {
260+
const ALIGN: ptr::Alignment = align_of::<ListSkeleton<H, T>>();
261+
}
229262

230-
align_of::<Equivalent<T>>()
231-
};
263+
/// A [`List`] that additionally stores type information inline to speed up
264+
/// [`TypeVisitableExt`](super::TypeVisitableExt) operations.
265+
pub type ListWithCachedTypeInfo<T> = RawList<TypeInfo, T>;
266+
267+
impl<T> ListWithCachedTypeInfo<T> {
268+
#[inline(always)]
269+
pub fn flags(&self) -> TypeFlags {
270+
self.skel.header.flags
271+
}
272+
273+
#[inline(always)]
274+
pub fn outer_exclusive_binder(&self) -> DebruijnIndex {
275+
self.skel.header.outer_exclusive_binder
276+
}
277+
}
278+
279+
impl_list_empty!(TypeInfo, TypeInfo::empty());
280+
281+
/// The additional info that is stored in [`ListWithCachedTypeInfo`].
282+
#[repr(C)]
283+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
284+
pub struct TypeInfo {
285+
flags: TypeFlags,
286+
outer_exclusive_binder: DebruijnIndex,
287+
}
288+
289+
impl TypeInfo {
290+
const fn empty() -> Self {
291+
Self { flags: TypeFlags::empty(), outer_exclusive_binder: super::INNERMOST }
292+
}
293+
}
294+
295+
impl From<FlagComputation> for TypeInfo {
296+
fn from(computation: FlagComputation) -> TypeInfo {
297+
TypeInfo {
298+
flags: computation.flags,
299+
outer_exclusive_binder: computation.outer_exclusive_binder,
300+
}
301+
}
232302
}

‎compiler/rustc_middle/src/ty/mod.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub use self::context::{
8989
TyCtxt, TyCtxtFeed,
9090
};
9191
pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
92-
pub use self::list::List;
92+
pub use self::list::{List, ListWithCachedTypeInfo};
9393
pub use self::parameterized::ParameterizedOverTcx;
9494
pub use self::predicate::{
9595
Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection,
@@ -1034,6 +1034,18 @@ impl PlaceholderLike for PlaceholderConst {
10341034
}
10351035
}
10361036

1037+
pub type Clauses<'tcx> = &'tcx ListWithCachedTypeInfo<Clause<'tcx>>;
1038+
1039+
impl<'tcx> rustc_type_ir::visit::Flags for Clauses<'tcx> {
1040+
fn flags(&self) -> TypeFlags {
1041+
(**self).flags()
1042+
}
1043+
1044+
fn outer_exclusive_binder(&self) -> DebruijnIndex {
1045+
(**self).outer_exclusive_binder()
1046+
}
1047+
}
1048+
10371049
/// When interacting with the type system we must provide information about the
10381050
/// environment. `ParamEnv` is the type that represents this information. See the
10391051
/// [dev guide chapter][param_env_guide] for more information.
@@ -1053,7 +1065,7 @@ pub struct ParamEnv<'tcx> {
10531065
/// want `Reveal::All`.
10541066
///
10551067
/// Note: This is packed, use the reveal() method to access it.
1056-
packed: CopyTaggedPtr<&'tcx List<Clause<'tcx>>, ParamTag, true>,
1068+
packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>,
10571069
}
10581070

10591071
#[derive(Copy, Clone)]
@@ -1112,11 +1124,11 @@ impl<'tcx> ParamEnv<'tcx> {
11121124
/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
11131125
#[inline]
11141126
pub fn empty() -> Self {
1115-
Self::new(List::empty(), Reveal::UserFacing)
1127+
Self::new(ListWithCachedTypeInfo::empty(), Reveal::UserFacing)
11161128
}
11171129

11181130
#[inline]
1119-
pub fn caller_bounds(self) -> &'tcx List<Clause<'tcx>> {
1131+
pub fn caller_bounds(self) -> Clauses<'tcx> {
11201132
self.packed.pointer()
11211133
}
11221134

@@ -1134,12 +1146,12 @@ impl<'tcx> ParamEnv<'tcx> {
11341146
/// or invoke `param_env.with_reveal_all()`.
11351147
#[inline]
11361148
pub fn reveal_all() -> Self {
1137-
Self::new(List::empty(), Reveal::All)
1149+
Self::new(ListWithCachedTypeInfo::empty(), Reveal::All)
11381150
}
11391151

11401152
/// Construct a trait environment with the given set of predicates.
11411153
#[inline]
1142-
pub fn new(caller_bounds: &'tcx List<Clause<'tcx>>, reveal: Reveal) -> Self {
1154+
pub fn new(caller_bounds: Clauses<'tcx>, reveal: Reveal) -> Self {
11431155
ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
11441156
}
11451157

@@ -1168,7 +1180,7 @@ impl<'tcx> ParamEnv<'tcx> {
11681180
/// Returns this same environment but with no caller bounds.
11691181
#[inline]
11701182
pub fn without_caller_bounds(self) -> Self {
1171-
Self::new(List::empty(), self.reveal())
1183+
Self::new(ListWithCachedTypeInfo::empty(), self.reveal())
11721184
}
11731185

11741186
/// Creates a pair of param-env and value for use in queries.

‎compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
712712
}
713713
}
714714

715-
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> {
715+
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Clauses<'tcx> {
716+
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
717+
visitor.visit_clauses(self)
718+
}
719+
}
720+
721+
impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Clauses<'tcx> {
722+
fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
723+
self.as_slice().visit_with(visitor)
724+
}
725+
}
726+
727+
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clauses<'tcx> {
716728
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
717729
self,
718730
folder: &mut F,

‎compiler/rustc_middle/src/ty/util.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,25 +1608,27 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
16081608
/// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
16091609
/// folder.tcx().intern_*(&v)
16101610
/// ```
1611-
pub fn fold_list<'tcx, F, T>(
1612-
list: &'tcx ty::List<T>,
1611+
pub fn fold_list<'tcx, F, L, T>(
1612+
list: L,
16131613
folder: &mut F,
1614-
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
1615-
) -> Result<&'tcx ty::List<T>, F::Error>
1614+
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L,
1615+
) -> Result<L, F::Error>
16161616
where
16171617
F: FallibleTypeFolder<TyCtxt<'tcx>>,
1618+
L: AsRef<[T]>,
16181619
T: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy,
16191620
{
1620-
let mut iter = list.iter();
1621+
let slice = list.as_ref();
1622+
let mut iter = slice.iter().copied();
16211623
// Look for the first element that changed
16221624
match iter.by_ref().enumerate().find_map(|(i, t)| match t.try_fold_with(folder) {
16231625
Ok(new_t) if new_t == t => None,
16241626
new_t => Some((i, new_t)),
16251627
}) {
16261628
Some((i, Ok(new_t))) => {
16271629
// An element changed, prepare to intern the resulting list
1628-
let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
1629-
new_list.extend_from_slice(&list[..i]);
1630+
let mut new_list = SmallVec::<[_; 8]>::with_capacity(slice.len());
1631+
new_list.extend_from_slice(&slice[..i]);
16301632
new_list.push(new_t);
16311633
for t in iter {
16321634
new_list.push(t.try_fold_with(folder)?)
@@ -1647,8 +1649,8 @@ pub struct AlwaysRequiresDrop;
16471649
/// with their underlying types.
16481650
pub fn reveal_opaque_types_in_bounds<'tcx>(
16491651
tcx: TyCtxt<'tcx>,
1650-
val: &'tcx ty::List<ty::Clause<'tcx>>,
1651-
) -> &'tcx ty::List<ty::Clause<'tcx>> {
1652+
val: ty::Clauses<'tcx>,
1653+
) -> ty::Clauses<'tcx> {
16521654
let mut visitor = OpaqueTypeExpander {
16531655
seen_opaque_tys: FxHashSet::default(),
16541656
expanded_cache: FxHashMap::default(),

‎compiler/rustc_type_ir/src/interner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub trait Interner: Sized + Copy {
100100
type SubtypePredicate: Copy + Debug + Hash + Eq;
101101
type CoercePredicate: Copy + Debug + Hash + Eq;
102102
type ClosureKind: Copy + Debug + Hash + Eq;
103+
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
103104

104105
fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
105106
}

‎compiler/rustc_type_ir/src/visit.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ pub trait TypeVisitor<I: Interner>: Sized {
110110
fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result {
111111
p.super_visit_with(self)
112112
}
113+
114+
fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result {
115+
p.super_visit_with(self)
116+
}
113117
}
114118

115119
///////////////////////////////////////////////////////////////////////////
@@ -423,6 +427,16 @@ impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
423427
ControlFlow::Continue(())
424428
}
425429
}
430+
431+
#[inline]
432+
fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result {
433+
// Note: no `super_visit_with` call.
434+
if clauses.flags().intersects(self.flags) {
435+
ControlFlow::Break(FoundFlags)
436+
} else {
437+
ControlFlow::Continue(())
438+
}
439+
}
426440
}
427441

428442
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -515,6 +529,15 @@ impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
515529
ControlFlow::Continue(())
516530
}
517531
}
532+
533+
#[inline]
534+
fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result {
535+
if clauses.outer_exclusive_binder() > self.outer_index {
536+
ControlFlow::Break(FoundEscapingVars)
537+
} else {
538+
ControlFlow::Continue(())
539+
}
540+
}
518541
}
519542

520543
struct HasErrorVisitor;

0 commit comments

Comments
 (0)
This repository has been archived.