diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:41 +0000 |
commit | 4f9fe856a25ab29345b90e7725509e9ee38a37be (patch) | |
tree | e4ffd8a9374cae7b21f7cbfb352927e0e074aff6 /compiler/rustc_metadata/src/rmeta | |
parent | Adding upstream version 1.68.2+dfsg1. (diff) | |
download | rustc-upstream/1.69.0+dfsg1.tar.xz rustc-upstream/1.69.0+dfsg1.zip |
Adding upstream version 1.69.0+dfsg1.upstream/1.69.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_metadata/src/rmeta')
-rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder.rs | 92 | ||||
-rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 78 | ||||
-rw-r--r-- | compiler/rustc_metadata/src/rmeta/encoder.rs | 459 | ||||
-rw-r--r-- | compiler/rustc_metadata/src/rmeta/mod.rs | 78 | ||||
-rw-r--r-- | compiler/rustc_metadata/src/rmeta/table.rs | 231 |
5 files changed, 498 insertions, 440 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 143d8f2f1..b1e59b0a4 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -11,7 +11,7 @@ use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::diagnostic_items::DiagnosticItems; @@ -654,7 +654,7 @@ impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyValue<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 { LazyArray::empty() } else { decoder.read_lazy_array(len) } + if len == 0 { LazyArray::default() } else { decoder.read_lazy_array(len) } } } @@ -864,7 +864,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, index) - .unwrap_or_else(LazyArray::empty) + .expect("fields are not encoded for a variant") .decode(self) .map(|index| ty::FieldDef { did: self.local_def_id(index), @@ -896,7 +896,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, item_id) - .unwrap_or_else(LazyArray::empty) + .expect("variants are not encoded for an enum") .decode(self) .filter_map(|index| { let kind = self.def_kind(index); @@ -910,7 +910,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { std::iter::once(self.get_variant(&kind, item_id, did)).collect() }; - tcx.alloc_adt_def(did, adt_kind, variants, repr) + tcx.mk_adt_def(did, adt_kind, variants, repr) } fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics { @@ -985,7 +985,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let vis = self.get_visibility(id); let span = self.get_span(id, sess); let macro_rules = match kind { - DefKind::Macro(..) => self.root.tables.macro_rules.get(self, id).is_some(), + DefKind::Macro(..) => self.root.tables.is_macro_rules.get(self, id), _ => false, }; @@ -1045,7 +1045,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .fn_arg_names .get(self, id) - .unwrap_or_else(LazyArray::empty) + .expect("argument names not encoded for a function") .decode((self, sess)) .nth(0) .map_or(false, |ident| ident.name == kw::SelfLower) @@ -1060,7 +1060,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, id) - .unwrap_or_else(LazyArray::empty) + .expect("associated items not encoded for an item") .decode((self, sess)) .map(move |child_index| self.local_def_id(child_index)) } @@ -1068,13 +1068,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { let name = self.item_name(id); - let kind = match self.def_kind(id) { - DefKind::AssocConst => ty::AssocKind::Const, - DefKind::AssocFn => ty::AssocKind::Fn, - DefKind::AssocTy => ty::AssocKind::Type, + let (kind, has_self) = match self.def_kind(id) { + DefKind::AssocConst => (ty::AssocKind::Const, false), + DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)), + DefKind::AssocTy => (ty::AssocKind::Type, false), _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; - let has_self = self.get_fn_has_self_parameter(id, sess); let container = self.root.tables.assoc_container.get(self, id).unwrap(); ty::AssocItem { @@ -1131,7 +1130,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, id) - .unwrap_or_else(LazyArray::empty) + .expect("fields not encoded for a struct") .decode(self) .map(move |index| respan(self.get_span(index, sess), self.item_name(index))) } @@ -1144,7 +1143,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, id) - .unwrap_or_else(LazyArray::empty) + .expect("fields not encoded for a struct") .decode(self) .map(move |field_index| self.get_visibility(field_index)) } @@ -1159,52 +1158,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .inherent_impls .get(self, id) - .unwrap_or_else(LazyArray::empty) .decode(self) .map(|index| self.local_def_id(index)), ) } - /// Decodes all inherent impls in the crate (for rustdoc). - fn get_inherent_impls(self) -> impl Iterator<Item = (DefId, DefId)> + 'a { - (0..self.root.tables.inherent_impls.size()).flat_map(move |i| { - let ty_index = DefIndex::from_usize(i); - let ty_def_id = self.local_def_id(ty_index); - self.root - .tables - .inherent_impls - .get(self, ty_index) - .unwrap_or_else(LazyArray::empty) - .decode(self) - .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index))) - }) - } - /// Decodes all traits in the crate (for rustdoc and rustc diagnostics). fn get_traits(self) -> impl Iterator<Item = DefId> + 'a { self.root.traits.decode(self).map(move |index| self.local_def_id(index)) } /// Decodes all trait impls in the crate (for rustdoc). - fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a { - self.cdata.trait_impls.iter().flat_map(move |(&(trait_cnum_raw, trait_index), impls)| { - let trait_def_id = DefId { - krate: self.cnum_map[CrateNum::from_u32(trait_cnum_raw)], - index: trait_index, - }; - impls.decode(self).map(move |(impl_index, simplified_self_ty)| { - (trait_def_id, self.local_def_id(impl_index), simplified_self_ty) - }) + fn get_trait_impls(self) -> impl Iterator<Item = DefId> + 'a { + self.cdata.trait_impls.values().flat_map(move |impls| { + impls.decode(self).map(move |(impl_index, _)| self.local_def_id(impl_index)) }) } - fn get_all_incoherent_impls(self) -> impl Iterator<Item = DefId> + 'a { - self.cdata - .incoherent_impls - .values() - .flat_map(move |impls| impls.decode(self).map(move |idx| self.local_def_id(idx))) - } - fn get_incoherent_impls(self, tcx: TyCtxt<'tcx>, simp: SimplifiedType) -> &'tcx [DefId] { if let Some(impls) = self.cdata.incoherent_impls.get(&simp) { tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx))) @@ -1283,7 +1253,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { match self.def_kind(id) { DefKind::Macro(_) => { - let macro_rules = self.root.tables.macro_rules.get(self, id).is_some(); + let macro_rules = self.root.tables.is_macro_rules.get(self, id); let body = self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); ast::MacroDef { macro_rules, body: ast::ptr::P(body) } @@ -1322,7 +1292,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) -> DefPathHash { *def_path_hashes .entry(index) - .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index).unwrap()) + .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index)) } #[inline] @@ -1594,12 +1564,30 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn get_may_have_doc_links(self, index: DefIndex) -> bool { - self.root.tables.may_have_doc_links.get(self, index).is_some() + fn get_attr_flags(self, index: DefIndex) -> AttrFlags { + self.root.tables.attr_flags.get(self, index) } fn get_is_intrinsic(self, index: DefIndex) -> bool { - self.root.tables.is_intrinsic.get(self, index).is_some() + self.root.tables.is_intrinsic.get(self, index) + } + + fn get_doc_link_resolutions(self, index: DefIndex) -> DocLinkResMap { + self.root + .tables + .doc_link_resolutions + .get(self, index) + .expect("no resolutions for a doc link") + .decode(self) + } + + fn get_doc_link_traits_in_scope(self, index: DefIndex) -> impl Iterator<Item = DefId> + 'a { + self.root + .tables + .doc_link_traits_in_scope + .get(self, index) + .expect("no traits in scope for a doc link") + .decode(self) } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 6fd5bd52a..83a0e833e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -1,6 +1,8 @@ use crate::creader::{CStore, LoadedMacro}; use crate::foreign_modules; use crate::native_libs; +use crate::rmeta::table::IsDefault; +use crate::rmeta::AttrFlags; use rustc_ast as ast; use rustc_attr::Deprecation; @@ -87,6 +89,14 @@ macro_rules! provide_one { } } }; + ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_defaulted_array }) => { + provide_one! { + $tcx, $def_id, $other, $cdata, $name => { + let lazy = $cdata.root.tables.$name.get($cdata, $def_id.index); + if lazy.is_default() { &[] } else { $tcx.arena.alloc_from_iter(lazy.decode(($cdata, $tcx))) } + } + } + }; ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => { provide_one! { $tcx, $def_id, $other, $cdata, $name => { @@ -104,7 +114,7 @@ macro_rules! provide_one { fn $name<'tcx>( $tcx: TyCtxt<'tcx>, def_id_arg: ty::query::query_keys::$name<'tcx>, - ) -> ty::query::query_values::$name<'tcx> { + ) -> ty::query::query_provided::$name<'tcx> { let _prof_timer = $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name))); @@ -120,7 +130,13 @@ macro_rules! provide_one { $tcx.ensure().crate_hash($def_id.krate); } - let $cdata = CStore::from_tcx($tcx).get_crate_data($def_id.krate); + let cdata = rustc_data_structures::sync::MappedReadGuard::map(CStore::from_tcx($tcx), |c| { + c.get_crate_data($def_id.krate).cdata + }); + let $cdata = crate::creader::CrateMetadataRef { + cdata: &cdata, + cstore: &CStore::from_tcx($tcx), + }; $compute } @@ -186,10 +202,10 @@ impl IntoArgs for (CrateNum, SimplifiedType) { } provide! { tcx, def_id, other, cdata, - explicit_item_bounds => { table } + explicit_item_bounds => { table_defaulted_array } explicit_predicates_of => { table } generics_of => { table } - inferred_outlives_of => { table } + inferred_outlives_of => { table_defaulted_array } super_predicates_of => { table } type_of => { table } variances_of => { table } @@ -201,6 +217,7 @@ provide! { tcx, def_id, other, cdata, thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } + mir_generator_witnesses => { table } promoted_mir => { table } def_span => { table } def_ident_span => { table } @@ -225,12 +242,7 @@ provide! { tcx, def_id, other, cdata, deduced_param_attrs => { table } is_type_alias_impl_trait => { debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); - cdata - .root - .tables - .is_type_alias_impl_trait - .get(cdata, def_id.index) - .is_some() + cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index) } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata @@ -242,6 +254,8 @@ provide! { tcx, def_id, other, cdata, .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } + associated_items_for_impl_trait_in_trait => { table_defaulted_array } + visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { @@ -298,6 +312,7 @@ provide! { tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } @@ -338,6 +353,11 @@ provide! { tcx, def_id, other, cdata, crate_extern_paths => { cdata.source().paths().cloned().collect() } expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) } generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) } + is_doc_hidden => { cdata.get_attr_flags(def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) } + doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(def_id.index)) } + doc_link_traits_in_scope => { + tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index)) + } } pub(in crate::rmeta) fn provide(providers: &mut Providers) { @@ -425,7 +445,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { return; } - if ty::util::is_doc_hidden(tcx, parent) { + if tcx.is_doc_hidden(parent) { fallback_map.push((def_id, parent)); return; } @@ -597,42 +617,6 @@ impl CStore { ) -> Span { self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) } - - /// Decodes all trait impls in the crate (for rustdoc). - pub fn trait_impls_in_crate_untracked( - &self, - cnum: CrateNum, - ) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ { - self.get_crate_data(cnum).get_trait_impls() - } - - /// Decodes all inherent impls in the crate (for rustdoc). - pub fn inherent_impls_in_crate_untracked( - &self, - cnum: CrateNum, - ) -> impl Iterator<Item = (DefId, DefId)> + '_ { - self.get_crate_data(cnum).get_inherent_impls() - } - - /// Decodes all incoherent inherent impls in the crate (for rustdoc). - pub fn incoherent_impls_in_crate_untracked( - &self, - cnum: CrateNum, - ) -> impl Iterator<Item = DefId> + '_ { - self.get_crate_data(cnum).get_all_incoherent_impls() - } - - pub fn associated_item_def_ids_untracked<'a>( - &'a self, - def_id: DefId, - sess: &'a Session, - ) -> impl Iterator<Item = DefId> + 'a { - self.get_crate_data(def_id.krate).get_associated_item_def_ids(def_id.index, sess) - } - - pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool { - self.get_crate_data(def_id.krate).get_may_have_doc_links(def_id.index) - } } impl CrateStore for CStore { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8f7a61b72..3ab01f780 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -38,7 +38,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{ self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext, }; -use rustc_target::abi::VariantIdx; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; @@ -76,13 +75,13 @@ pub(super) struct EncodeContext<'a, 'tcx> { symbol_table: FxHashMap<Symbol, usize>, } -/// If the current crate is a proc-macro, returns early with `LazyArray::empty()`. +/// If the current crate is a proc-macro, returns early with `LazyArray::default()`. /// This is useful for skipping the encoding of things that aren't needed /// for proc-macro crates. macro_rules! empty_proc_macro { ($self:ident) => { if $self.is_proc_macro { - return LazyArray::empty(); + return LazyArray::default(); } }; } @@ -365,25 +364,35 @@ impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { } } -// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would +// Shorthand for `$self.$tables.$table.set_some($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) => {{ { let value = $value; let lazy = $self.lazy(value); - $self.$tables.$table.set($def_id.index, lazy); + $self.$tables.$table.set_some($def_id.index, lazy); } }}; } -// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would +// Shorthand for `$self.$tables.$table.set_some($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_some($def_id.index, lazy); + } + }}; +} + +macro_rules! record_defaulted_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); } }}; @@ -467,13 +476,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { { let def_key = self.lazy(table.def_key(def_index)); let def_path_hash = table.def_path_hash(def_index); - self.tables.def_keys.set(def_index, def_key); + self.tables.def_keys.set_some(def_index, def_key); self.tables.def_path_hashes.set(def_index, def_path_hash); } } else { for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { let def_key = self.lazy(def_key); - self.tables.def_keys.set(def_index, def_key); + self.tables.def_keys.set_some(def_index, def_key); self.tables.def_path_hashes.set(def_index, *def_path_hash); } } @@ -483,7 +492,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(DefPathHashMapRef::BorrowedFromTcx(self.tcx.def_path_hash_to_def_index_map())) } - fn encode_source_map(&mut self) -> LazyTable<u32, LazyValue<rustc_span::SourceFile>> { + fn encode_source_map(&mut self) -> LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>> { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -548,7 +557,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let on_disk_index: u32 = on_disk_index.try_into().expect("cannot export more than U32_MAX files"); - adapted.set(on_disk_index, self.lazy(source_file)); + adapted.set_some(on_disk_index, self.lazy(source_file)); } adapted.encode(&mut self.opaque) @@ -760,36 +769,50 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } +struct AnalyzeAttrState { + is_exported: bool, + is_doc_hidden: bool, +} + /// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and /// useful in downstream crates. Local-only attributes are an obvious example, but some /// rustdoc-specific attributes can equally be of use while documenting the current crate only. /// /// Removing these superfluous attributes speeds up compilation by making the metadata smaller. /// -/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public +/// Note: the `is_exported` parameter is used to cache whether the given `DefId` has a public /// visibility: this is a piece of data that can be computed once per defid, and not once per /// attribute. Some attributes would only be usable downstream if they are public. #[inline] -fn should_encode_attr( - tcx: TyCtxt<'_>, - attr: &Attribute, - def_id: LocalDefId, - is_def_id_public: &mut Option<bool>, -) -> bool { +fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool { + let mut should_encode = false; if rustc_feature::is_builtin_only_local(attr.name_or_empty()) { // Attributes marked local-only don't need to be encoded for downstream crates. - false } else if attr.doc_str().is_some() { - // We keep all public doc comments because they might be "imported" into downstream crates - // if they use `#[doc(inline)]` to copy an item's documentation into their own. - *is_def_id_public.get_or_insert_with(|| tcx.effective_visibilities(()).is_exported(def_id)) + // We keep all doc comments reachable to rustdoc because they might be "imported" into + // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into + // their own. + if state.is_exported { + should_encode = true; + } } else if attr.has_name(sym::doc) { - // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can - // remove it. It won't be inlinable in downstream crates. - attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false) + // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in + // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates. + if let Some(item_list) = attr.meta_item_list() { + for item in item_list { + if !item.has_name(sym::inline) { + should_encode = true; + if item.has_name(sym::hidden) { + state.is_doc_hidden = true; + break; + } + } + } + } } else { - true + should_encode = true; } + should_encode } fn should_encode_visibility(def_kind: DefKind) -> bool { @@ -815,7 +838,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::ForeignMod | DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder - | DefKind::Impl + | DefKind::Impl { .. } | DefKind::Field => true, DefKind::TyParam | DefKind::ConstParam @@ -850,7 +873,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::ImplTraitPlaceholder | DefKind::Enum | DefKind::Union - | DefKind::Impl + | DefKind::Impl { .. } | DefKind::Trait | DefKind::TraitAlias | DefKind::Macro(..) @@ -928,7 +951,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Const | DefKind::ForeignMod | DefKind::TyAlias - | DefKind::Impl + | DefKind::Impl { .. } | DefKind::Trait | DefKind::TraitAlias | DefKind::Macro(..) @@ -965,7 +988,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder - | DefKind::Impl + | DefKind::Impl { .. } | DefKind::Field | DefKind::TyParam | DefKind::Closure @@ -995,7 +1018,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::TyAlias | DefKind::OpaqueTy | DefKind::ForeignTy - | DefKind::Impl + | DefKind::Impl { .. } | DefKind::AssocFn | DefKind::AssocConst | DefKind::Closure @@ -1058,7 +1081,7 @@ fn should_encode_const(def_kind: DefKind) -> bool { | DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder | DefKind::ForeignTy - | DefKind::Impl + | DefKind::Impl { .. } | DefKind::AssocFn | DefKind::Closure | DefKind::Generator @@ -1078,49 +1101,40 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if tcx.def_kind(def_id) != DefKind::AssocFn { - return false; - } - - let Some(item) = tcx.opt_associated_item(def_id) else { return false; }; - if item.container != ty::AssocItemContainer::ImplContainer { - return false; +// We only encode impl trait in trait when using `lower-impl-trait-in-trait-to-assoc-ty` unstable +// option. +fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty + && let Some(assoc_item) = tcx.opt_associated_item(def_id) + && assoc_item.container == ty::AssocItemContainer::TraitContainer + && assoc_item.kind == ty::AssocKind::Fn + { + true + } else { + false } - - let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; - - // FIXME(RPITIT): This does a somewhat manual walk through the signature - // of the trait fn to look for any RPITITs, but that's kinda doing a lot - // of work. We can probably remove this when we refactor RPITITs to be - // associated types. - tcx.fn_sig(trait_item_def_id).skip_binder().output().walk().any(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection, data) = ty.kind() - && tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder - { - true - } else { - false - } - }) } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let mut is_public: Option<bool> = None; - - let mut attrs = tcx - .hir() - .attrs(tcx.hir().local_def_id_to_hir_id(def_id)) + let mut state = AnalyzeAttrState { + is_exported: tcx.effective_visibilities(()).is_exported(def_id), + is_doc_hidden: false, + }; + let attr_iter = tcx + .opt_local_def_id_to_hir_id(def_id) + .map_or(Default::default(), |hir_id| tcx.hir().attrs(hir_id)) .iter() - .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public)); + .filter(|attr| analyze_attr(attr, &mut state)); + + record_array!(self.tables.attributes[def_id.to_def_id()] <- attr_iter); - 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, ()); + let mut attr_flags = AttrFlags::empty(); + if state.is_doc_hidden { + attr_flags |= AttrFlags::IS_DOC_HIDDEN; } + self.tables.attr_flags.set(def_id.local_def_index, attr_flags); } fn encode_def_ids(&mut self) { @@ -1132,7 +1146,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = local_id.to_def_id(); let def_kind = tcx.opt_def_kind(local_id); let Some(def_kind) = def_kind else { continue }; - self.tables.opt_def_kind.set(def_id.index, def_kind); + self.tables.opt_def_kind.set_some(def_id.index, def_kind); let def_span = tcx.def_span(local_id); record!(self.tables.def_span[def_id] <- def_span); self.encode_attrs(local_id); @@ -1163,9 +1177,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.generics_of[def_id] <- g); 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_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); - } + record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); } if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); @@ -1178,70 +1190,85 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { - let params_in_repr = self.tcx.params_in_repr(def_id); - record!(self.tables.params_in_repr[def_id] <- params_in_repr); + self.encode_info_for_adt(def_id); } - if should_encode_trait_impl_trait_tys(tcx, def_id) + if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } + if should_encode_fn_impl_trait_in_trait(tcx, def_id) { + let table = tcx.associated_items_for_impl_trait_in_trait(def_id); + record_defaulted_array!(self.tables.associated_items_for_impl_trait_in_trait[def_id] <- table); + } } + let inherent_impls = tcx.with_stable_hashing_context(|hcx| { tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true) }); - - for (def_id, implementations) in inherent_impls { - if implementations.is_empty() { - continue; - } - record_array!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| { + for (def_id, impls) in inherent_impls { + record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| { assert!(def_id.is_local()); def_id.index })); } + + for (def_id, res_map) in &tcx.resolutions(()).doc_link_resolutions { + record!(self.tables.doc_link_resolutions[def_id.to_def_id()] <- res_map); + } + + for (def_id, traits) in &tcx.resolutions(()).doc_link_traits_in_scope { + record_array!(self.tables.doc_link_traits_in_scope[def_id.to_def_id()] <- traits); + } } - fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) { + #[instrument(level = "trace", skip(self))] + fn encode_info_for_adt(&mut self, def_id: DefId) { let tcx = self.tcx; - let variant = &def.variant(index); - let def_id = variant.def_id; - debug!("EncodeContext::encode_enum_variant_info({:?})", def_id); - - let data = VariantData { - discr: variant.discr, - ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }; + let adt_def = tcx.adt_def(def_id); + record!(self.tables.repr_options[def_id] <- adt_def.repr()); + + let params_in_repr = self.tcx.params_in_repr(def_id); + record!(self.tables.params_in_repr[def_id] <- params_in_repr); - record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); - record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { - assert!(f.did.is_local()); - f.did.index - })); - if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { - // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id)); + if adt_def.is_enum() { + record_array!(self.tables.children[def_id] <- iter::from_generator(|| + for variant in tcx.adt_def(def_id).variants() { + yield variant.def_id.index; + // Encode constructors which take a separate slot in value namespace. + if let Some(ctor_def_id) = variant.ctor_def_id() { + yield ctor_def_id.index; + } + } + )); + } else { + // For non-enum, there is only one variant, and its def_id is the adt's. + debug_assert_eq!(adt_def.variants().len(), 1); + debug_assert_eq!(adt_def.non_enum_variant().def_id, def_id); + // Therefore, the loop over variants will encode its fields as the adt's children. } - } - fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) { - let variant = &def.variant(index); - let Some((ctor_kind, def_id)) = variant.ctor else { return }; - debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id); + for variant in adt_def.variants().iter() { + let data = VariantData { + discr: variant.discr, + ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), + is_non_exhaustive: variant.is_field_list_non_exhaustive(), + }; + record!(self.tables.variant_data[variant.def_id] <- data); - // FIXME(eddyb) encode only the `CtorKind` for constructors. - let data = VariantData { - discr: variant.discr, - ctor: Some((ctor_kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }; + self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const); + record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| { + assert!(f.did.is_local()); + f.did.index + })); - record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); - if ctor_kind == CtorKind::Fn { - record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id)); + if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { + self.tables.constness.set_some(ctor_def_id.index, hir::Constness::Const); + let fn_sig = tcx.fn_sig(ctor_def_id); + record!(self.tables.fn_sig[ctor_def_id] <- fn_sig); + // FIXME only encode signature for ctor_def_id + record!(self.tables.fn_sig[variant.def_id] <- fn_sig); + } } } @@ -1275,8 +1302,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Struct(ref vdata, _) => { yield item_id.owner_id.def_id.local_def_index; // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_hir_id) = vdata.ctor_hir_id() { - yield tcx.hir().local_def_id(ctor_hir_id).local_def_index; + if let Some(ctor_def_id) = vdata.ctor_def_id() { + yield ctor_def_id.local_def_index; } } _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => { @@ -1294,31 +1321,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>) { - let variant = adt_def.non_enum_variant(); - let Some((ctor_kind, def_id)) = variant.ctor else { return }; - debug!("EncodeContext::encode_struct_ctor({:?})", def_id); - - let data = VariantData { - discr: variant.discr, - ctor: Some((ctor_kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }; - - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - record!(self.tables.variant_data[def_id] <- data); - self.tables.constness.set(def_id.index, hir::Constness::Const); - if ctor_kind == CtorKind::Fn { - record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id)); - } - } - fn encode_explicit_item_bounds(&mut self, def_id: DefId) { debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id); let bounds = self.tcx.explicit_item_bounds(def_id); - if !bounds.is_empty() { - record_array!(self.tables.explicit_item_bounds[def_id] <- bounds); - } + record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } fn encode_info_for_trait_item(&mut self, def_id: DefId) { @@ -1326,16 +1332,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; let impl_defaultness = tcx.impl_defaultness(def_id.expect_local()); - self.tables.impl_defaultness.set(def_id.index, impl_defaultness); + self.tables.impl_defaultness.set_some(def_id.index, impl_defaultness); let trait_item = tcx.associated_item(def_id); - self.tables.assoc_container.set(def_id.index, trait_item.container); + self.tables.assoc_container.set_some(def_id.index, trait_item.container); match trait_item.kind { ty::AssocKind::Const => {} ty::AssocKind::Fn => { record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id)); - self.tables.asyncness.set(def_id.index, tcx.asyncness(def_id)); - self.tables.constness.set(def_id.index, hir::Constness::NotConst); + self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id)); + self.tables.constness.set_some(def_id.index, hir::Constness::NotConst); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); @@ -1351,14 +1357,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local()); - self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness); + self.tables.impl_defaultness.set_some(def_id.index, ast_item.defaultness); let impl_item = self.tcx.associated_item(def_id); - self.tables.assoc_container.set(def_id.index, impl_item.container); + self.tables.assoc_container.set_some(def_id.index, impl_item.container); match impl_item.kind { 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); + self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); 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) { @@ -1366,18 +1372,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { hir::Constness::NotConst }; - self.tables.constness.set(def_id.index, constness); + self.tables.constness.set_some(def_id.index, constness); } ty::AssocKind::Const | ty::AssocKind::Type => {} } if let Some(trait_item_def_id) = impl_item.trait_item_def_id { - self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into()); + self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into()); } if impl_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); - } + self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); } } @@ -1398,6 +1402,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); + + if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) { + record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id)); + } } if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id)); @@ -1502,14 +1510,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match item.kind { hir::ItemKind::Fn(ref sig, .., body) => { - self.tables.asyncness.set(def_id.index, sig.header.asyncness); + self.tables.asyncness.set_some(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); - self.tables.constness.set(def_id.index, sig.header.constness); + self.tables.constness.set_some(def_id.index, sig.header.constness); } hir::ItemKind::Macro(ref macro_def, _) => { - if macro_def.macro_rules { - self.tables.macro_rules.set(def_id.index, ()); - } + self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules); record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } hir::ItemKind::Mod(ref m) => { @@ -1517,47 +1523,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); - if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) { - self.tables.is_type_alias_impl_trait.set(def_id.index, ()); - } - } - hir::ItemKind::Enum(..) => { - let adt_def = self.tcx.adt_def(def_id); - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - } - hir::ItemKind::Struct(..) => { - let adt_def = self.tcx.adt_def(def_id); - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - self.tables.constness.set(def_id.index, hir::Constness::Const); - - let variant = adt_def.non_enum_variant(); - record!(self.tables.variant_data[def_id] <- VariantData { - discr: variant.discr, - ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }); - } - hir::ItemKind::Union(..) => { - let adt_def = self.tcx.adt_def(def_id); - record!(self.tables.repr_options[def_id] <- adt_def.repr()); - - let variant = adt_def.non_enum_variant(); - record!(self.tables.variant_data[def_id] <- VariantData { - discr: variant.discr, - ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), - is_non_exhaustive: variant.is_field_list_non_exhaustive(), - }); + self.tables + .is_type_alias_impl_trait + .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)); } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { - self.tables.impl_defaultness.set(def_id.index, *defaultness); - self.tables.constness.set(def_id.index, *constness); + self.tables.impl_defaultness.set_some(def_id.index, *defaultness); + self.tables.constness.set_some(def_id.index, *constness); - let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder); + let trait_ref = self.tcx.impl_trait_ref(def_id); if let Some(trait_ref) = trait_ref { + let trait_ref = trait_ref.skip_binder(); let trait_def = self.tcx.trait_def(trait_ref.def_id); if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) { if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) { - self.tables.impl_parent.set(def_id.index, parent.into()); + self.tables.impl_parent.set_some(def_id.index, parent.into()); } } @@ -1571,7 +1551,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } let polarity = self.tcx.impl_polarity(def_id); - self.tables.impl_polarity.set(def_id.index, polarity); + self.tables.impl_polarity.set_some(def_id.index, polarity); } hir::ItemKind::Trait(..) => { let trait_def = self.tcx.trait_def(def_id); @@ -1586,31 +1566,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Static(..) | hir::ItemKind::Const(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::TyAlias(..) => {} }; // FIXME(eddyb) there should be a nicer way to do this. match item.kind { - hir::ItemKind::Enum(..) => { - record_array!(self.tables.children[def_id] <- iter::from_generator(|| - for variant in tcx.adt_def(def_id).variants() { - yield variant.def_id.index; - // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_def_id) = variant.ctor_def_id() { - yield ctor_def_id.index; - } - } - )) - } - hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - 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 - }) - ) - } hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => { let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); record_array!(self.tables.children[def_id] <- @@ -1624,9 +1588,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let hir::ItemKind::Fn(..) = item.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); - if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); - } + self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); } if let hir::ItemKind::Impl { .. } = item.kind { if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { @@ -1638,17 +1600,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // so it's easier to do that here then to wait until we would encounter // normally in the visitor walk. match item.kind { - hir::ItemKind::Enum(..) => { - let def = self.tcx.adt_def(item.owner_id.to_def_id()); - for (i, _) in def.variants().iter_enumerated() { - self.encode_enum_variant_info(def, i); - self.encode_enum_variant_ctor(def, i); - } - } - hir::ItemKind::Struct(..) => { - let def = self.tcx.adt_def(item.owner_id.to_def_id()); - self.encode_struct_ctor(def); - } hir::ItemKind::Impl { .. } => { for &trait_item_def_id in self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter() @@ -1670,7 +1621,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn encode_info_for_closure(&mut self, def_id: LocalDefId) { // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic, - // including on the signature, which is inferred in `typeck. + // including on the signature, which is inferred in `typeck`. let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id); let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let ty = typeck_result.node_type(hir_id); @@ -1684,8 +1635,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Closure(_, substs) => { let constness = self.tcx.constness(def_id.to_def_id()); - self.tables.constness.set(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig()); + self.tables.constness.set_some(def_id.to_def_id().index, constness); + record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig())); } _ => bug!("closure that is neither generator nor closure"), @@ -1712,12 +1663,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.hygiene_ctxt.encode( &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table), |(this, syntax_contexts, _, _), index, ctxt_data| { - syntax_contexts.set(index, this.lazy(ctxt_data)); + syntax_contexts.set_some(index, this.lazy(ctxt_data)); }, |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { if let Some(index) = index.as_local() { - expn_data_table.set(index.as_raw(), this.lazy(expn_data)); - expn_hash_table.set(index.as_raw(), this.lazy(hash)); + expn_data_table.set_some(index.as_raw(), this.lazy(expn_data)); + expn_hash_table.set_some(index.as_raw(), this.lazy(hash)); } }, ); @@ -1742,10 +1693,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans(); for (i, span) in spans.into_iter().enumerate() { let span = self.lazy(span); - self.tables.proc_macro_quoted_spans.set(i, span); + self.tables.proc_macro_quoted_spans.set_some(i, span); } - self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod); + self.tables.opt_def_kind.set_some(LOCAL_CRATE.as_def_id().index, DefKind::Mod); record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local()); let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index); @@ -1754,6 +1705,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability); } self.encode_deprecation(LOCAL_CRATE.as_def_id()); + if let Some(res_map) = tcx.resolutions(()).doc_link_resolutions.get(&CRATE_DEF_ID) { + record!(self.tables.doc_link_resolutions[LOCAL_CRATE.as_def_id()] <- res_map); + } + if let Some(traits) = tcx.resolutions(()).doc_link_traits_in_scope.get(&CRATE_DEF_ID) { + record_array!(self.tables.doc_link_traits_in_scope[LOCAL_CRATE.as_def_id()] <- traits); + } // Normally, this information is encoded when we walk the items // defined in this crate. However, we skip doing that for proc-macro crates, @@ -1787,8 +1744,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { def_key.disambiguated_data.data = DefPathData::MacroNs(name); let def_id = id.to_def_id(); - self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind)); - self.tables.proc_macro.set(def_id.index, macro_kind); + self.tables.opt_def_kind.set_some(def_id.index, DefKind::Macro(macro_kind)); + self.tables.proc_macro.set_some(def_id.index, macro_kind); self.encode_attrs(id); record!(self.tables.def_keys[def_id] <- def_key); record!(self.tables.def_ident_span[def_id] <- span); @@ -1894,7 +1851,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { FxHashMap::default(); for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) { + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) { if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) { let trait_ref = trait_ref.subst_identity(); @@ -2003,7 +1960,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Linkage::Static => Some(LinkagePreference::RequireStatic), })); } - LazyArray::empty() + LazyArray::default() } fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) { @@ -2013,22 +1970,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match nitem.kind { hir::ForeignItemKind::Fn(_, ref names, _) => { - self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync); + self.tables.asyncness.set_some(def_id.index, hir::IsAsync::NotAsync); 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 { hir::Constness::NotConst }; - self.tables.constness.set(def_id.index, constness); + self.tables.constness.set_some(def_id.index, constness); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {} } if let hir::ForeignItemKind::Fn(..) = nitem.kind { - if tcx.is_intrinsic(def_id) { - self.tables.is_intrinsic.set(def_id.index, ()); - } + self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id)); } } } @@ -2266,6 +2221,18 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { pub fn provide(providers: &mut Providers) { *providers = Providers { + doc_link_resolutions: |tcx, def_id| { + tcx.resolutions(()) + .doc_link_resolutions + .get(&def_id.expect_local()) + .expect("no resolutions for a doc link") + }, + doc_link_traits_in_scope: |tcx, def_id| { + tcx.resolutions(()) + .doc_link_traits_in_scope + .get(&def_id.expect_local()) + .expect("no traits in scope for a doc link") + }, traits_in_crate: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); @@ -2280,6 +2247,22 @@ pub fn provide(providers: &mut Providers) { traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); tcx.arena.alloc_slice(&traits) }, + trait_impls_in_crate: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + + let mut trait_impls = Vec::new(); + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) + && tcx.impl_trait_ref(id.owner_id).is_some() + { + trait_impls.push(id.owner_id.to_def_id()) + } + } + + // Bring everything into deterministic order. + trait_impls.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); + tcx.arena.alloc_slice(&trait_impls) + }, ..*providers } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5066dbbb9..a7ec2d790 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -9,7 +9,7 @@ use rustc_attr as attr; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind}; +use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items::LangItem; @@ -18,7 +18,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; -use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; +use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; @@ -115,14 +115,16 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> { type Value<'tcx> = LazyArray<T::Value<'tcx>>; } +impl<T> Default for LazyArray<T> { + fn default() -> LazyArray<T> { + LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0) + } +} + impl<T> LazyArray<T> { fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray<T> { LazyArray { position, num_elems, _marker: PhantomData } } - - fn empty() -> LazyArray<T> { - LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0) - } } /// A list of lazily-decoded values, with the added capability of random access. @@ -185,9 +187,9 @@ enum LazyState { Previous(NonZeroUsize), } -type SyntaxContextTable = LazyTable<u32, LazyValue<SyntaxContextData>>; -type ExpnDataTable = LazyTable<ExpnIndex, LazyValue<ExpnData>>; -type ExpnHashTable = LazyTable<ExpnIndex, LazyValue<ExpnHash>>; +type SyntaxContextTable = LazyTable<u32, Option<LazyValue<SyntaxContextData>>>; +type ExpnDataTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnData>>>; +type ExpnHashTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnHash>>>; #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct ProcMacroData { @@ -253,7 +255,7 @@ pub(crate) struct CrateRoot { def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>, - source_map: LazyTable<u32, LazyValue<rustc_span::SourceFile>>, + source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>, compiler_builtins: bool, needs_allocator: bool, @@ -315,21 +317,27 @@ pub(crate) struct IncoherentImpls { /// Define `LazyTables` and `TableBuilders` at the same time. macro_rules! define_tables { - ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => { + ( + - defaulted: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+ + - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+ + ) => { #[derive(MetadataEncodable, MetadataDecodable)] pub(crate) struct LazyTables { - $($name: LazyTable<$IDX, $T>),+ + $($name1: LazyTable<$IDX1, $T1>,)+ + $($name2: LazyTable<$IDX2, Option<$T2>>,)+ } #[derive(Default)] struct TableBuilders { - $($name: TableBuilder<$IDX, $T>),+ + $($name1: TableBuilder<$IDX1, $T1>,)+ + $($name2: TableBuilder<$IDX2, Option<$T2>>,)+ } impl TableBuilders { fn encode(&self, buf: &mut FileEncoder) -> LazyTables { LazyTables { - $($name: self.$name.encode(buf)),+ + $($name1: self.$name1.encode(buf),)+ + $($name2: self.$name2.encode(buf),)+ } } } @@ -337,9 +345,20 @@ macro_rules! define_tables { } define_tables! { +- defaulted: + is_intrinsic: Table<DefIndex, bool>, + is_macro_rules: Table<DefIndex, bool>, + is_type_alias_impl_trait: Table<DefIndex, bool>, + attr_flags: Table<DefIndex, AttrFlags>, + def_path_hashes: Table<DefIndex, DefPathHash>, + explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>, + inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, + inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, + associated_items_for_impl_trait_in_trait: Table<DefIndex, LazyArray<DefId>>, + +- optional: attributes: Table<DefIndex, LazyArray<ast::Attribute>>, children: Table<DefIndex, LazyArray<DefIndex>>, - opt_def_kind: Table<DefIndex, DefKind>, visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>, def_span: Table<DefIndex, LazyValue<Span>>, @@ -348,29 +367,25 @@ define_tables! { lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>, lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>, lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>, - // As an optimization, a missing entry indicates an empty `&[]`. - explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>, explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, generics_of: Table<DefIndex, LazyValue<ty::Generics>>, - // As an optimization, a missing entry indicates an empty `&[]`. - inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>, super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>, - type_of: Table<DefIndex, LazyValue<Ty<'static>>>, + type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<Ty<'static>>>>, variances_of: Table<DefIndex, LazyArray<ty::Variance>>, - fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>, + fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::PolyFnSig<'static>>>>, codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>, impl_trait_ref: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::TraitRef<'static>>>>, const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>, object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>, optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>, mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>, + mir_generator_witnesses: Table<DefIndex, LazyValue<mir::GeneratorLayout<'static>>>, promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>, // FIXME(compiler-errors): Why isn't this a LazyArray? thir_abstract_const: Table<DefIndex, LazyValue<ty::Const<'static>>>, impl_parent: Table<DefIndex, RawDefId>, impl_polarity: Table<DefIndex, ty::ImplPolarity>, 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, LazyValue<ty::adjustment::CoerceUnsizedInfo>>, @@ -380,9 +395,7 @@ define_tables! { 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, LazyArray<DefIndex>>, expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>, unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>, params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>, @@ -392,22 +405,17 @@ define_tables! { // `DefPathTable` up front, since we may only ever use a few // definitions from any given crate. def_keys: Table<DefIndex, LazyValue<DefKey>>, - def_path_hashes: Table<DefIndex, DefPathHash>, proc_macro_quoted_spans: Table<usize, LazyValue<Span>>, generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>, - may_have_doc_links: Table<DefIndex, ()>, variant_data: Table<DefIndex, LazyValue<VariantData>>, assoc_container: Table<DefIndex, ty::AssocItemContainer>, - // Slot is full when macro is macro_rules. - macro_rules: Table<DefIndex, ()>, macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>, proc_macro: Table<DefIndex, MacroKind>, module_reexports: Table<DefIndex, LazyArray<ModChild>>, deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, - // Slot is full when opaque is TAIT. - is_type_alias_impl_trait: Table<DefIndex, ()>, - trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>, + doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>, + doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>, } #[derive(TyEncodable, TyDecodable)] @@ -418,6 +426,13 @@ struct VariantData { is_non_exhaustive: bool, } +bitflags::bitflags! { + #[derive(Default)] + pub struct AttrFlags: u8 { + const IS_DOC_HIDDEN = 1 << 0; + } +} + // Tags used for encoding Spans: const TAG_VALID_SPAN_LOCAL: u8 = 0; const TAG_VALID_SPAN_FOREIGN: u8 = 1; @@ -440,4 +455,5 @@ trivially_parameterized_over_tcx! { IncoherentImpls, CrateRoot, CrateDep, + AttrFlags, } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 716655c7f..b89d48ec1 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -10,18 +10,61 @@ use rustc_span::hygiene::MacroKind; use std::marker::PhantomData; use std::num::NonZeroUsize; +pub(super) trait IsDefault: Default { + fn is_default(&self) -> bool; +} + +impl<T> IsDefault for Option<T> { + fn is_default(&self) -> bool { + self.is_none() + } +} + +impl IsDefault for AttrFlags { + fn is_default(&self) -> bool { + self.is_empty() + } +} + +impl IsDefault for bool { + fn is_default(&self) -> bool { + !self + } +} + +impl IsDefault for u32 { + fn is_default(&self) -> bool { + *self == 0 + } +} + +impl<T> IsDefault for LazyArray<T> { + fn is_default(&self) -> bool { + self.num_elems == 0 + } +} + +impl IsDefault for DefPathHash { + fn is_default(&self) -> bool { + self.0 == Fingerprint::ZERO + } +} + /// Helper trait, for encoding to, and decoding from, a fixed number of bytes. /// Used mainly for Lazy positions and lengths. /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`, /// but this has no impact on safety. -pub(super) trait FixedSizeEncoding: Default { +pub(super) trait FixedSizeEncoding: IsDefault { /// This should be `[u8; BYTE_LEN]`; + /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations. type ByteArray; fn from_bytes(b: &Self::ByteArray) -> Self; fn write_to_bytes(self, b: &mut Self::ByteArray); } +/// This implementation is not used generically, but for reading/writing +/// concrete `u32` fields in `Lazy*` structures, which may be zero. impl FixedSizeEncoding for u32 { type ByteArray = [u8; 4]; @@ -57,7 +100,7 @@ macro_rules! fixed_size_enum { fn write_to_bytes(self, b: &mut [u8;1]) { use $ty::*; b[0] = match self { - None => 0, + None => unreachable!(), $(Some($($pat)*) => 1 + ${index()},)* } } @@ -93,7 +136,8 @@ fixed_size_enum! { ( Field ) ( LifetimeParam ) ( GlobalAsm ) - ( Impl ) + ( Impl { of_trait: false } ) + ( Impl { of_trait: true } ) ( Closure ) ( Generator ) ( Static(ast::Mutability::Not) ) @@ -154,20 +198,18 @@ fixed_size_enum! { } // We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost. -impl FixedSizeEncoding for Option<DefPathHash> { +impl FixedSizeEncoding for DefPathHash { type ByteArray = [u8; 16]; #[inline] fn from_bytes(b: &[u8; 16]) -> Self { - Some(DefPathHash(Fingerprint::from_le_bytes(*b))) + DefPathHash(Fingerprint::from_le_bytes(*b)) } #[inline] fn write_to_bytes(self, b: &mut [u8; 16]) { - let Some(DefPathHash(fingerprint)) = self else { - panic!("Trying to encode absent DefPathHash.") - }; - *b = fingerprint.to_le_bytes(); + debug_assert!(!self.is_default()); + *b = self.0.to_le_bytes(); } } @@ -178,17 +220,17 @@ impl FixedSizeEncoding for Option<RawDefId> { #[inline] fn from_bytes(b: &[u8; 8]) -> Self { let krate = u32::from_le_bytes(b[0..4].try_into().unwrap()); - let index = u32::from_le_bytes(b[4..8].try_into().unwrap()); if krate == 0 { return None; } + let index = u32::from_le_bytes(b[4..8].try_into().unwrap()); Some(RawDefId { krate: krate - 1, index }) } #[inline] fn write_to_bytes(self, b: &mut [u8; 8]) { match self { - None => *b = [0; 8], + None => unreachable!(), Some(RawDefId { krate, index }) => { // CrateNum is less than `CrateNum::MAX_AS_U32`. debug_assert!(krate < u32::MAX); @@ -199,17 +241,33 @@ impl FixedSizeEncoding for Option<RawDefId> { } } -impl FixedSizeEncoding for Option<()> { +impl FixedSizeEncoding for AttrFlags { + type ByteArray = [u8; 1]; + + #[inline] + fn from_bytes(b: &[u8; 1]) -> Self { + AttrFlags::from_bits_truncate(b[0]) + } + + #[inline] + fn write_to_bytes(self, b: &mut [u8; 1]) { + debug_assert!(!self.is_default()); + b[0] = self.bits(); + } +} + +impl FixedSizeEncoding for bool { type ByteArray = [u8; 1]; #[inline] fn from_bytes(b: &[u8; 1]) -> Self { - (b[0] != 0).then(|| ()) + b[0] != 0 } #[inline] fn write_to_bytes(self, b: &mut [u8; 1]) { - b[0] = self.is_some() as u8 + debug_assert!(!self.is_default()); + b[0] = self as u8 } } @@ -227,76 +285,115 @@ impl<T> FixedSizeEncoding for Option<LazyValue<T>> { #[inline] fn write_to_bytes(self, b: &mut [u8; 4]) { - let position = self.map_or(0, |lazy| lazy.position.get()); + match self { + None => unreachable!(), + Some(lazy) => { + let position = lazy.position.get(); + let position: u32 = position.try_into().unwrap(); + position.write_to_bytes(b) + } + } + } +} + +impl<T> LazyArray<T> { + #[inline] + fn write_to_bytes_impl(self, b: &mut [u8; 8]) { + let ([position_bytes, meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() }; + + let position = self.position.get(); let position: u32 = position.try_into().unwrap(); - position.write_to_bytes(b) + position.write_to_bytes(position_bytes); + + let len = self.num_elems; + let len: u32 = len.try_into().unwrap(); + len.write_to_bytes(meta_bytes); + } + + fn from_bytes_impl(position_bytes: &[u8; 4], meta_bytes: &[u8; 4]) -> Option<LazyArray<T>> { + let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?; + let len = u32::from_bytes(meta_bytes) as usize; + Some(LazyArray::from_position_and_num_elems(position, len)) } } -impl<T> FixedSizeEncoding for Option<LazyArray<T>> { +impl<T> FixedSizeEncoding for LazyArray<T> { type ByteArray = [u8; 8]; #[inline] fn from_bytes(b: &[u8; 8]) -> Self { - 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(LazyArray::from_position_and_num_elems(position, len)) + let ([position_bytes, meta_bytes],[])= b.as_chunks::<4>() else { panic!() }; + if *meta_bytes == [0; 4] { + return Default::default(); + } + LazyArray::from_bytes_impl(position_bytes, meta_bytes).unwrap() } #[inline] fn write_to_bytes(self, b: &mut [u8; 8]) { - let ([ref mut position_bytes, ref mut meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() }; + assert!(!self.is_default()); + self.write_to_bytes_impl(b) + } +} - let position = self.map_or(0, |lazy| lazy.position.get()); - let position: u32 = position.try_into().unwrap(); - position.write_to_bytes(position_bytes); +impl<T> FixedSizeEncoding for Option<LazyArray<T>> { + type ByteArray = [u8; 8]; - let len = self.map_or(0, |lazy| lazy.num_elems); - let len: u32 = len.try_into().unwrap(); - len.write_to_bytes(meta_bytes); + #[inline] + fn from_bytes(b: &[u8; 8]) -> Self { + let ([position_bytes, meta_bytes],[])= b.as_chunks::<4>() else { panic!() }; + LazyArray::from_bytes_impl(position_bytes, meta_bytes) + } + + #[inline] + fn write_to_bytes(self, b: &mut [u8; 8]) { + match self { + None => unreachable!(), + Some(lazy) => lazy.write_to_bytes_impl(b), + } } } /// Helper for constructing a table's serialization (also see `Table`). -pub(super) struct TableBuilder<I: Idx, T> -where - Option<T>: FixedSizeEncoding, -{ - blocks: IndexVec<I, <Option<T> as FixedSizeEncoding>::ByteArray>, +pub(super) struct TableBuilder<I: Idx, T: FixedSizeEncoding> { + blocks: IndexVec<I, T::ByteArray>, _marker: PhantomData<T>, } -impl<I: Idx, T> Default for TableBuilder<I, T> -where - Option<T>: FixedSizeEncoding, -{ +impl<I: Idx, T: FixedSizeEncoding> Default for TableBuilder<I, T> { fn default() -> Self { TableBuilder { blocks: Default::default(), _marker: PhantomData } } } -impl<I: Idx, T> TableBuilder<I, T> +impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>> where - Option<T>: FixedSizeEncoding, + Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, { - pub(crate) fn set<const N: usize>(&mut self, i: I, value: T) - where - Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, - { - // FIXME(eddyb) investigate more compact encodings for sparse tables. - // On the PR @michaelwoerister mentioned: - // > Space requirements could perhaps be optimized by using the HAMT `popcnt` - // > trick (i.e. divide things into buckets of 32 or 64 items and then - // > store bit-masks of which item in each bucket is actually serialized). - self.blocks.ensure_contains_elem(i, || [0; N]); - Some(value).write_to_bytes(&mut self.blocks[i]); - } - - pub(crate) fn encode<const N: usize>(&self, buf: &mut FileEncoder) -> LazyTable<I, T> - where - Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, - { + pub(crate) fn set_some(&mut self, i: I, value: T) { + self.set(i, Some(value)) + } +} + +impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> { + /// Sets the table value if it is not default. + /// ATTENTION: For optimization default values are simply ignored by this function, because + /// right now metadata tables never need to reset non-default values to default. If such need + /// arises in the future then a new method (e.g. `clear` or `reset`) will need to be introduced + /// for doing that explicitly. + pub(crate) fn set(&mut self, i: I, value: T) { + if !value.is_default() { + // FIXME(eddyb) investigate more compact encodings for sparse tables. + // On the PR @michaelwoerister mentioned: + // > Space requirements could perhaps be optimized by using the HAMT `popcnt` + // > trick (i.e. divide things into buckets of 32 or 64 items and then + // > store bit-masks of which item in each bucket is actually serialized). + self.blocks.ensure_contains_elem(i, || [0; N]); + value.write_to_bytes(&mut self.blocks[i]); + } + } + + pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> { let pos = buf.position(); for block in &self.blocks { buf.emit_raw_bytes(block); @@ -309,34 +406,24 @@ where } } -impl<I: Idx, T: ParameterizedOverTcx> LazyTable<I, T> +impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]> + ParameterizedOverTcx> + LazyTable<I, T> where - Option<T>: FixedSizeEncoding, + for<'tcx> T::Value<'tcx>: FixedSizeEncoding<ByteArray = [u8; N]>, { /// Given the metadata, extract out the value at a particular index (if any). #[inline(never)] - pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>, const N: usize>( - &self, - metadata: M, - i: I, - ) -> Option<T::Value<'tcx>> - where - Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>, - { + pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> { debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size); let start = self.position.get(); 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) + bytes.get(i.index()).map_or_else(Default::default, FixedSizeEncoding::from_bytes) } /// Size of the table in entries, including possible gaps. - pub(super) fn size<const N: usize>(&self) -> usize - where - for<'tcx> Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>, - { + pub(super) fn size(&self) -> usize { self.encoded_size / N } } |