bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
layout: InternedSet<'tcx, Layout>,
adt_def: InternedSet<'tcx, AdtDef>,
+
+ /// `#[stable]` and `#[unstable]` attributes
+ stability: InternedSet<'tcx, attr::Stability>,
+
+ /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
+ const_stability: InternedSet<'tcx, attr::ConstStability>,
}
impl<'tcx> CtxtInterners<'tcx> {
bound_variable_kinds: Default::default(),
layout: Default::default(),
adt_def: Default::default(),
+ stability: Default::default(),
+ const_stability: Default::default(),
}
}
/// `ReStatic`
pub re_static: Region<'tcx>,
- /// Erased region, used after type-checking
+ /// Erased region, used outside of type inference.
pub re_erased: Region<'tcx>,
}
field_indices: ItemLocalMap<usize>,
/// Stores the types for various nodes in the AST. Note that this table
- /// is not guaranteed to be populated until after typeck. See
+ /// is not guaranteed to be populated outside inference. See
/// typeck::check::fn_ctxt for details.
node_types: ItemLocalMap<Ty<'tcx>>,
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
- /// `#[stable]` and `#[unstable]` attributes
- stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>,
-
- /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
- const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>,
-
/// Stores memory for globals (statics/consts).
pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
self.create_memory_alloc(alloc)
}
- // FIXME(eddyb) move to `direct_interners!`.
- pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
- self.stability_interner.intern(stab, |stab| self.arena.alloc(stab))
- }
-
- // FIXME(eddyb) move to `direct_interners!`.
- pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
- self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab))
- }
-
/// Returns a range of the start/end indices specified with the
/// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
evaluation_cache: Default::default(),
crate_name: Symbol::intern(crate_name),
data_layout,
- stability_interner: Default::default(),
- const_stability_interner: Default::default(),
alloc_map: Lock::new(interpret::AllocMap::new()),
output_filenames: Arc::new(output_filenames),
}
writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?;
writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
- writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?;
+ writeln!(fmt, "Stability interner: #{}", self.0.interners.stability.len())?;
writeln!(
fmt,
"Const Stability interner: #{}",
- self.0.const_stability_interner.len()
+ self.0.interners.const_stability.len()
)?;
writeln!(
fmt,
}
}
-/// An entry in an interner.
+// This type holds a `T` in the interner. The `T` is stored in the arena and
+// this type just holds a pointer to it, but it still effectively owns it. It
+// impls `Borrow` so that it can be looked up using the original
+// (non-arena-memory-owning) types.
struct Interned<'tcx, T: ?Sized>(&'tcx T);
impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
Interned(self.0)
}
}
+
impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {}
impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
self.0 as *const _ as *const ()
}
}
-// N.B., an `Interned<Ty>` compares and hashes as a `TyKind`.
+
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
+ fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
+ &self.0.kind()
+ }
+}
+
impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
self.0.kind() == other.0.kind()
}
}
impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
self.0.kind().hash(s)
}
}
-#[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
- fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
- &self.0.kind()
+impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
+ fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
+ &self.0.kind
}
}
-// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
+
impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
self.0.kind == other.0.kind
}
}
impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
self.0.kind.hash(s)
}
}
-impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
- fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
- &self.0.kind
+impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
+ fn borrow<'a>(&'a self) -> &'a [T] {
+ &self.0[..]
}
}
-// N.B., an `Interned<List<T>>` compares and hashes as its elements.
impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+ // `x == y`.
self.0[..] == other.0[..]
}
}
impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> {
fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
self.0[..].hash(s)
}
}
-impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
- fn borrow<'a>(&'a self) -> &'a [T] {
- &self.0[..]
- }
-}
-
macro_rules! direct_interners {
($($name:ident: $method:ident($ty:ty),)+) => {
- $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
+ $(impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
+ fn borrow<'a>(&'a self) -> &'a $ty {
+ &self.0
+ }
+ }
+
+ impl<'tcx> PartialEq for Interned<'tcx, $ty> {
fn eq(&self, other: &Self) -> bool {
+ // The `Borrow` trait requires that `x.borrow() == y.borrow()`
+ // equals `x == y`.
self.0 == other.0
}
}
impl<'tcx> Hash for Interned<'tcx, $ty> {
fn hash<H: Hasher>(&self, s: &mut H) {
+ // The `Borrow` trait requires that `x.borrow().hash(s) ==
+ // x.hash(s)`.
self.0.hash(s)
}
}
- impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
- fn borrow<'a>(&'a self) -> &'a $ty {
- &self.0
- }
- }
-
impl<'tcx> TyCtxt<'tcx> {
pub fn $method(self, v: $ty) -> &'tcx $ty {
self.interners.$name.intern(v, |v| {
const_allocation: intern_const_alloc(Allocation),
layout: intern_layout(Layout),
adt_def: intern_adt_def(AdtDef),
+ stability: intern_stability(attr::Stability),
+ const_stability: intern_const_stability(attr::ConstStability),
}
macro_rules! slice_interners {
impl<T, R> InternIteratorElement<T, R> for T {
type Output = R;
- fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
- f(&iter.collect::<SmallVec<[_; 8]>>())
+ fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
+ mut iter: I,
+ f: F,
+ ) -> Self::Output {
+ // This code is hot enough that it's worth specializing for the most
+ // common length lists, to avoid the overhead of `SmallVec` creation.
+ // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+ // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+ // `assert`.
+ match iter.size_hint() {
+ (0, Some(0)) => {
+ assert!(iter.next().is_none());
+ f(&[])
+ }
+ (1, Some(1)) => {
+ let t0 = iter.next().unwrap();
+ assert!(iter.next().is_none());
+ f(&[t0])
+ }
+ (2, Some(2)) => {
+ let t0 = iter.next().unwrap();
+ let t1 = iter.next().unwrap();
+ assert!(iter.next().is_none());
+ f(&[t0, t1])
+ }
+ _ => f(&iter.collect::<SmallVec<[_; 8]>>()),
+ }
}
}
{
type Output = R;
fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
+ // This code isn't hot.
f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
}
}
) -> Self::Output {
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
- // The match arms are in order of frequency. The 1, 2, and 0 cases are
- // typically hit in ~95% of cases. We assume that if the upper and
- // lower bounds from `size_hint` agree they are correct.
+ // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+ // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+ // `assert`, unless a failure happens first, in which case the result
+ // will be an error anyway.
Ok(match iter.size_hint() {
+ (0, Some(0)) => {
+ assert!(iter.next().is_none());
+ f(&[])
+ }
(1, Some(1)) => {
let t0 = iter.next().unwrap()?;
assert!(iter.next().is_none());
assert!(iter.next().is_none());
f(&[t0, t1])
}
- (0, Some(0)) => {
- assert!(iter.next().is_none());
- f(&[])
- }
_ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
})
}
}
pub fn provide(providers: &mut ty::query::Providers) {
- providers.in_scope_traits_map =
- |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map);
providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
providers.module_reexports =
|tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);