From 08f204e17f1f007d844743802e04d7f62689e966 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 4 Apr 2023 14:15:29 -0700 Subject: [PATCH] rustdoc: migrate `document_type_layout` to askama --- src/librustdoc/html/render/print_item.rs | 166 +++++++----------- .../html/templates/type_layout.html | 45 +++++ 2 files changed, 112 insertions(+), 99 deletions(-) create mode 100644 src/librustdoc/html/templates/type_layout.html diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 6bce57340040..e089b55b9c4d 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -5,13 +5,15 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; +use rustc_index::vec::IndexVec; use rustc_middle::middle::stability; use rustc_middle::span_bug; -use rustc_middle::ty::layout::LayoutError; +use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::{self, Adt, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_target::abi::{LayoutS, Primitive, TagEncoding, Variants}; +use rustc_target::abi::{LayoutS, Primitive, TagEncoding, VariantIdx, Variants}; +use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; use std::rc::Rc; @@ -1936,111 +1938,77 @@ fn document_type_layout<'a, 'cx: 'a>( cx: &'a Context<'cx>, ty_def_id: DefId, ) -> impl fmt::Display + 'a + Captures<'cx> { - fn write_size_of_layout(mut w: impl fmt::Write, layout: &LayoutS, tag_size: u64) { - if layout.abi.is_unsized() { - write!(w, "(unsized)").unwrap(); - } else { - let size = layout.size.bytes() - tag_size; - write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" }).unwrap(); - if layout.abi.is_uninhabited() { - write!( - w, - " (uninhabited)" - ).unwrap(); + #[derive(Template)] + #[template(path = "type_layout.html")] + struct TypeLayout<'a, 'cx> { + cx: &'a Context<'cx>, + ty_def_id: DefId, + } + + impl<'a, 'cx: 'a> TypeLayout<'a, 'cx> { + fn variants<'b: 'a>(&'b self) -> Option<&'b IndexVec> { + if let Variants::Multiple { variants, .. } = + self.type_layout().unwrap().layout.variants() && !variants.is_empty() { + Some(&variants) + } else { + None } } + fn type_layout<'b: 'a>(&'b self) -> Result, LayoutError<'cx>> { + let tcx = self.cx.tcx(); + let param_env = tcx.param_env(self.ty_def_id); + let ty = tcx.type_of(self.ty_def_id).subst_identity(); + tcx.layout_of(param_env.and(ty)) + } + fn variant_name<'b: 'a>(&'b self, index: VariantIdx) -> Symbol { + let Adt(adt, _) = self.type_layout().unwrap().ty.kind() else { + span_bug!(self.cx.tcx().def_span(self.ty_def_id), "not an adt") + }; + adt.variant(index).name + } + fn tag_size<'b: 'a>(&'b self) -> u64 { + if let Variants::Multiple { variants, tag, tag_encoding, .. } = + self.type_layout().unwrap().layout.variants() && !variants.is_empty() { + if let TagEncoding::Niche { .. } = tag_encoding { + 0 + } else if let Primitive::Int(i, _) = tag.primitive() { + i.size().bytes() + } else { + span_bug!(self.cx.tcx().def_span(self.ty_def_id), "tag is neither niche nor int") + } + } else { + 0 + } + } + fn write_size<'b: 'a>( + &'b self, + layout: &'b LayoutS, + tag_size: u64, + ) -> impl fmt::Display + Captures<'cx> + Captures<'b> { + display_fn(move |f| { + if layout.abi.is_unsized() { + write!(f, "(unsized)")?; + } else { + let size = layout.size.bytes() - tag_size; + write!(f, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" })?; + if layout.abi.is_uninhabited() { + write!( + f, + " (uninhabited)" + )?; + } + } + Ok(()) + }) + } } - display_fn(move |mut f| { + display_fn(move |f| { if !cx.shared.show_type_layout { return Ok(()); } - writeln!( - f, - "

\ - Layout§

" - )?; - writeln!(f, "
")?; - - let tcx = cx.tcx(); - let param_env = tcx.param_env(ty_def_id); - let ty = tcx.type_of(ty_def_id).subst_identity(); - match tcx.layout_of(param_env.and(ty)) { - Ok(ty_layout) => { - writeln!( - f, - "

Note: Most layout information is \ - completely unstable and may even differ between compilations. \ - The only exception is types with certain repr(...) attributes. \ - Please see the Rust Reference’s \ - “Type Layout” \ - chapter for details on type layout guarantees.

" - )?; - f.write_str("

Size: ")?; - write_size_of_layout(&mut f, &ty_layout.layout.0, 0); - writeln!(f, "

")?; - if let Variants::Multiple { variants, tag, tag_encoding, .. } = - &ty_layout.layout.variants() - { - if !variants.is_empty() { - f.write_str( - "

Size for each variant:

\ -
    ", - )?; - - let Adt(adt, _) = ty_layout.ty.kind() else { - span_bug!(tcx.def_span(ty_def_id), "not an adt") - }; - - let tag_size = if let TagEncoding::Niche { .. } = tag_encoding { - 0 - } else if let Primitive::Int(i, _) = tag.primitive() { - i.size().bytes() - } else { - span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") - }; - - for (index, layout) in variants.iter_enumerated() { - let name = adt.variant(index).name; - write!(&mut f, "
  • {name}: ")?; - write_size_of_layout(&mut f, layout, tag_size); - writeln!(&mut f, "
  • ")?; - } - f.write_str("
")?; - } - } - } - // This kind of layout error can occur with valid code, e.g. if you try to - // get the layout of a generic type such as `Vec`. - Err(LayoutError::Unknown(_)) => { - writeln!( - f, - "

Note: Unable to compute type layout, \ - possibly due to this type having generic parameters. \ - Layout can only be computed for concrete, fully-instantiated types.

" - )?; - } - // This kind of error probably can't happen with valid code, but we don't - // want to panic and prevent the docs from building, so we just let the - // user know that we couldn't compute the layout. - Err(LayoutError::SizeOverflow(_)) => { - writeln!( - f, - "

Note: Encountered an error during type layout; \ - the type was too big.

" - )?; - } - Err(LayoutError::NormalizationFailure(_, _)) => { - writeln!( - f, - "

Note: Encountered an error during type layout; \ - the type failed to be normalized.

" - )?; - } - } - - writeln!(f, "
") + Ok(TypeLayout { cx, ty_def_id }.render_into(f).unwrap()) }) } diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html new file mode 100644 index 000000000000..70149d4e1ab8 --- /dev/null +++ b/src/librustdoc/html/templates/type_layout.html @@ -0,0 +1,45 @@ +

{# #} + Layout§ {# #} +

{# #} +
{# #} + {% match self.type_layout() %} + {% when Ok(ty_layout) %} +
{# #} +

{# #} + Note: Most layout information is completely {#+ #} + unstable and may even differ between compilations. {#+ #} + The only exception is types with certain repr(...) {#+ #} + attributes. Please see the Rust Reference’s {#+ #} + “Type Layout” {#+ #} + chapter for details on type layout guarantees. {# #} +

{# #} +
{# #} +

Size: {{ self.write_size(ty_layout.layout.0.borrow(), 0) | safe }}

{# #} + {% if let Some(variants) = self.variants() %} +

Size for each variant:

{# #} +
    {# #} + {% for (index, layout) in variants.iter_enumerated() %} +
  • {# #} + {{ self.variant_name(index.clone()) }}: {#+ #} + {{ self.write_size(layout, self.tag_size()) | safe }} +
  • {# #} + {% endfor %} +
{# #} + {% endif %} + {# This kind of layout error can occur with valid code, e.g. if you try to + get the layout of a generic type such as `Vec`. #} + {% when Err(LayoutError::Unknown(_)) %} +

Note: Unable to compute type layout, {#+ #} + possibly due to this type having generic parameters. {#+ #} + Layout can only be computed for concrete, fully-instantiated types.

{# #} + {# This kind of error probably can't happen with valid code, but we don't + want to panic and prevent the docs from building, so we just let the + user know that we couldn't compute the layout. #} + {% when Err(LayoutError::SizeOverflow(_)) %} +

Note: Encountered an error during type layout; {#+ #} + the type was too big.

{# #} + {% when Err(LayoutError::NormalizationFailure(_, _)) %} +

Note: Encountered an error during type layout; {#+ #} + the type failed to be normalized.

{# #} + {% endmatch %} +
{# #}