diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 3df18098a07fd..5e4c1284e241e 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 4038af38a2cbe..72b7c08f04bc2 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)]>>, + trait_impls: FxHashMap<(u32, DefIndex), LazyArray<(DefIndex, Option)>>, /// 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>, + incoherent_impls: FxHashMap>, /// 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>> Lazy { +impl<'a, 'tcx, T: Decodable>> LazyValue { fn decode>(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>> Lazy { } } -impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable>> Lazy<[T]> { - fn decode>( - self, - metadata: M, - ) -> impl ExactSizeIterator + 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 { - 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, + dcx: DecodeContext<'a, 'tcx>, + _phantom: PhantomData T>, } -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option> -where - T: Decodable>, -{ - 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> -where - T: Decodable>, - 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>> Iterator for DecodeIterator<'a, 'tcx, T> { + type Item = T; -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, Option> for Option> -where - T: Decodable>, -{ - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - _err: impl FnOnce() -> !, - ) -> Option { - self.map(|l| l.decode((cdata, tcx))) + #[inline(always)] + fn next(&mut self) -> Option { + self.elem_counter.next().map(|_| T::decode(&mut self.dcx)) } -} -impl<'a, 'tcx, T, E> LazyQueryDecodable<'a, 'tcx, Result, E>> for Option> -where - T: Decodable>, -{ - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - _err: impl FnOnce() -> !, - ) -> Result, E> { - Ok(self.map(|l| l.decode((cdata, tcx)))) + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.elem_counter.size_hint() } } -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx [T]> for Option> -where - T: Decodable> + Copy, +impl<'a, 'tcx, T: Decodable>> 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> - for Option> +unsafe impl<'a, 'tcx, T: Decodable>> TrustedLen + for DecodeIterator<'a, 'tcx, T> { - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - _err: impl FnOnce() -> !, - ) -> Option { - self.map(|l| l.decode((cdata, tcx))).map(DeprecationEntry::external) - } } -impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option> for Option { - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - _: TyCtxt<'tcx>, - _: impl FnOnce() -> !, - ) -> Option { - self.map(|raw_def_id| raw_def_id.decode(cdata)) +impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable>> LazyArray { + fn decode>(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(&mut self, meta: T::Meta) -> Lazy { + #[inline] + fn read_lazy_offset_then(&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(&mut self) -> LazyValue { + self.read_lazy_offset_then(|pos| LazyValue::from_position(pos)) + } + + fn read_lazy_array(&mut self, len: usize) -> LazyArray { + self.read_lazy_offset_then(|pos| LazyArray::from_position_and_num_elems(pos, len)) + } + + fn read_lazy_table(&mut self, len: usize) -> LazyTable { + self.read_lazy_offset_then(|pos| LazyTable::from_position_and_encoded_size(pos, len)) } #[inline] @@ -714,36 +635,29 @@ impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx } } -impl<'a, 'tcx, T: Decodable>> Decodable> - for Lazy -{ +impl<'a, 'tcx, T> Decodable> for LazyValue { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { - decoder.read_lazy_with_meta(()) + decoder.read_lazy() } } -impl<'a, 'tcx, T: Decodable>> Decodable> - for Lazy<[T]> -{ +impl<'a, 'tcx, T> Decodable> for LazyArray { 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> for Lazy> -where - Option: FixedSizeEncoding, -{ +impl<'a, 'tcx, I: Idx, T> Decodable> for LazyTable { 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::::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap()) + LazyValue::::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::>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self) + LazyValue::>::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 { - 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 065224a2a65d7..e3581a7607fb8 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 ProcessQueryValue<'_, Option> for Option { + #[inline(always)] + fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option { + self + } +} + +impl ProcessQueryValue<'_, T> for Option { + #[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 { + #[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 ProcessQueryValue<'_, Result, E>> for Option { + #[inline(always)] + fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Result, E> { + Ok(self) + } +} + +impl<'a, 'tcx, T: Copy + Decodable>> ProcessQueryValue<'tcx, &'tcx [T]> + for Option> +{ + #[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> for Option { + #[inline(always)] + fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option { + 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 e66d226a441e4..28f289f06ecb2 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>> Encodable> - for Lazy -{ +impl<'a, 'tcx, T> Encodable> for LazyValue { 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>> Encodable> - for Lazy<[T]> -{ +impl<'a, 'tcx, T> Encodable> for LazyArray { 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> for Lazy> -where - Option: FixedSizeEncoding, -{ +impl<'a, 'tcx, I, T> Encodable> for LazyTable { 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>> 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>> 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>> 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( + fn emit_lazy_distance( &mut self, - lazy: Lazy, + position: NonZeroUsize, ) -> Result<(), ::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( + fn lazy>, B: Borrow>( + &mut self, + value: B, + ) -> LazyValue { + 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>, + I: IntoIterator, + B: Borrow, + >( &mut self, - value: impl EncodeContentsForLazy<'a, 'tcx, T>, - ) -> Lazy { + values: I, + ) -> LazyArray { 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> { + fn encode_def_path_hash_map(&mut self) -> LazyValue> { 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 { 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::>(); - self.lazy(adapted.iter().map(|rc| &**rc)) + self.lazy_array(adapted.iter().map(|rc| &**rc)) } - fn encode_crate_root(&mut self) -> Lazy> { + fn encode_crate_root(&mut self) -> LazyValue> { 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 { 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 { 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 { 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 { 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)]> { + fn encode_lib_features(&mut self) -> LazyArray<(Symbol, Option)> { 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 { 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 { 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 { 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 { 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]> { + fn encode_dylib_dependency_formats(&mut self) -> LazyArray> { 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 7ae177c3a563a..00c4dc3955da0 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` 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 LazyMeta for T { - type Meta = (); -} - -impl 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 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 { + position: NonZeroUsize, + _marker: PhantomData T>, +} + +impl LazyValue { + fn from_position(position: NonZeroUsize) -> LazyValue { + LazyValue { position, _marker: PhantomData } + } +} + +/// A list of lazily-decoded values. /// /// Unlike `Lazy>`, the length is encoded next to the /// position, not at the position, which means that the length @@ -102,39 +99,58 @@ impl 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::Meta> -where - T: ?Sized + LazyMeta, - Meta: 'static + Copy, -{ +struct LazyArray { + position: NonZeroUsize, + num_elems: usize, + _marker: PhantomData T>, +} + +impl LazyArray { + fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray { + LazyArray { position, num_elems, _marker: PhantomData } + } + + fn empty() -> LazyArray { + 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`, but without requiring encoding or decoding all the values +/// eagerly and in-order. +struct LazyTable { position: NonZeroUsize, - meta: Meta, - _marker: PhantomData, + encoded_size: usize, + _marker: PhantomData T>, } -impl Lazy { - fn from_position_and_meta(position: NonZeroUsize, meta: T::Meta) -> Lazy { - Lazy { position, meta, _marker: PhantomData } +impl LazyTable { + fn from_position_and_encoded_size( + position: NonZeroUsize, + encoded_size: usize, + ) -> LazyTable { + LazyTable { position, encoded_size, _marker: PhantomData } } } -impl Lazy { - fn from_position(position: NonZeroUsize) -> Lazy { - Lazy::from_position_and_meta(position, ()) +impl Copy for LazyValue {} +impl Clone for LazyValue { + fn clone(&self) -> Self { + *self } } -impl Lazy<[T]> { - fn empty() -> Lazy<[T]> { - Lazy::from_position_and_meta(NonZeroUsize::new(1).unwrap(), 0) +impl Copy for LazyArray {} +impl Clone for LazyArray { + fn clone(&self) -> Self { + *self } } -impl Copy for Lazy {} -impl Clone for Lazy { +impl Copy for LazyTable {} +impl Clone for LazyTable { fn clone(&self) -> Self { *self } @@ -155,29 +171,20 @@ enum LazyState { Previous(NonZeroUsize), } -// FIXME(#59875) `Lazy!(T)` replaces `Lazy`, 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, usize>}; - ([$T:ty]) => {Lazy<[$T], usize>}; - ($T:ty) => {Lazy<$T, ()>}; -} - -type SyntaxContextTable = Lazy>>; -type ExpnDataTable = Lazy>>; -type ExpnHashTable = Lazy>>; +type SyntaxContextTable = LazyTable>; +type ExpnDataTable = LazyTable>; +type ExpnHashTable = LazyTable>; #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct ProcMacroData { proc_macro_decls_static: DefIndex, stability: Option, - macros: Lazy<[DefIndex]>, + macros: LazyArray, } /// 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` 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]>, - lib_features: Lazy<[(Symbol, Option)]>, - 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, + dylib_dependency_formats: LazyArray>, + lib_features: LazyArray<(Symbol, Option)>, + lang_items: LazyArray<(DefIndex, usize)>, + lang_items_missing: LazyArray, + diagnostic_items: LazyArray<(Symbol, DefIndex)>, + native_libraries: LazyArray, + foreign_modules: LazyArray, + traits: LazyArray, + impls: LazyArray, + incoherent_impls: LazyArray, + interpret_alloc_index: LazyArray, proc_macro_data: Option, tables: LazyTables<'tcx>, - debugger_visualizers: Lazy<[rustc_span::DebuggerVisualizerFile]>, + debugger_visualizers: LazyArray, - 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>, + def_path_hash_map: LazyValue>, - source_map: Lazy<[rustc_span::SourceFile]>, + source_map: LazyArray, compiler_builtins: bool, needs_allocator: bool, @@ -257,7 +264,12 @@ impl Into 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)]>, + impls: LazyArray<(DefIndex, Option)>, } #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct IncoherentImpls { self_ty: SimplifiedType, - impls: Lazy<[DefIndex]>, + impls: LazyArray, } /// 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>, - attributes: Table>, - children: Table>, + kind: Table>, + attributes: Table>, + children: Table>, opt_def_kind: Table, - visibility: Table>, - def_span: Table>, - def_ident_span: Table>, - lookup_stability: Table>, - lookup_const_stability: Table>, - lookup_deprecation_entry: Table>, + visibility: Table>, + def_span: Table>, + def_ident_span: Table>, + lookup_stability: Table>, + lookup_const_stability: Table>, + lookup_deprecation_entry: Table>, // As an optimization, a missing entry indicates an empty `&[]`. - explicit_item_bounds: Table, Span)])>, - explicit_predicates_of: Table)>, - generics_of: Table>, + explicit_item_bounds: Table, Span)>>, + explicit_predicates_of: Table>>, + generics_of: Table>, // As an optimization, a missing entry indicates an empty `&[]`. - inferred_outlives_of: Table, Span)])>, - super_predicates_of: Table)>, - type_of: Table)>, - variances_of: Table>, - fn_sig: Table)>, - codegen_fn_attrs: Table, - impl_trait_ref: Table)>, - const_param_default: Table>>, - optimized_mir: Table)>, - mir_for_ctfe: Table)>, - promoted_mir: Table>)>, - thir_abstract_const: Table])>, + inferred_outlives_of: Table, Span)>>, + super_predicates_of: Table>>, + type_of: Table>>, + variances_of: Table>, + fn_sig: Table>>, + codegen_fn_attrs: Table>, + impl_trait_ref: Table>>, + const_param_default: Table>>, + optimized_mir: Table>>, + mir_for_ctfe: Table>>, + promoted_mir: Table>>>, + // FIXME(compiler-errors): Why isn't this a LazyArray? + thir_abstract_const: Table]>>, impl_parent: Table, impl_polarity: Table, impl_constness: Table, is_intrinsic: Table, impl_defaultness: Table, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? - coerce_unsized_info: Table, - mir_const_qualif: Table, - rendered_const: Table, + coerce_unsized_info: Table>, + mir_const_qualif: Table>, + rendered_const: Table>, asyncness: Table, - fn_arg_names: Table, - generator_kind: Table, - trait_def: Table, + fn_arg_names: Table>, + generator_kind: Table>, + trait_def: Table>, trait_item_def_id: Table, - inherent_impls: Table>, - expn_that_defined: Table>, - unused_generic_params: Table>>, - repr_options: Table>, + inherent_impls: Table>, + expn_that_defined: Table>, + unused_generic_params: Table>>, + repr_options: Table>, // `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>, + def_keys: Table>, def_path_hashes: Table, - proc_macro_quoted_spans: Table>, - generator_diagnostic_data: Table>>, + proc_macro_quoted_spans: Table>, + generator_diagnostic_data: Table>>, may_have_doc_links: Table, } @@ -382,19 +395,19 @@ enum EntryKind { OpaqueTy, Enum, Field, - Variant(Lazy), - Struct(Lazy), - Union(Lazy), + Variant(LazyValue), + Struct(LazyValue), + Union(LazyValue), Fn, ForeignFn, - Mod(Lazy<[ModChild]>), - MacroDef(Lazy, /*macro_rules*/ bool), + Mod(LazyArray), + MacroDef(LazyValue, /*macro_rules*/ bool), ProcMacro(MacroKind), Closure, Generator, Trait, Impl, - AssocFn(Lazy), + AssocFn(LazyValue), AssocType(AssocContainer), AssocConst(AssocContainer), TraitAlias, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 53fc2efe00bb7..60c5143a6c377 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` impl, but in the general case we might not need / want to -// fit every `usize` in `u32`. -impl FixedSizeEncoding for Option> { +// generic `LazyValue` impl, but in the general case we might not need / want +// to fit every `usize` in `u32`. +impl FixedSizeEncoding for Option> { 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 FixedSizeEncoding for Option> { } } -impl FixedSizeEncoding for Option> { +impl FixedSizeEncoding for Option> { type ByteArray = [u8; 8]; #[inline] @@ -228,7 +228,7 @@ impl FixedSizeEncoding for Option> { 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 FixedSizeEncoding for Option> { 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>`, but without requiring encoding or decoding all the values -/// eagerly and in-order. -/// A total of `(max_idx + 1)` times `Option as FixedSizeEncoding>::ByteArray` -/// are used for a table, where `max_idx` is the largest index passed to -/// `TableBuilder::set`. -pub(super) struct Table -where - Option: 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 where @@ -296,7 +280,7 @@ where Some(value).write_to_bytes(&mut self.blocks[i]); } - pub(crate) fn encode(&self, buf: &mut Encoder) -> Lazy> + pub(crate) fn encode(&self, buf: &mut Encoder) -> LazyTable where Option: FixedSizeEncoding, { @@ -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 LazyMeta for Table -where - Option: FixedSizeEncoding, -{ - /// Number of bytes in the data stream. - type Meta = usize; -} - -impl Lazy> +impl LazyTable where Option: FixedSizeEncoding, { @@ -331,10 +310,10 @@ where where Option: FixedSizeEncoding, { - 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::() else { panic!() }; let bytes = bytes.get(i.index())?; FixedSizeEncoding::from_bytes(bytes) @@ -345,6 +324,6 @@ where where Option: FixedSizeEncoding, { - self.meta / N + self.encoded_size / N } }