Skip to content

Commit d46ed5d

Browse files
committed
Clarify some code relating to interning and types.
I have found this code very confusing at times. This commit clarifies things. In particular, the commit explains the requirements that the `Borrow` impls put on the `Eq` and `Hash` impls, which are non-obvious. And it puts the `Borrow` impls first, since they force `Eq` and `Hash` to have particular forms. The commit also notes `TyS`'s uniqueness requirements.
1 parent c55819a commit d46ed5d

File tree

2 files changed

+57
-24
lines changed

2 files changed

+57
-24
lines changed

compiler/rustc_middle/src/ty/context.rs

+40-24
Original file line numberDiff line numberDiff line change
@@ -1946,24 +1946,37 @@ impl<'tcx> TyCtxt<'tcx> {
19461946
}
19471947
}
19481948

1949-
/// An entry in an interner.
1949+
// This type holds a `T` in the interner. The `T` is stored in the arena and
1950+
// this type just holds a pointer to it, but it still effectively owns it. It
1951+
// impls `Borrow` so that it can be looked up using the original
1952+
// (non-arena-memory-owning) types.
19501953
struct Interned<'tcx, T: ?Sized>(&'tcx T);
19511954

19521955
impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
19531956
fn clone(&self) -> Self {
19541957
Interned(self.0)
19551958
}
19561959
}
1960+
19571961
impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {}
19581962

19591963
impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
19601964
fn into_pointer(&self) -> *const () {
19611965
self.0 as *const _ as *const ()
19621966
}
19631967
}
1964-
// N.B., an `Interned<Ty>` compares and hashes as a `TyKind`.
1968+
1969+
#[allow(rustc::usage_of_ty_tykind)]
1970+
impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
1971+
fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
1972+
&self.0.kind()
1973+
}
1974+
}
1975+
19651976
impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
19661977
fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
1978+
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
1979+
// `x == y`.
19671980
self.0.kind() == other.0.kind()
19681981
}
19691982
}
@@ -1972,19 +1985,21 @@ impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {}
19721985

19731986
impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
19741987
fn hash<H: Hasher>(&self, s: &mut H) {
1988+
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
19751989
self.0.kind().hash(s)
19761990
}
19771991
}
19781992

1979-
#[allow(rustc::usage_of_ty_tykind)]
1980-
impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
1981-
fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
1982-
&self.0.kind()
1993+
impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
1994+
fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
1995+
&self.0.kind
19831996
}
19841997
}
1985-
// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
1998+
19861999
impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
19872000
fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
2001+
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
2002+
// `x == y`.
19882003
self.0.kind == other.0.kind
19892004
}
19902005
}
@@ -1993,19 +2008,21 @@ impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
19932008

19942009
impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
19952010
fn hash<H: Hasher>(&self, s: &mut H) {
2011+
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
19962012
self.0.kind.hash(s)
19972013
}
19982014
}
19992015

2000-
impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
2001-
fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
2002-
&self.0.kind
2016+
impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
2017+
fn borrow<'a>(&'a self) -> &'a [T] {
2018+
&self.0[..]
20032019
}
20042020
}
20052021

2006-
// N.B., an `Interned<List<T>>` compares and hashes as its elements.
20072022
impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
20082023
fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool {
2024+
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
2025+
// `x == y`.
20092026
self.0[..] == other.0[..]
20102027
}
20112028
}
@@ -2014,20 +2031,23 @@ impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {}
20142031

20152032
impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> {
20162033
fn hash<H: Hasher>(&self, s: &mut H) {
2034+
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
20172035
self.0[..].hash(s)
20182036
}
20192037
}
20202038

2021-
impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
2022-
fn borrow<'a>(&'a self) -> &'a [T] {
2023-
&self.0[..]
2024-
}
2025-
}
2026-
20272039
macro_rules! direct_interners {
20282040
($($name:ident: $method:ident($ty:ty),)+) => {
2029-
$(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
2041+
$(impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
2042+
fn borrow<'a>(&'a self) -> &'a $ty {
2043+
&self.0
2044+
}
2045+
}
2046+
2047+
impl<'tcx> PartialEq for Interned<'tcx, $ty> {
20302048
fn eq(&self, other: &Self) -> bool {
2049+
// The `Borrow` trait requires that `x.borrow() == y.borrow()`
2050+
// equals `x == y`.
20312051
self.0 == other.0
20322052
}
20332053
}
@@ -2036,16 +2056,12 @@ macro_rules! direct_interners {
20362056

20372057
impl<'tcx> Hash for Interned<'tcx, $ty> {
20382058
fn hash<H: Hasher>(&self, s: &mut H) {
2059+
// The `Borrow` trait requires that `x.borrow().hash(s) ==
2060+
// x.hash(s)`.
20392061
self.0.hash(s)
20402062
}
20412063
}
20422064

2043-
impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
2044-
fn borrow<'a>(&'a self) -> &'a $ty {
2045-
&self.0
2046-
}
2047-
}
2048-
20492065
impl<'tcx> TyCtxt<'tcx> {
20502066
pub fn $method(self, v: $ty) -> &'tcx $ty {
20512067
self.interners.$name.intern(v, |v| {

compiler/rustc_middle/src/ty/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -376,15 +376,28 @@ pub struct CReaderCacheKey {
376376
pub pos: usize,
377377
}
378378

379+
/// Represents a type.
380+
///
381+
/// IMPORTANT: Every `TyS` is *required* to have unique contents. The type's
382+
/// correctness relies on this, *but it does not enforce it*. Therefore, any
383+
/// code that creates a `TyS` must ensure uniqueness itself. In practice this
384+
/// is achieved by interning.
379385
#[allow(rustc::usage_of_ty_tykind)]
380386
pub struct TyS<'tcx> {
381387
/// This field shouldn't be used directly and may be removed in the future.
382388
/// Use `TyS::kind()` instead.
383389
kind: TyKind<'tcx>,
390+
391+
/// This field provides fast access to information that is also contained
392+
/// in `kind`.
393+
///
384394
/// This field shouldn't be used directly and may be removed in the future.
385395
/// Use `TyS::flags()` instead.
386396
flags: TypeFlags,
387397

398+
/// This field provides fast access to information that is also contained
399+
/// in `kind`.
400+
///
388401
/// This is a kind of confusing thing: it stores the smallest
389402
/// binder such that
390403
///
@@ -436,13 +449,17 @@ impl<'tcx> PartialOrd for TyS<'tcx> {
436449
impl<'tcx> PartialEq for TyS<'tcx> {
437450
#[inline]
438451
fn eq(&self, other: &TyS<'tcx>) -> bool {
452+
// Pointer equality implies equality (due to the unique contents
453+
// assumption).
439454
ptr::eq(self, other)
440455
}
441456
}
442457
impl<'tcx> Eq for TyS<'tcx> {}
443458

444459
impl<'tcx> Hash for TyS<'tcx> {
445460
fn hash<H: Hasher>(&self, s: &mut H) {
461+
// Pointer hashing is sufficient (due to the unique contents
462+
// assumption).
446463
(self as *const TyS<'_>).hash(s)
447464
}
448465
}

0 commit comments

Comments
 (0)