Auto merge of #97291 - compiler-errors:lazy-is-actually-3-types-in-a-trenchcoat, r=cjgillot

Split out the various responsibilities of `rustc_metadata::Lazy`

`Lazy<T>` actually acts like three different types -- a pointer in the crate metadata to a single value, a pointer to a list/array of values, and an indexable pointer of a list of values (a table).

We currently overload `Lazy<T>` to work differently than `Lazy<[T]>` and the same for `Lazy<Table<I, T>>`. All is well with some helper adapter traits such as [`LazyQueryDecodable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/decoder/trait.LazyQueryDecodable.html) and [`EncodeContentsForLazy`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/encoder/trait.EncodeContentsForLazy.html).

Well, changes in #97287 that make `Lazy` work with the now invariant lifetime `'tcx` make these adapters fall apart because of coherence reasons. So we split out these three types and rework some of the helper traits so it's both 1. more clear to understand, and 2. compatible with the changes later in that PR.

Split out from #97287 so it can be reviewed separately, since this PR stands on its own.
This commit is contained in:
bors 2022-05-24 13:42:33 +00:00
commit ee9726cb10
6 changed files with 404 additions and 432 deletions

View File

@ -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"]

View File

@ -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 {
struct DecodeIterator<'a, 'tcx, T> {
elem_counter: std::ops::Range<usize>,
dcx: DecodeContext<'a, 'tcx>,
_phantom: PhantomData<fn() -> T>,
}
impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Iterator for DecodeIterator<'a, 'tcx, T> {
type Item = T;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.elem_counter.next().map(|_| T::decode(&mut self.dcx))
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.elem_counter.size_hint()
}
}
impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> ExactSizeIterator
for DecodeIterator<'a, 'tcx, T>
{
}
unsafe impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> TrustedLen
for DecodeIterator<'a, 'tcx, T>
{
}
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);
(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() }
}
}
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> 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)))
}
}
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))))
}
}
impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx [T]> for Option<Lazy<[T], usize>>
where
T: Decodable<DecodeContext<'a, 'tcx>> + Copy,
{
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>>
{
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))
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)))
})

View File

@ -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 }

View File

@ -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: impl EncodeContentsForLazy<'a, 'tcx, T>,
) -> Lazy<T> {
value: B,
) -> LazyValue<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);
value.borrow().encode(self).unwrap();
self.lazy_state = LazyState::NoNode;
assert!(pos.get() <= self.position());
Lazy::from_position_and_meta(pos, meta)
LazyValue::from_position(pos)
}
fn lazy_array<
T: Encodable<EncodeContext<'a, 'tcx>>,
I: IntoIterator<Item = B>,
B: Borrow<T>,
>(
&mut self,
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 len = values.into_iter().map(|value| value.borrow().encode(self).unwrap()).count();
self.lazy_state = LazyState::NoNode;
assert!(pos.get() <= self.position());
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 {

View File

@ -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,
meta: Meta,
_marker: PhantomData<T>,
num_elems: usize,
_marker: PhantomData<fn() -> 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<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)
}
}
impl<T> Lazy<T> {
fn from_position(position: NonZeroUsize) -> Lazy<T> {
Lazy::from_position_and_meta(position, ())
/// 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,
encoded_size: usize,
_marker: PhantomData<fn(I) -> T>,
}
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 empty() -> Lazy<[T]> {
Lazy::from_position_and_meta(NonZeroUsize::new(1).unwrap(), 0)
impl<T> Copy for LazyValue<T> {}
impl<T> Clone for LazyValue<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized + LazyMeta> Copy for Lazy<T> {}
impl<T: ?Sized + LazyMeta> Clone for Lazy<T> {
impl<T> Copy for LazyArray<T> {}
impl<T> Clone for LazyArray<T> {
fn clone(&self) -> Self {
*self
}
}
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,

View File

@ -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
}
}