From 8c7889bd18a93a7c82db0dcdf6c661594a5a8093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 1 Dec 2025 11:48:22 +0100 Subject: [PATCH] document various traits --- compiler/rustc_macros/src/lib.rs | 79 +++++++++++++++++--- compiler/rustc_macros/src/serialize.rs | 2 +- compiler/rustc_metadata/src/locator.rs | 1 - compiler/rustc_metadata/src/rmeta/decoder.rs | 12 ++- compiler/rustc_metadata/src/rmeta/mod.rs | 13 ++-- compiler/rustc_span/src/lib.rs | 14 ++++ 6 files changed, 97 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 9f55143ecf53..8cd6c0264448 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -72,25 +72,80 @@ pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { hash_stable::hash_stable_no_context_derive ); -decl_derive!([Decodable_NoContext] => serialize::decodable_nocontext_derive); +// Encoding and Decoding derives +decl_derive!([Decodable_NoContext] => + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: Decoder`. + serialize::decodable_nocontext_derive +); decl_derive!([Encodable_NoContext] => serialize::encodable_nocontext_derive); -decl_derive!([Decodable] => serialize::decodable_derive); +decl_derive!([Decodable] => + /// Derives `Decodable for T where D: SpanDecoder` + /// + /// # Deriving decoding traits + /// + /// > Some shared docs about decoding traits, since this is likely the first trait you find + /// + /// The difference between these derives can be subtle! + /// At a high level, there's the `T: Decodable` trait that says some type `T` + /// can be decoded using a decoder `D`. There are various decoders! + /// The different derives place different *trait* bounds on this type `D`. + /// + /// Even though this derive, based on its name, seems like the most vanilla one, + /// it actually places a pretty strict bound on `D`: `SpanDecoder`. + /// It means that types that derive this can contain spans, among other things, + /// and still be decoded. The reason this is hard is that at least in metadata, + /// spans can only be decoded later, once some information from the header + /// is already decoded to properly deal with spans. + /// + /// The hierarchy is roughly: + /// + /// - derive [`Decodable_NoContext`] is the most relaxed bounds that could be placed on `D`, + /// and is only really suited for structs and enums containing primitive types. + /// - derive [`BlobDecodable`] may be a better default, than deriving `Decodable`: + /// it places fewer requirements on `D`, while still allowing some complex types to be decoded. + /// - derive [`LazyDecodable`]: Only for types containing `Lazy{Array,Table,Value}`. + /// - derive [`Decodable`] for structures containing spans. Requires `D: SpanDecoder` + /// - derive [`TyDecodable`] for types that require access to the `TyCtxt` while decoding. + /// For example: arena allocated types. + serialize::decodable_derive +); decl_derive!([Encodable] => serialize::encodable_derive); -decl_derive!([TyDecodable] => serialize::type_decodable_derive); +decl_derive!([TyDecodable] => + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: TyDecoder`. + serialize::type_decodable_derive +); decl_derive!([TyEncodable] => serialize::type_encodable_derive); -decl_derive!([MetadataDecodable] => - /// This constrains the decoder to be specifically the decoder that can decode LazyArrays in metadata. - /// Therefore, we only use this on things containing LazyArray really. - /// Anything else should either be `NoContext`, if possible `BlobDecodable`, or otherwise just `Decodable`. - serialize::meta_decodable_derive +decl_derive!([LazyDecodable] => + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: LazyDecoder`. + /// This constrains the decoder to be specifically the decoder that can decode + /// `LazyArray`s, `LazyValue`s amd `LazyTable`s in metadata. + /// Therefore, we only need this on things containing LazyArray really. + /// + /// Most decodable derives mirror an encodable derive. + /// [`LazyDecodable`] and [`BlobDecodable`] together roughly mirror [`MetadataEncodable`] + serialize::lazy_decodable_derive ); decl_derive!([BlobDecodable] => - /// For anything that is "simple" to decode, without needing anything but the original data, - /// but for which the Decoder can customize some things - /// (unlike Decodable_NoContext which individual decoders can't customize). + /// See docs on derive [`Decodable`]. + /// + /// Derives `Decodable for T where D: BlobDecoder`. + /// + /// Most decodable derives mirror an encodable derive. + /// [`LazyDecodable`] and [`BlobDecodable`] together roughly mirror [`MetadataEncodable`] serialize::blob_decodable_derive ); -decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); +decl_derive!([MetadataEncodable] => + /// Most encodable derives mirror a decodable derive. + /// [`MetadataEncodable`] is roughly mirrored by the combination of [`LazyDecodable`] and [`BlobDecodable`] + serialize::meta_encodable_derive +); + decl_derive!( [TypeFoldable, attributes(type_foldable)] => /// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index abf566288df4..5ae6fb241c98 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -26,7 +26,7 @@ pub(super) fn blob_decodable_derive( decodable_body(s, decoder_ty) } -pub(super) fn meta_decodable_derive( +pub(super) fn lazy_decodable_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 6a441706a22b..9fef22f9558d 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -224,7 +224,6 @@ use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; -use rustc_middle::ty::TyCtxt; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index df0d1b7d085f..bf7818b49933 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -155,15 +155,20 @@ struct ImportedSourceFile { translated_source_file: Arc, } -/// Decode context used when we just have a blob, -/// and we still have to read the header etc. +/// Decode context used when we just have a blob of metadata from which we have to decode a header +/// and [`CrateRoot`]. After that, [`MetadataDecodeContext`] can be used. +/// Most notably, [`BlobDecodeContext]` doesn't implement [`SpanDecoder`] pub(super) struct BlobDecodeContext<'a> { opaque: MemDecoder<'a>, blob: &'a MetadataBlob, lazy_state: LazyState, } -/// trait for anything containing `LazyState` and is a decoder. +/// This trait abstracts over decoders that can decode lazy values using [`LazyState`]: +/// +/// - [`LazyValue`] +/// - [`LazyArray`] +/// - [`LazyTable`] pub(super) trait LazyDecoder: BlobDecoder { fn set_lazy_state(&mut self, state: LazyState); fn get_lazy_state(&self) -> LazyState; @@ -210,6 +215,7 @@ fn get_lazy_state(&self) -> LazyState { /// This is the decode context used when crate metadata was already read. /// Decoding of some types, like `Span` require some information to already been read. +/// Can be constructed from a [`TyCtxt`] and [`CrateMetadataRef`] (see the [`Metadata`] trait) pub(super) struct MetadataDecodeContext<'a, 'tcx> { blob_decoder: BlobDecodeContext<'a>, cdata: CrateMetadataRef<'a>, diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index b1b9bcfcc506..8ac1dd83ee5d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -19,8 +19,7 @@ use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_macros::{ - BlobDecodable, Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, - TyEncodable, + BlobDecodable, Decodable, Encodable, LazyDecodable, MetadataEncodable, TyDecodable, TyEncodable, }; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -188,7 +187,7 @@ enum LazyState { type ExpnDataTable = LazyTable>>; type ExpnHashTable = LazyTable>>; -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct ProcMacroData { proc_macro_decls_static: DefIndex, stability: Option, @@ -237,7 +236,7 @@ pub(crate) struct CrateHeader { /// compilation session. If we were to serialize a proc-macro crate like /// a normal crate, much of what we serialized would be unusable in addition /// to being unused. -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct CrateRoot { /// A header used to detect if this is the right crate to load. header: CrateHeader, @@ -334,13 +333,13 @@ pub(crate) struct CrateDep { pub is_private: bool, } -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct TraitImpls { trait_id: (u32, DefIndex), impls: LazyArray<(DefIndex, Option)>, } -#[derive(MetadataEncodable, MetadataDecodable)] +#[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct IncoherentImpls { self_ty: LazyValue, impls: LazyArray, @@ -352,7 +351,7 @@ macro_rules! define_tables { - defaulted: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+ - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+ ) => { - #[derive(MetadataEncodable, MetadataDecodable)] + #[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct LazyTables { $($name1: LazyTable<$IDX1, $T1>,)+ $($name2: LazyTable<$IDX2, Option<$T2>>,)+ diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index c6490b358ef8..6a359c5f4656 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1304,6 +1304,20 @@ pub trait BlobDecoder: Decoder { /// This trait is used to allow decoder specific encodings of certain types. /// It is similar to rustc_type_ir's TyDecoder. +/// +/// Specifically for metadata, an important note is that spans can only be decoded once +/// some other metadata is already read. +/// Spans have to be properly mapped into the decoding crate's sourcemap, +/// and crate numbers have to be converted sometimes. +/// This can only be done once the `CrateRoot` is available. +/// +/// As such, some methods that used to be in the `SpanDecoder` trait +/// are now in the `BlobDecoder` trait. This hierarchy is not mirrored for `Encoder`s. +/// `BlobDecoder` has methods for deserializing types that are more complex than just those +/// that can be decoded with `Decoder`, but which can be decoded on their own, *before* any other metadata is. +/// Importantly, that means that types that can be decoded with `BlobDecoder` can show up in the crate root. +/// The place where this distinction is relevant is in `rustc_metadata` where metadata is decoded using either the +/// `MetadataDecodeContext` or the `BlobDecodeContext`. pub trait SpanDecoder: BlobDecoder { fn decode_span(&mut self) -> Span; fn decode_expn_id(&mut self) -> ExpnId;