about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_metadata/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs206
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs89
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs218
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs245
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs53
6 files changed, 392 insertions, 420 deletions
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 3df18098a07..5e4c1284e24 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -10,6 +10,7 @@
 #![feature(macro_metavar_expr)]
 #![feature(min_specialization)]
 #![feature(slice_as_chunks)]
+#![feature(trusted_len)]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 4038af38a2c..72b7c08f04b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1,12 +1,10 @@
 // Decoding metadata from a single crate's metadata
 
 use crate::creader::{CStore, CrateMetadataRef};
-use crate::rmeta::table::{FixedSizeEncoding, Table};
 use crate::rmeta::*;
 
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_attr as attr;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
@@ -20,10 +18,8 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_hir::lang_items;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
-use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
@@ -42,6 +38,7 @@ use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP};
 
 use proc_macro::bridge::client::ProcMacro;
 use std::io;
+use std::iter::TrustedLen;
 use std::mem;
 use std::num::NonZeroUsize;
 use std::path::Path;
@@ -85,7 +82,6 @@ pub(crate) struct CrateMetadata {
     blob: MetadataBlob,
 
     // --- Some data pre-decoded from the metadata blob, usually for performance ---
-    /// Properties of the whole crate.
     /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
     /// lifetime is only used behind `Lazy`, and therefore acts like a
     /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
@@ -94,12 +90,12 @@ pub(crate) struct CrateMetadata {
     /// Trait impl data.
     /// FIXME: Used only from queries and can use query cache,
     /// so pre-decoding can probably be avoided.
-    trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<SimplifiedType>)]>>,
+    trait_impls: FxHashMap<(u32, DefIndex), LazyArray<(DefIndex, Option<SimplifiedType>)>>,
     /// Inherent impls which do not follow the normal coherence rules.
     ///
     /// These can be introduced using either `#![rustc_coherence_is_core]`
     /// or `#[rustc_allow_incoherent_impl]`.
-    incoherent_impls: FxHashMap<SimplifiedType, Lazy<[DefIndex]>>,
+    incoherent_impls: FxHashMap<SimplifiedType, LazyArray<DefIndex>>,
     /// Proc macro descriptions for this crate, if it's a proc macro crate.
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
@@ -265,7 +261,7 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) {
     }
 }
 
-impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<T> {
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> LazyValue<T> {
     fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
         let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
@@ -273,130 +269,41 @@ impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<T> {
     }
 }
 
-impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<[T]> {
-    fn decode<M: Metadata<'a, 'tcx>>(
-        self,
-        metadata: M,
-    ) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
-        let mut dcx = metadata.decoder(self.position.get());
-        dcx.lazy_state = LazyState::NodeStart(self.position);
-        (0..self.meta).map(move |_| T::decode(&mut dcx))
-    }
-}
-
-trait LazyQueryDecodable<'a, 'tcx, T> {
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        err: impl FnOnce() -> !,
-    ) -> T;
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for T {
-    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, _: impl FnOnce() -> !) -> T {
-        self
-    }
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<T> {
-    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, err: impl FnOnce() -> !) -> T {
-        if let Some(l) = self { l } else { err() }
-    }
+struct DecodeIterator<'a, 'tcx, T> {
+    elem_counter: std::ops::Range<usize>,
+    dcx: DecodeContext<'a, 'tcx>,
+    _phantom: PhantomData<fn() -> T>,
 }
 
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        err: impl FnOnce() -> !,
-    ) -> T {
-        if let Some(l) = self { l.decode((cdata, tcx)) } else { err() }
-    }
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx T> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-    T: ArenaAllocatable<'tcx>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        err: impl FnOnce() -> !,
-    ) -> &'tcx T {
-        if let Some(l) = self { tcx.arena.alloc(l.decode((cdata, tcx))) } else { err() }
-    }
-}
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Iterator for DecodeIterator<'a, 'tcx, T> {
+    type Item = T;
 
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, Option<T>> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> Option<T> {
-        self.map(|l| l.decode((cdata, tcx)))
+    #[inline(always)]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.elem_counter.next().map(|_| T::decode(&mut self.dcx))
     }
-}
 
-impl<'a, 'tcx, T, E> LazyQueryDecodable<'a, 'tcx, Result<Option<T>, E>> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> Result<Option<T>, E> {
-        Ok(self.map(|l| l.decode((cdata, tcx))))
+    #[inline(always)]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.elem_counter.size_hint()
     }
 }
 
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx [T]> for Option<Lazy<[T], usize>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>> + Copy,
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> ExactSizeIterator
+    for DecodeIterator<'a, 'tcx, T>
 {
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> &'tcx [T] {
-        if let Some(l) = self { tcx.arena.alloc_from_iter(l.decode((cdata, tcx))) } else { &[] }
-    }
 }
 
-impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option<DeprecationEntry>>
-    for Option<Lazy<attr::Deprecation>>
+unsafe impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> TrustedLen
+    for DecodeIterator<'a, 'tcx, T>
 {
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> Option<DeprecationEntry> {
-        self.map(|l| l.decode((cdata, tcx))).map(DeprecationEntry::external)
-    }
 }
 
-impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option<DefId>> for Option<RawDefId> {
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        _: TyCtxt<'tcx>,
-        _: impl FnOnce() -> !,
-    ) -> Option<DefId> {
-        self.map(|raw_def_id| raw_def_id.decode(cdata))
+impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable<DecodeContext<'a, 'tcx>>> LazyArray<T> {
+    fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> DecodeIterator<'a, 'tcx, T> {
+        let mut dcx = metadata.decoder(self.position.get());
+        dcx.lazy_state = LazyState::NodeStart(self.position);
+        DecodeIterator { elem_counter: (0..self.num_elems), dcx, _phantom: PhantomData }
     }
 }
 
@@ -423,7 +330,8 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
         self.cdata().map_encoded_cnum_to_current(cnum)
     }
 
-    fn read_lazy_with_meta<T: ?Sized + LazyMeta>(&mut self, meta: T::Meta) -> Lazy<T> {
+    #[inline]
+    fn read_lazy_offset_then<T>(&mut self, f: impl Fn(NonZeroUsize) -> T) -> T {
         let distance = self.read_usize();
         let position = match self.lazy_state {
             LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
@@ -434,8 +342,21 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
             }
             LazyState::Previous(last_pos) => last_pos.get() + distance,
         };
-        self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap());
-        Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta)
+        let position = NonZeroUsize::new(position).unwrap();
+        self.lazy_state = LazyState::Previous(position);
+        f(position)
+    }
+
+    fn read_lazy<T>(&mut self) -> LazyValue<T> {
+        self.read_lazy_offset_then(|pos| LazyValue::from_position(pos))
+    }
+
+    fn read_lazy_array<T>(&mut self, len: usize) -> LazyArray<T> {
+        self.read_lazy_offset_then(|pos| LazyArray::from_position_and_num_elems(pos, len))
+    }
+
+    fn read_lazy_table<I, T>(&mut self, len: usize) -> LazyTable<I, T> {
+        self.read_lazy_offset_then(|pos| LazyTable::from_position_and_encoded_size(pos, len))
     }
 
     #[inline]
@@ -714,36 +635,29 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx
     }
 }
 
-impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
-    for Lazy<T>
-{
+impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyValue<T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
-        decoder.read_lazy_with_meta(())
+        decoder.read_lazy()
     }
 }
 
-impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
-    for Lazy<[T]>
-{
+impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyArray<T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         let len = decoder.read_usize();
-        if len == 0 { Lazy::empty() } else { decoder.read_lazy_with_meta(len) }
+        if len == 0 { LazyArray::empty() } else { decoder.read_lazy_array(len) }
     }
 }
 
-impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
-where
-    Option<T>: FixedSizeEncoding,
-{
+impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         let len = decoder.read_usize();
-        decoder.read_lazy_with_meta(len)
+        decoder.read_lazy_table(len)
     }
 }
 
 implement_ty_decoder!(DecodeContext<'a, 'tcx>);
 
-impl<'tcx> MetadataBlob {
+impl MetadataBlob {
     pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob {
         MetadataBlob(Lrc::new(metadata_ref))
     }
@@ -753,18 +667,18 @@ impl<'tcx> MetadataBlob {
     }
 
     pub(crate) fn get_rustc_version(&self) -> String {
-        Lazy::<String>::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap())
+        LazyValue::<String>::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap())
             .decode(self)
     }
 
-    pub(crate) fn get_root(&self) -> CrateRoot<'tcx> {
+    pub(crate) fn get_root<'tcx>(&self) -> CrateRoot<'tcx> {
         let slice = &self.blob()[..];
         let offset = METADATA_HEADER.len();
         let pos = (((slice[offset + 0] as u32) << 24)
             | ((slice[offset + 1] as u32) << 16)
             | ((slice[offset + 2] as u32) << 8)
             | ((slice[offset + 3] as u32) << 0)) as usize;
-        Lazy::<CrateRoot<'tcx>>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self)
+        LazyValue::<CrateRoot<'tcx>>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self)
     }
 
     pub(crate) fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> {
@@ -963,7 +877,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .tables
                 .children
                 .get(self, index)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| ty::FieldDef {
                     did: self.local_def_id(index),
@@ -996,7 +910,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .tables
                 .children
                 .get(self, item_id)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| self.get_variant(&self.kind(index), index, did))
                 .collect()
@@ -1016,7 +930,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
-        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
+        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
     }
 
     fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
@@ -1202,7 +1116,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(Lazy::empty)
+            .unwrap_or_else(LazyArray::empty)
             .decode((self, sess))
             .map(move |child_index| self.local_def_id(child_index))
     }
@@ -1278,7 +1192,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(Lazy::empty)
+            .unwrap_or_else(LazyArray::empty)
             .decode(self)
             .map(move |index| respan(self.get_span(index, sess), self.item_name(index)))
     }
@@ -1288,7 +1202,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(Lazy::empty)
+            .unwrap_or_else(LazyArray::empty)
             .decode(self)
             .map(move |field_index| self.get_visibility(field_index))
     }
@@ -1303,7 +1217,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .tables
                 .inherent_impls
                 .get(self, id)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| self.local_def_id(index)),
         )
@@ -1318,7 +1232,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .tables
                 .inherent_impls
                 .get(self, ty_index)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index)))
         })
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 065224a2a65..e3581a7607f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -1,14 +1,16 @@
-use super::LazyQueryDecodable;
 use crate::creader::{CStore, LoadedMacro};
 use crate::foreign_modules;
 use crate::native_libs;
 
 use rustc_ast as ast;
+use rustc_attr::Deprecation;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
+use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
+use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt, Visibility};
@@ -23,15 +25,80 @@ use rustc_data_structures::sync::Lrc;
 use smallvec::SmallVec;
 use std::any::Any;
 
+use super::{Decodable, DecodeContext, DecodeIterator};
+
+trait ProcessQueryValue<'tcx, T> {
+    fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T;
+}
+
+impl<T> ProcessQueryValue<'_, Option<T>> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option<T> {
+        self
+    }
+}
+
+impl<T> ProcessQueryValue<'_, T> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, err: impl Fn() -> !) -> T {
+        if let Some(value) = self { value } else { err() }
+    }
+}
+
+impl<'tcx, T: ArenaAllocatable<'tcx>> ProcessQueryValue<'tcx, &'tcx T> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx T {
+        if let Some(value) = self { tcx.arena.alloc(value) } else { err() }
+    }
+}
+
+impl<T, E> ProcessQueryValue<'_, Result<Option<T>, E>> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Result<Option<T>, E> {
+        Ok(self)
+    }
+}
+
+impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'tcx, &'tcx [T]>
+    for Option<DecodeIterator<'a, 'tcx, T>>
+{
+    #[inline(always)]
+    fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> &'tcx [T] {
+        if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { &[] }
+    }
+}
+
+impl ProcessQueryValue<'_, Option<DeprecationEntry>> for Option<Deprecation> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option<DeprecationEntry> {
+        self.map(DeprecationEntry::external)
+    }
+}
+
 macro_rules! provide_one {
     (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => {
         provide_one! {
             <$lt> $tcx, $def_id, $other, $cdata, $name => {
-                $cdata.root.tables.$name.get($cdata, $def_id.index).decode_query(
-                    $cdata,
-                    $tcx,
-                    || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)),
-                )
+                $cdata
+                    .root
+                    .tables
+                    .$name
+                    .get($cdata, $def_id.index)
+                    .map(|lazy| lazy.decode(($cdata, $tcx)))
+                    .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)))
+            }
+        }
+    };
+    (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => {
+        provide_one! {
+            <$lt> $tcx, $def_id, $other, $cdata, $name => {
+                // We don't decode `table_direct`, since it's not a Lazy, but an actual value
+                $cdata
+                    .root
+                    .tables
+                    .$name
+                    .get($cdata, $def_id.index)
+                    .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)))
             }
         }
     };
@@ -143,15 +210,15 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     lookup_deprecation_entry => { table }
     visibility => { table }
     unused_generic_params => { table }
-    opt_def_kind => { table }
+    opt_def_kind => { table_direct }
     impl_parent => { table }
-    impl_polarity => { table }
-    impl_defaultness => { table }
-    impl_constness => { table }
+    impl_polarity => { table_direct }
+    impl_defaultness => { table_direct }
+    impl_constness => { table_direct }
     coerce_unsized_info => { table }
     mir_const_qualif => { table }
     rendered_const => { table }
-    asyncness => { table }
+    asyncness => { table_direct }
     fn_arg_names => { table }
     generator_kind => { table }
     trait_def => { table }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index e66d226a441..28f289f06ec 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1,5 +1,5 @@
 use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
-use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
+use crate::rmeta::table::TableBuilder;
 use crate::rmeta::*;
 
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -17,7 +17,6 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::lang_items;
 use rustc_hir::{AnonConst, GenericParamKind};
 use rustc_index::bit_set::GrowableBitSet;
-use rustc_index::vec::Idx;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
@@ -38,6 +37,7 @@ use rustc_span::{
     self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
 };
 use rustc_target::abi::VariantIdx;
+use std::borrow::Borrow;
 use std::hash::Hash;
 use std::num::NonZeroUsize;
 use tracing::{debug, trace};
@@ -79,7 +79,7 @@ pub(super) struct EncodeContext<'a, 'tcx> {
 macro_rules! empty_proc_macro {
     ($self:ident) => {
         if $self.is_proc_macro {
-            return Lazy::empty();
+            return LazyArray::empty();
         }
     };
 }
@@ -124,33 +124,26 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
-    for Lazy<T>
-{
+impl<'a, 'tcx, T> Encodable<EncodeContext<'a, 'tcx>> for LazyValue<T> {
     fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        e.emit_lazy_distance(*self)
+        e.emit_lazy_distance(self.position)
     }
 }
 
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
-    for Lazy<[T]>
-{
+impl<'a, 'tcx, T> Encodable<EncodeContext<'a, 'tcx>> for LazyArray<T> {
     fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        e.emit_usize(self.meta)?;
-        if self.meta == 0 {
+        e.emit_usize(self.num_elems)?;
+        if self.num_elems == 0 {
             return Ok(());
         }
-        e.emit_lazy_distance(*self)
+        e.emit_lazy_distance(self.position)
     }
 }
 
-impl<'a, 'tcx, I: Idx, T> Encodable<EncodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
-where
-    Option<T>: FixedSizeEncoding,
-{
+impl<'a, 'tcx, I, T> Encodable<EncodeContext<'a, 'tcx>> for LazyTable<I, T> {
     fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        e.emit_usize(self.meta)?;
-        e.emit_lazy_distance(*self)
+        e.emit_usize(self.encoded_size)?;
+        e.emit_lazy_distance(self.position)
     }
 }
 
@@ -345,34 +338,7 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
     }
 }
 
-/// Helper trait to allow overloading `EncodeContext::lazy` for iterators.
-trait EncodeContentsForLazy<'a, 'tcx, T: ?Sized + LazyMeta> {
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> T::Meta;
-}
-
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, T> for &T {
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
-        self.encode(ecx).unwrap()
-    }
-}
-
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, T> for T {
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
-        self.encode(ecx).unwrap()
-    }
-}
-
-impl<'a, 'tcx, I, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, [T]> for I
-where
-    I: IntoIterator,
-    I::Item: EncodeContentsForLazy<'a, 'tcx, T>,
-{
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> usize {
-        self.into_iter().map(|value| value.encode_contents_for_lazy(ecx)).count()
-    }
-}
-
-// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy($value))`, which would
+// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
@@ -384,12 +350,24 @@ macro_rules! record {
     }};
 }
 
+// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
+// normally need extra variables to avoid errors about multiple mutable borrows.
+macro_rules! record_array {
+    ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
+        {
+            let value = $value;
+            let lazy = $self.lazy_array(value);
+            $self.$tables.$table.set($def_id.index, lazy);
+        }
+    }};
+}
+
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    fn emit_lazy_distance<T: ?Sized + LazyMeta>(
+    fn emit_lazy_distance(
         &mut self,
-        lazy: Lazy<T>,
+        position: NonZeroUsize,
     ) -> Result<(), <Self as Encoder>::Error> {
-        let pos = lazy.position.get();
+        let pos = position.get();
         let distance = match self.lazy_state {
             LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
             LazyState::NodeStart(start) => {
@@ -399,31 +377,51 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             LazyState::Previous(last_pos) => {
                 assert!(
-                    last_pos <= lazy.position,
+                    last_pos <= position,
                     "make sure that the calls to `lazy*` \
                      are in the same order as the metadata fields",
                 );
-                lazy.position.get() - last_pos.get()
+                position.get() - last_pos.get()
             }
         };
         self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap());
         self.emit_usize(distance)
     }
 
-    fn lazy<T: ?Sized + LazyMeta>(
+    fn lazy<T: Encodable<EncodeContext<'a, 'tcx>>, B: Borrow<T>>(
+        &mut self,
+        value: B,
+    ) -> LazyValue<T> {
+        let pos = NonZeroUsize::new(self.position()).unwrap();
+
+        assert_eq!(self.lazy_state, LazyState::NoNode);
+        self.lazy_state = LazyState::NodeStart(pos);
+        value.borrow().encode(self).unwrap();
+        self.lazy_state = LazyState::NoNode;
+
+        assert!(pos.get() <= self.position());
+
+        LazyValue::from_position(pos)
+    }
+
+    fn lazy_array<
+        T: Encodable<EncodeContext<'a, 'tcx>>,
+        I: IntoIterator<Item = B>,
+        B: Borrow<T>,
+    >(
         &mut self,
-        value: impl EncodeContentsForLazy<'a, 'tcx, T>,
-    ) -> Lazy<T> {
+        values: I,
+    ) -> LazyArray<T> {
         let pos = NonZeroUsize::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
         self.lazy_state = LazyState::NodeStart(pos);
-        let meta = value.encode_contents_for_lazy(self);
+        let len = values.into_iter().map(|value| value.borrow().encode(self).unwrap()).count();
         self.lazy_state = LazyState::NoNode;
 
         assert!(pos.get() <= self.position());
 
-        Lazy::from_position_and_meta(pos, meta)
+        LazyArray::from_position_and_num_elems(pos, len)
     }
 
     fn encode_info_for_items(&mut self) {
@@ -458,13 +456,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
-    fn encode_def_path_hash_map(&mut self) -> Lazy<DefPathHashMapRef<'tcx>> {
+    fn encode_def_path_hash_map(&mut self) -> LazyValue<DefPathHashMapRef<'tcx>> {
         self.lazy(DefPathHashMapRef::BorrowedFromTcx(
             self.tcx.resolutions(()).definitions.def_path_hash_to_def_index_map(),
         ))
     }
 
-    fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
+    fn encode_source_map(&mut self) -> LazyArray<rustc_span::SourceFile> {
         let source_map = self.tcx.sess.source_map();
         let all_source_files = source_map.files();
 
@@ -534,10 +532,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             })
             .collect::<Vec<_>>();
 
-        self.lazy(adapted.iter().map(|rc| &**rc))
+        self.lazy_array(adapted.iter().map(|rc| &**rc))
     }
 
-    fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
+    fn encode_crate_root(&mut self) -> LazyValue<CrateRoot<'tcx>> {
         let tcx = self.tcx;
         let mut i = self.position();
 
@@ -619,7 +617,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }
                 n = new_n;
             }
-            self.lazy(interpret_alloc_index)
+            self.lazy_array(interpret_alloc_index)
         };
 
         // Encode the proc macro data. This affects 'tables',
@@ -951,7 +949,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             .iter()
             .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty()));
 
-        record!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
+        record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
         if attrs.any(|attr| attr.may_have_doc_links()) {
             self.tables.may_have_doc_links.set(def_id.local_def_index, ());
         }
@@ -984,7 +982,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             if should_encode_variances(def_kind) {
                 let v = self.tcx.variances_of(def_id);
-                record!(self.tables.variances_of[def_id] <- v);
+                record_array!(self.tables.variances_of[def_id] <- v);
             }
             if should_encode_generics(def_kind) {
                 let g = tcx.generics_of(def_id);
@@ -992,7 +990,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id));
                 let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
                 if !inferred_outlives.is_empty() {
-                    record!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
+                    record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
                 }
             }
             if let DefKind::Trait | DefKind::TraitAlias = def_kind {
@@ -1004,7 +1002,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             if implementations.is_empty() {
                 continue;
             }
-            record!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| {
+            record_array!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| {
                 assert!(def_id.is_local());
                 def_id.index
             }));
@@ -1031,7 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
         self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
-        record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
+        record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
         }));
@@ -1079,11 +1077,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         // items - we encode information about proc-macros later on.
         let reexports = if !self.is_proc_macro {
             match tcx.module_reexports(local_def_id) {
-                Some(exports) => self.lazy(exports),
-                _ => Lazy::empty(),
+                Some(exports) => self.lazy_array(exports),
+                _ => LazyArray::empty(),
             }
         } else {
-            Lazy::empty()
+            LazyArray::empty()
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
@@ -1091,7 +1089,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             // Encode this here because we don't do it in encode_def_ids.
             record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
         } else {
-            record!(self.tables.children[def_id] <- iter_from_generator(|| {
+            record_array!(self.tables.children[def_id] <- iter_from_generator(|| {
                 for item_id in md.item_ids {
                     match tcx.hir().item(*item_id).kind {
                         // Foreign items are planted into their parent modules
@@ -1156,7 +1154,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
         let bounds = self.tcx.explicit_item_bounds(def_id);
         if !bounds.is_empty() {
-            record!(self.tables.explicit_item_bounds[def_id] <- bounds);
+            record_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
         }
     }
 
@@ -1188,10 +1186,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() };
                 match *m {
                     hir::TraitFn::Required(ref names) => {
-                        record!(self.tables.fn_arg_names[def_id] <- *names)
+                        record_array!(self.tables.fn_arg_names[def_id] <- *names)
                     }
                     hir::TraitFn::Provided(body) => {
-                        record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body))
+                        record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body))
                     }
                 };
                 self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
@@ -1253,7 +1251,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             ty::AssocKind::Fn => {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
-                record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
+                record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
@@ -1385,7 +1383,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemKind::Fn(ref sig, .., body) => {
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
-                record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
+                record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 self.tables.impl_constness.set(def_id.index, sig.header.constness);
                 EntryKind::Fn
             }
@@ -1485,14 +1483,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         record!(self.tables.kind[def_id] <- entry_kind);
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
-            hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <-
+            hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
                 self.tcx.adt_def(def_id).variants().iter().map(|v| {
                     assert!(v.def_id.is_local());
                     v.def_id.index
                 })
             ),
             hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                record!(self.tables.children[def_id] <-
+                record_array!(self.tables.children[def_id] <-
                     self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
                         assert!(f.did.is_local());
                         f.did.index
@@ -1501,7 +1499,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => {
                 let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
-                record!(self.tables.children[def_id] <-
+                record_array!(self.tables.children[def_id] <-
                     associated_item_def_ids.iter().map(|&def_id| {
                         assert!(def_id.is_local());
                         def_id.index
@@ -1583,16 +1581,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.encode_item_type(def_id.to_def_id());
     }
 
-    fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> {
+    fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> {
         empty_proc_macro!(self);
         let used_libraries = self.tcx.native_libraries(LOCAL_CRATE);
-        self.lazy(used_libraries.iter())
+        self.lazy_array(used_libraries.iter())
     }
 
-    fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> {
+    fn encode_foreign_modules(&mut self) -> LazyArray<ForeignModule> {
         empty_proc_macro!(self);
         let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE);
-        self.lazy(foreign_modules.iter().map(|(_, m)| m).cloned())
+        self.lazy_array(foreign_modules.iter().map(|(_, m)| m).cloned())
     }
 
     fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTable) {
@@ -1631,7 +1629,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index;
             let stability = tcx.lookup_stability(CRATE_DEF_ID);
             let macros =
-                self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
+                self.lazy_array(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
             let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
             for (i, span) in spans.into_iter().enumerate() {
                 let span = self.lazy(span);
@@ -1697,12 +1695,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
-    fn encode_debugger_visualizers(&mut self) -> Lazy<[DebuggerVisualizerFile]> {
+    fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> {
         empty_proc_macro!(self);
-        self.lazy(self.tcx.debugger_visualizers(LOCAL_CRATE).iter())
+        self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter())
     }
 
-    fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> {
+    fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> {
         empty_proc_macro!(self);
 
         let deps = self
@@ -1734,29 +1732,29 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         // the assumption that they are numbered 1 to n.
         // FIXME (#2166): This is not nearly enough to support correct versioning
         // but is enough to get transitive crate dependencies working.
-        self.lazy(deps.iter().map(|&(_, ref dep)| dep))
+        self.lazy_array(deps.iter().map(|&(_, ref dep)| dep))
     }
 
-    fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option<Symbol>)]> {
+    fn encode_lib_features(&mut self) -> LazyArray<(Symbol, Option<Symbol>)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let lib_features = tcx.lib_features(());
-        self.lazy(lib_features.to_vec())
+        self.lazy_array(lib_features.to_vec())
     }
 
-    fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> {
+    fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id;
-        self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
+        self.lazy_array(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
     }
 
-    fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> {
+    fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, usize)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let lang_items = tcx.lang_items();
         let lang_items = lang_items.items().iter();
-        self.lazy(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
+        self.lazy_array(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
             if let Some(def_id) = opt_def_id {
                 if def_id.is_local() {
                     return Some((def_id.index, i));
@@ -1766,19 +1764,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }))
     }
 
-    fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> {
+    fn encode_lang_items_missing(&mut self) -> LazyArray<lang_items::LangItem> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
-        self.lazy(&tcx.lang_items().missing)
+        self.lazy_array(&tcx.lang_items().missing)
     }
 
-    fn encode_traits(&mut self) -> Lazy<[DefIndex]> {
+    fn encode_traits(&mut self) -> LazyArray<DefIndex> {
         empty_proc_macro!(self);
-        self.lazy(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index))
+        self.lazy_array(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index))
     }
 
     /// Encodes an index, mapping each trait to its (local) implementations.
-    fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
+    fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
         debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
         let tcx = self.tcx;
@@ -1817,15 +1815,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
                 TraitImpls {
                     trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
-                    impls: self.lazy(&impls),
+                    impls: self.lazy_array(&impls),
                 }
             })
             .collect();
 
-        self.lazy(&all_impls)
+        self.lazy_array(&all_impls)
     }
 
-    fn encode_incoherent_impls(&mut self) -> Lazy<[IncoherentImpls]> {
+    fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> {
         debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
         let tcx = self.tcx;
@@ -1845,11 +1843,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     tcx.hir().def_path_hash(LocalDefId { local_def_index })
                 });
 
-                IncoherentImpls { self_ty: simp, impls: self.lazy(impls) }
+                IncoherentImpls { self_ty: simp, impls: self.lazy_array(impls) }
             })
             .collect();
 
-        self.lazy(&all_impls)
+        self.lazy_array(&all_impls)
     }
 
     // Encodes all symbols exported from this crate into the metadata.
@@ -1861,13 +1859,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_exported_symbols(
         &mut self,
         exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)],
-    ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportInfo)]> {
+    ) -> LazyArray<(ExportedSymbol<'tcx>, SymbolExportInfo)> {
         empty_proc_macro!(self);
         // The metadata symbol name is special. It should not show up in
         // downstream crates.
         let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx));
 
-        self.lazy(
+        self.lazy_array(
             exported_symbols
                 .iter()
                 .filter(|&&(ref exported_symbol, _)| match *exported_symbol {
@@ -1878,21 +1876,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         )
     }
 
-    fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option<LinkagePreference>]> {
+    fn encode_dylib_dependency_formats(&mut self) -> LazyArray<Option<LinkagePreference>> {
         empty_proc_macro!(self);
         let formats = self.tcx.dependency_formats(());
         for (ty, arr) in formats.iter() {
             if *ty != CrateType::Dylib {
                 continue;
             }
-            return self.lazy(arr.iter().map(|slot| match *slot {
+            return self.lazy_array(arr.iter().map(|slot| match *slot {
                 Linkage::NotLinked | Linkage::IncludedFromDylib => None,
 
                 Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
                 Linkage::Static => Some(LinkagePreference::RequireStatic),
             }));
         }
-        Lazy::empty()
+        LazyArray::empty()
     }
 
     fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) {
@@ -1903,7 +1901,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
                 self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync);
-                record!(self.tables.fn_arg_names[def_id] <- *names);
+                record_array!(self.tables.fn_arg_names[def_id] <- *names);
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
                 } else {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 7ae177c3a56..00c4dc3955d 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,7 +1,7 @@
 use crate::creader::CrateMetadataRef;
 use decoder::Metadata;
 use def_path_hash_map::DefPathHashMapRef;
-use table::{Table, TableBuilder};
+use table::TableBuilder;
 
 use rustc_ast as ast;
 use rustc_attr as attr;
@@ -20,8 +20,8 @@ use rustc_middle::mir;
 use rustc_middle::thir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::GeneratorDiagnosticData;
 use rustc_middle::ty::{self, ReprOptions, Ty};
+use rustc_middle::ty::{GeneratorDiagnosticData, TyCtxt};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
@@ -62,20 +62,6 @@ const METADATA_VERSION: u8 = 6;
 /// and further followed by the rustc version string.
 pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
-/// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`,
-/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
-trait LazyMeta {
-    type Meta: Copy + 'static;
-}
-
-impl<T> LazyMeta for T {
-    type Meta = ();
-}
-
-impl<T> LazyMeta for [T] {
-    type Meta = usize;
-}
-
 /// A value of type T referred to by its absolute position
 /// in the metadata, and which can be decoded lazily.
 ///
@@ -91,8 +77,19 @@ impl<T> LazyMeta for [T] {
 /// Distances start at 1, as 0-byte nodes are invalid.
 /// Also invalid are nodes being referred in a different
 /// order than they were encoded in.
-///
-/// # Sequences (`Lazy<[T]>`)
+#[must_use]
+struct LazyValue<T> {
+    position: NonZeroUsize,
+    _marker: PhantomData<fn() -> T>,
+}
+
+impl<T> LazyValue<T> {
+    fn from_position(position: NonZeroUsize) -> LazyValue<T> {
+        LazyValue { position, _marker: PhantomData }
+    }
+}
+
+/// A list of lazily-decoded values.
 ///
 /// Unlike `Lazy<Vec<T>>`, the length is encoded next to the
 /// position, not at the position, which means that the length
@@ -102,39 +99,58 @@ impl<T> LazyMeta for [T] {
 /// the encoding is that of `Lazy`, with the distinction that
 /// the minimal distance the length of the sequence, i.e.
 /// it's assumed there's no 0-byte element in the sequence.
-#[must_use]
-// FIXME(#59875) the `Meta` parameter only exists to dodge
-// invariance wrt `T` (coming from the `meta: T::Meta` field).
-struct Lazy<T, Meta = <T as LazyMeta>::Meta>
-where
-    T: ?Sized + LazyMeta<Meta = Meta>,
-    Meta: 'static + Copy,
-{
+struct LazyArray<T> {
+    position: NonZeroUsize,
+    num_elems: usize,
+    _marker: PhantomData<fn() -> T>,
+}
+
+impl<T> LazyArray<T> {
+    fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray<T> {
+        LazyArray { position, num_elems, _marker: PhantomData }
+    }
+
+    fn empty() -> LazyArray<T> {
+        LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0)
+    }
+}
+
+/// A list of lazily-decoded values, with the added capability of random access.
+///
+/// Random-access table (i.e. offering constant-time `get`/`set`), similar to
+/// `LazyArray<T>`, but without requiring encoding or decoding all the values
+/// eagerly and in-order.
+struct LazyTable<I, T> {
     position: NonZeroUsize,
-    meta: Meta,
-    _marker: PhantomData<T>,
+    encoded_size: usize,
+    _marker: PhantomData<fn(I) -> T>,
 }
 
-impl<T: ?Sized + LazyMeta> Lazy<T> {
-    fn from_position_and_meta(position: NonZeroUsize, meta: T::Meta) -> Lazy<T> {
-        Lazy { position, meta, _marker: PhantomData }
+impl<I, T> LazyTable<I, T> {
+    fn from_position_and_encoded_size(
+        position: NonZeroUsize,
+        encoded_size: usize,
+    ) -> LazyTable<I, T> {
+        LazyTable { position, encoded_size, _marker: PhantomData }
     }
 }
 
-impl<T> Lazy<T> {
-    fn from_position(position: NonZeroUsize) -> Lazy<T> {
-        Lazy::from_position_and_meta(position, ())
+impl<T> Copy for LazyValue<T> {}
+impl<T> Clone for LazyValue<T> {
+    fn clone(&self) -> Self {
+        *self
     }
 }
 
-impl<T> Lazy<[T]> {
-    fn empty() -> Lazy<[T]> {
-        Lazy::from_position_and_meta(NonZeroUsize::new(1).unwrap(), 0)
+impl<T> Copy for LazyArray<T> {}
+impl<T> Clone for LazyArray<T> {
+    fn clone(&self) -> Self {
+        *self
     }
 }
 
-impl<T: ?Sized + LazyMeta> Copy for Lazy<T> {}
-impl<T: ?Sized + LazyMeta> Clone for Lazy<T> {
+impl<I, T> Copy for LazyTable<I, T> {}
+impl<I, T> Clone for LazyTable<I, T> {
     fn clone(&self) -> Self {
         *self
     }
@@ -155,29 +171,20 @@ enum LazyState {
     Previous(NonZeroUsize),
 }
 
-// FIXME(#59875) `Lazy!(T)` replaces `Lazy<T>`, passing the `Meta` parameter
-// manually, instead of relying on the default, to get the correct variance.
-// Only needed when `T` itself contains a parameter (e.g. `'tcx`).
-macro_rules! Lazy {
-    (Table<$I:ty, $T:ty>) => {Lazy<Table<$I, $T>, usize>};
-    ([$T:ty]) => {Lazy<[$T], usize>};
-    ($T:ty) => {Lazy<$T, ()>};
-}
-
-type SyntaxContextTable = Lazy<Table<u32, Lazy<SyntaxContextData>>>;
-type ExpnDataTable = Lazy<Table<ExpnIndex, Lazy<ExpnData>>>;
-type ExpnHashTable = Lazy<Table<ExpnIndex, Lazy<ExpnHash>>>;
+type SyntaxContextTable = LazyTable<u32, LazyValue<SyntaxContextData>>;
+type ExpnDataTable = LazyTable<ExpnIndex, LazyValue<ExpnData>>;
+type ExpnHashTable = LazyTable<ExpnIndex, LazyValue<ExpnHash>>;
 
 #[derive(MetadataEncodable, MetadataDecodable)]
 pub(crate) struct ProcMacroData {
     proc_macro_decls_static: DefIndex,
     stability: Option<attr::Stability>,
-    macros: Lazy<[DefIndex]>,
+    macros: LazyArray<DefIndex>,
 }
 
 /// Serialized metadata for a crate.
 /// When compiling a proc-macro crate, we encode many of
-/// the `Lazy<[T]>` fields as `Lazy::empty()`. This serves two purposes:
+/// the `LazyArray<T>` fields as `Lazy::empty()`. This serves two purposes:
 ///
 /// 1. We avoid performing unnecessary work. Proc-macro crates can only
 /// export proc-macros functions, which are compiled into a shared library.
@@ -205,32 +212,32 @@ pub(crate) struct CrateRoot<'tcx> {
     has_panic_handler: bool,
     has_default_lib_allocator: bool,
 
-    crate_deps: Lazy<[CrateDep]>,
-    dylib_dependency_formats: Lazy<[Option<LinkagePreference>]>,
-    lib_features: Lazy<[(Symbol, Option<Symbol>)]>,
-    lang_items: Lazy<[(DefIndex, usize)]>,
-    lang_items_missing: Lazy<[lang_items::LangItem]>,
-    diagnostic_items: Lazy<[(Symbol, DefIndex)]>,
-    native_libraries: Lazy<[NativeLib]>,
-    foreign_modules: Lazy<[ForeignModule]>,
-    traits: Lazy<[DefIndex]>,
-    impls: Lazy<[TraitImpls]>,
-    incoherent_impls: Lazy<[IncoherentImpls]>,
-    interpret_alloc_index: Lazy<[u32]>,
+    crate_deps: LazyArray<CrateDep>,
+    dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
+    lib_features: LazyArray<(Symbol, Option<Symbol>)>,
+    lang_items: LazyArray<(DefIndex, usize)>,
+    lang_items_missing: LazyArray<lang_items::LangItem>,
+    diagnostic_items: LazyArray<(Symbol, DefIndex)>,
+    native_libraries: LazyArray<NativeLib>,
+    foreign_modules: LazyArray<ForeignModule>,
+    traits: LazyArray<DefIndex>,
+    impls: LazyArray<TraitImpls>,
+    incoherent_impls: LazyArray<IncoherentImpls>,
+    interpret_alloc_index: LazyArray<u32>,
     proc_macro_data: Option<ProcMacroData>,
 
     tables: LazyTables<'tcx>,
-    debugger_visualizers: Lazy<[rustc_span::DebuggerVisualizerFile]>,
+    debugger_visualizers: LazyArray<rustc_span::DebuggerVisualizerFile>,
 
-    exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportInfo)]),
+    exported_symbols: LazyArray<(ExportedSymbol<'tcx>, SymbolExportInfo)>,
 
     syntax_contexts: SyntaxContextTable,
     expn_data: ExpnDataTable,
     expn_hashes: ExpnHashTable,
 
-    def_path_hash_map: Lazy<DefPathHashMapRef<'tcx>>,
+    def_path_hash_map: LazyValue<DefPathHashMapRef<'tcx>>,
 
-    source_map: Lazy<[rustc_span::SourceFile]>,
+    source_map: LazyArray<rustc_span::SourceFile>,
 
     compiler_builtins: bool,
     needs_allocator: bool,
@@ -257,7 +264,12 @@ impl Into<RawDefId> for DefId {
 }
 
 impl RawDefId {
-    fn decode(self, cdata: CrateMetadataRef<'_>) -> DefId {
+    /// This exists so that `provide_one!` is happy
+    fn decode(self, meta: (CrateMetadataRef<'_>, TyCtxt<'_>)) -> DefId {
+        self.decode_from_cdata(meta.0)
+    }
+
+    fn decode_from_cdata(self, cdata: CrateMetadataRef<'_>) -> DefId {
         let krate = CrateNum::from_u32(self.krate);
         let krate = cdata.map_encoded_cnum_to_current(krate);
         DefId { krate, index: DefIndex::from_u32(self.index) }
@@ -276,13 +288,13 @@ pub(crate) struct CrateDep {
 #[derive(MetadataEncodable, MetadataDecodable)]
 pub(crate) struct TraitImpls {
     trait_id: (u32, DefIndex),
-    impls: Lazy<[(DefIndex, Option<SimplifiedType>)]>,
+    impls: LazyArray<(DefIndex, Option<SimplifiedType>)>,
 }
 
 #[derive(MetadataEncodable, MetadataDecodable)]
 pub(crate) struct IncoherentImpls {
     self_ty: SimplifiedType,
-    impls: Lazy<[DefIndex]>,
+    impls: LazyArray<DefIndex>,
 }
 
 /// Define `LazyTables` and `TableBuilders` at the same time.
@@ -290,7 +302,7 @@ macro_rules! define_tables {
     ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => {
         #[derive(MetadataEncodable, MetadataDecodable)]
         pub(crate) struct LazyTables<'tcx> {
-            $($name: Lazy!(Table<$IDX, $T>)),+
+            $($name: LazyTable<$IDX, $T>),+
         }
 
         #[derive(Default)]
@@ -309,61 +321,62 @@ macro_rules! define_tables {
 }
 
 define_tables! {
-    kind: Table<DefIndex, Lazy<EntryKind>>,
-    attributes: Table<DefIndex, Lazy<[ast::Attribute]>>,
-    children: Table<DefIndex, Lazy<[DefIndex]>>,
+    kind: Table<DefIndex, LazyValue<EntryKind>>,
+    attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
+    children: Table<DefIndex, LazyArray<DefIndex>>,
 
     opt_def_kind: Table<DefIndex, DefKind>,
-    visibility: Table<DefIndex, Lazy<ty::Visibility>>,
-    def_span: Table<DefIndex, Lazy<Span>>,
-    def_ident_span: Table<DefIndex, Lazy<Span>>,
-    lookup_stability: Table<DefIndex, Lazy<attr::Stability>>,
-    lookup_const_stability: Table<DefIndex, Lazy<attr::ConstStability>>,
-    lookup_deprecation_entry: Table<DefIndex, Lazy<attr::Deprecation>>,
+    visibility: Table<DefIndex, LazyValue<ty::Visibility>>,
+    def_span: Table<DefIndex, LazyValue<Span>>,
+    def_ident_span: Table<DefIndex, LazyValue<Span>>,
+    lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
+    lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
+    lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
     // As an optimization, a missing entry indicates an empty `&[]`.
-    explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
-    explicit_predicates_of: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
-    generics_of: Table<DefIndex, Lazy<ty::Generics>>,
+    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'tcx>, Span)>>,
+    explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'tcx>>>,
+    generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
     // As an optimization, a missing entry indicates an empty `&[]`.
-    inferred_outlives_of: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
-    super_predicates_of: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
-    type_of: Table<DefIndex, Lazy!(Ty<'tcx>)>,
-    variances_of: Table<DefIndex, Lazy<[ty::Variance]>>,
-    fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
-    codegen_fn_attrs: Table<DefIndex, Lazy!(CodegenFnAttrs)>,
-    impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
-    const_param_default: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
-    optimized_mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
-    mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
-    promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
-    thir_abstract_const: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
+    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Predicate<'tcx>, Span)>>,
+    super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'tcx>>>,
+    type_of: Table<DefIndex, LazyValue<Ty<'tcx>>>,
+    variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
+    fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'tcx>>>,
+    codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
+    impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'tcx>>>,
+    const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'tcx>>>,
+    optimized_mir: Table<DefIndex, LazyValue<mir::Body<'tcx>>>,
+    mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'tcx>>>,
+    promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'tcx>>>>,
+    // FIXME(compiler-errors): Why isn't this a LazyArray?
+    thir_abstract_const: Table<DefIndex, LazyValue<&'tcx [thir::abstract_const::Node<'tcx>]>>,
     impl_parent: Table<DefIndex, RawDefId>,
     impl_polarity: Table<DefIndex, ty::ImplPolarity>,
     impl_constness: Table<DefIndex, hir::Constness>,
     is_intrinsic: Table<DefIndex, ()>,
     impl_defaultness: Table<DefIndex, hir::Defaultness>,
     // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
-    coerce_unsized_info: Table<DefIndex, Lazy!(ty::adjustment::CoerceUnsizedInfo)>,
-    mir_const_qualif: Table<DefIndex, Lazy!(mir::ConstQualifs)>,
-    rendered_const: Table<DefIndex, Lazy!(String)>,
+    coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
+    mir_const_qualif: Table<DefIndex, LazyValue<mir::ConstQualifs>>,
+    rendered_const: Table<DefIndex, LazyValue<String>>,
     asyncness: Table<DefIndex, hir::IsAsync>,
-    fn_arg_names: Table<DefIndex, Lazy!([Ident])>,
-    generator_kind: Table<DefIndex, Lazy!(hir::GeneratorKind)>,
-    trait_def: Table<DefIndex, Lazy!(ty::TraitDef)>,
+    fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
+    generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>,
+    trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
 
     trait_item_def_id: Table<DefIndex, RawDefId>,
-    inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
-    expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
-    unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
-    repr_options: Table<DefIndex, Lazy<ReprOptions>>,
+    inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
+    expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
+    unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
+    repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
     // `DefPathTable`. This allows us to avoid deserializing an entire
     // `DefPathTable` up front, since we may only ever use a few
     // definitions from any given crate.
-    def_keys: Table<DefIndex, Lazy<DefKey>>,
+    def_keys: Table<DefIndex, LazyValue<DefKey>>,
     def_path_hashes: Table<DefIndex, DefPathHash>,
-    proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
-    generator_diagnostic_data: Table<DefIndex, Lazy<GeneratorDiagnosticData<'tcx>>>,
+    proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
+    generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'tcx>>>,
     may_have_doc_links: Table<DefIndex, ()>,
 }
 
@@ -382,19 +395,19 @@ enum EntryKind {
     OpaqueTy,
     Enum,
     Field,
-    Variant(Lazy<VariantData>),
-    Struct(Lazy<VariantData>),
-    Union(Lazy<VariantData>),
+    Variant(LazyValue<VariantData>),
+    Struct(LazyValue<VariantData>),
+    Union(LazyValue<VariantData>),
     Fn,
     ForeignFn,
-    Mod(Lazy<[ModChild]>),
-    MacroDef(Lazy<ast::MacArgs>, /*macro_rules*/ bool),
+    Mod(LazyArray<ModChild>),
+    MacroDef(LazyValue<ast::MacArgs>, /*macro_rules*/ bool),
     ProcMacro(MacroKind),
     Closure,
     Generator,
     Trait,
     Impl,
-    AssocFn(Lazy<AssocFnData>),
+    AssocFn(LazyValue<AssocFnData>),
     AssocType(AssocContainer),
     AssocConst(AssocContainer),
     TraitAlias,
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 53fc2efe00b..60c5143a6c3 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -201,15 +201,15 @@ impl FixedSizeEncoding for Option<()> {
 }
 
 // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
-// generic `Lazy<T>` impl, but in the general case we might not need / want to
-// fit every `usize` in `u32`.
-impl<T> FixedSizeEncoding for Option<Lazy<T>> {
+// generic `LazyValue<T>` impl, but in the general case we might not need / want
+// to fit every `usize` in `u32`.
+impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
     type ByteArray = [u8; 4];
 
     #[inline]
     fn from_bytes(b: &[u8; 4]) -> Self {
         let position = NonZeroUsize::new(u32::from_bytes(b) as usize)?;
-        Some(Lazy::from_position(position))
+        Some(LazyValue::from_position(position))
     }
 
     #[inline]
@@ -220,7 +220,7 @@ impl<T> FixedSizeEncoding for Option<Lazy<T>> {
     }
 }
 
-impl<T> FixedSizeEncoding for Option<Lazy<[T]>> {
+impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
     type ByteArray = [u8; 8];
 
     #[inline]
@@ -228,7 +228,7 @@ impl<T> FixedSizeEncoding for Option<Lazy<[T]>> {
         let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
         let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
         let len = u32::from_bytes(meta_bytes) as usize;
-        Some(Lazy::from_position_and_meta(position, len))
+        Some(LazyArray::from_position_and_num_elems(position, len))
     }
 
     #[inline]
@@ -239,28 +239,12 @@ impl<T> FixedSizeEncoding for Option<Lazy<[T]>> {
         let position: u32 = position.try_into().unwrap();
         position.write_to_bytes(position_bytes);
 
-        let len = self.map_or(0, |lazy| lazy.meta);
+        let len = self.map_or(0, |lazy| lazy.num_elems);
         let len: u32 = len.try_into().unwrap();
         len.write_to_bytes(meta_bytes);
     }
 }
 
-/// Random-access table (i.e. offering constant-time `get`/`set`), similar to
-/// `Vec<Option<T>>`, but without requiring encoding or decoding all the values
-/// eagerly and in-order.
-/// A total of `(max_idx + 1)` times `Option<T> as FixedSizeEncoding>::ByteArray`
-/// are used for a table, where `max_idx` is the largest index passed to
-/// `TableBuilder::set`.
-pub(super) struct Table<I: Idx, T>
-where
-    Option<T>: FixedSizeEncoding,
-{
-    _marker: PhantomData<(fn(&I), T)>,
-    // NOTE(eddyb) this makes `Table` not implement `Sized`, but no
-    // value of `Table` is ever created (it's always behind `Lazy`).
-    _bytes: [u8],
-}
-
 /// Helper for constructing a table's serialization (also see `Table`).
 pub(super) struct TableBuilder<I: Idx, T>
 where
@@ -296,7 +280,7 @@ where
         Some(value).write_to_bytes(&mut self.blocks[i]);
     }
 
-    pub(crate) fn encode<const N: usize>(&self, buf: &mut Encoder) -> Lazy<Table<I, T>>
+    pub(crate) fn encode<const N: usize>(&self, buf: &mut Encoder) -> LazyTable<I, T>
     where
         Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
     {
@@ -305,19 +289,14 @@ where
             buf.emit_raw_bytes(block).unwrap();
         }
         let num_bytes = self.blocks.len() * N;
-        Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), num_bytes)
+        LazyTable::from_position_and_encoded_size(
+            NonZeroUsize::new(pos as usize).unwrap(),
+            num_bytes,
+        )
     }
 }
 
-impl<I: Idx, T> LazyMeta for Table<I, T>
-where
-    Option<T>: FixedSizeEncoding,
-{
-    /// Number of bytes in the data stream.
-    type Meta = usize;
-}
-
-impl<I: Idx, T> Lazy<Table<I, T>>
+impl<I: Idx, T> LazyTable<I, T>
 where
     Option<T>: FixedSizeEncoding,
 {
@@ -331,10 +310,10 @@ where
     where
         Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
     {
-        debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
+        debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size);
 
         let start = self.position.get();
-        let bytes = &metadata.blob()[start..start + self.meta];
+        let bytes = &metadata.blob()[start..start + self.encoded_size];
         let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
         let bytes = bytes.get(i.index())?;
         FixedSizeEncoding::from_bytes(bytes)
@@ -345,6 +324,6 @@ where
     where
         Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
     {
-        self.meta / N
+        self.encoded_size / N
     }
 }