Skip to content

Commit 08f204e

Browse files
committed
rustdoc: migrate document_type_layout to askama
1 parent d1be642 commit 08f204e

File tree

2 files changed

+112
-99
lines changed

2 files changed

+112
-99
lines changed

src/librustdoc/html/render/print_item.rs

Lines changed: 67 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
55
use rustc_hir as hir;
66
use rustc_hir::def::CtorKind;
77
use rustc_hir::def_id::DefId;
8+
use rustc_index::vec::IndexVec;
89
use rustc_middle::middle::stability;
910
use rustc_middle::span_bug;
10-
use rustc_middle::ty::layout::LayoutError;
11+
use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
1112
use rustc_middle::ty::{self, Adt, TyCtxt};
1213
use rustc_span::hygiene::MacroKind;
1314
use rustc_span::symbol::{kw, sym, Symbol};
14-
use rustc_target::abi::{LayoutS, Primitive, TagEncoding, Variants};
15+
use rustc_target::abi::{LayoutS, Primitive, TagEncoding, VariantIdx, Variants};
16+
use std::borrow::Borrow;
1517
use std::cmp::Ordering;
1618
use std::fmt;
1719
use std::rc::Rc;
@@ -1936,111 +1938,77 @@ fn document_type_layout<'a, 'cx: 'a>(
19361938
cx: &'a Context<'cx>,
19371939
ty_def_id: DefId,
19381940
) -> impl fmt::Display + 'a + Captures<'cx> {
1939-
fn write_size_of_layout(mut w: impl fmt::Write, layout: &LayoutS, tag_size: u64) {
1940-
if layout.abi.is_unsized() {
1941-
write!(w, "(unsized)").unwrap();
1942-
} else {
1943-
let size = layout.size.bytes() - tag_size;
1944-
write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" }).unwrap();
1945-
if layout.abi.is_uninhabited() {
1946-
write!(
1947-
w,
1948-
" (<a href=\"https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\">uninhabited</a>)"
1949-
).unwrap();
1950-
}
1951-
}
1941+
#[derive(Template)]
1942+
#[template(path = "type_layout.html")]
1943+
struct TypeLayout<'a, 'cx> {
1944+
cx: &'a Context<'cx>,
1945+
ty_def_id: DefId,
19521946
}
19531947

1954-
display_fn(move |mut f| {
1955-
if !cx.shared.show_type_layout {
1956-
return Ok(());
1948+
impl<'a, 'cx: 'a> TypeLayout<'a, 'cx> {
1949+
fn variants<'b: 'a>(&'b self) -> Option<&'b IndexVec<VariantIdx, LayoutS>> {
1950+
if let Variants::Multiple { variants, .. } =
1951+
self.type_layout().unwrap().layout.variants() && !variants.is_empty() {
1952+
Some(&variants)
1953+
} else {
1954+
None
1955+
}
19571956
}
1958-
1959-
writeln!(
1960-
f,
1961-
"<h2 id=\"layout\" class=\"small-section-header\"> \
1962-
Layout<a href=\"#layout\" class=\"anchor\">§</a></h2>"
1963-
)?;
1964-
writeln!(f, "<div class=\"docblock\">")?;
1965-
1966-
let tcx = cx.tcx();
1967-
let param_env = tcx.param_env(ty_def_id);
1968-
let ty = tcx.type_of(ty_def_id).subst_identity();
1969-
match tcx.layout_of(param_env.and(ty)) {
1970-
Ok(ty_layout) => {
1971-
writeln!(
1972-
f,
1973-
"<div class=\"warning\"><p><strong>Note:</strong> Most layout information is \
1974-
<strong>completely unstable</strong> and may even differ between compilations. \
1975-
The only exception is types with certain <code>repr(...)</code> attributes. \
1976-
Please see the Rust Reference’s \
1977-
<a href=\"https://doc.rust-lang.org/reference/type-layout.html\">“Type Layout”</a> \
1978-
chapter for details on type layout guarantees.</p></div>"
1979-
)?;
1980-
f.write_str("<p><strong>Size:</strong> ")?;
1981-
write_size_of_layout(&mut f, &ty_layout.layout.0, 0);
1982-
writeln!(f, "</p>")?;
1983-
if let Variants::Multiple { variants, tag, tag_encoding, .. } =
1984-
&ty_layout.layout.variants()
1985-
{
1986-
if !variants.is_empty() {
1987-
f.write_str(
1988-
"<p><strong>Size for each variant:</strong></p>\
1989-
<ul>",
1957+
fn type_layout<'b: 'a>(&'b self) -> Result<TyAndLayout<'cx>, LayoutError<'cx>> {
1958+
let tcx = self.cx.tcx();
1959+
let param_env = tcx.param_env(self.ty_def_id);
1960+
let ty = tcx.type_of(self.ty_def_id).subst_identity();
1961+
tcx.layout_of(param_env.and(ty))
1962+
}
1963+
fn variant_name<'b: 'a>(&'b self, index: VariantIdx) -> Symbol {
1964+
let Adt(adt, _) = self.type_layout().unwrap().ty.kind() else {
1965+
span_bug!(self.cx.tcx().def_span(self.ty_def_id), "not an adt")
1966+
};
1967+
adt.variant(index).name
1968+
}
1969+
fn tag_size<'b: 'a>(&'b self) -> u64 {
1970+
if let Variants::Multiple { variants, tag, tag_encoding, .. } =
1971+
self.type_layout().unwrap().layout.variants() && !variants.is_empty() {
1972+
if let TagEncoding::Niche { .. } = tag_encoding {
1973+
0
1974+
} else if let Primitive::Int(i, _) = tag.primitive() {
1975+
i.size().bytes()
1976+
} else {
1977+
span_bug!(self.cx.tcx().def_span(self.ty_def_id), "tag is neither niche nor int")
1978+
}
1979+
} else {
1980+
0
1981+
}
1982+
}
1983+
fn write_size<'b: 'a>(
1984+
&'b self,
1985+
layout: &'b LayoutS,
1986+
tag_size: u64,
1987+
) -> impl fmt::Display + Captures<'cx> + Captures<'b> {
1988+
display_fn(move |f| {
1989+
if layout.abi.is_unsized() {
1990+
write!(f, "(unsized)")?;
1991+
} else {
1992+
let size = layout.size.bytes() - tag_size;
1993+
write!(f, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" })?;
1994+
if layout.abi.is_uninhabited() {
1995+
write!(
1996+
f,
1997+
" (<a href=\"https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\">uninhabited</a>)"
19901998
)?;
1991-
1992-
let Adt(adt, _) = ty_layout.ty.kind() else {
1993-
span_bug!(tcx.def_span(ty_def_id), "not an adt")
1994-
};
1995-
1996-
let tag_size = if let TagEncoding::Niche { .. } = tag_encoding {
1997-
0
1998-
} else if let Primitive::Int(i, _) = tag.primitive() {
1999-
i.size().bytes()
2000-
} else {
2001-
span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int")
2002-
};
2003-
2004-
for (index, layout) in variants.iter_enumerated() {
2005-
let name = adt.variant(index).name;
2006-
write!(&mut f, "<li><code>{name}</code>: ")?;
2007-
write_size_of_layout(&mut f, layout, tag_size);
2008-
writeln!(&mut f, "</li>")?;
2009-
}
2010-
f.write_str("</ul>")?;
20111999
}
20122000
}
2013-
}
2014-
// This kind of layout error can occur with valid code, e.g. if you try to
2015-
// get the layout of a generic type such as `Vec<T>`.
2016-
Err(LayoutError::Unknown(_)) => {
2017-
writeln!(
2018-
f,
2019-
"<p><strong>Note:</strong> Unable to compute type layout, \
2020-
possibly due to this type having generic parameters. \
2021-
Layout can only be computed for concrete, fully-instantiated types.</p>"
2022-
)?;
2023-
}
2024-
// This kind of error probably can't happen with valid code, but we don't
2025-
// want to panic and prevent the docs from building, so we just let the
2026-
// user know that we couldn't compute the layout.
2027-
Err(LayoutError::SizeOverflow(_)) => {
2028-
writeln!(
2029-
f,
2030-
"<p><strong>Note:</strong> Encountered an error during type layout; \
2031-
the type was too big.</p>"
2032-
)?;
2033-
}
2034-
Err(LayoutError::NormalizationFailure(_, _)) => {
2035-
writeln!(
2036-
f,
2037-
"<p><strong>Note:</strong> Encountered an error during type layout; \
2038-
the type failed to be normalized.</p>"
2039-
)?;
2040-
}
2001+
Ok(())
2002+
})
2003+
}
2004+
}
2005+
2006+
display_fn(move |f| {
2007+
if !cx.shared.show_type_layout {
2008+
return Ok(());
20412009
}
20422010

2043-
writeln!(f, "</div>")
2011+
Ok(TypeLayout { cx, ty_def_id }.render_into(f).unwrap())
20442012
})
20452013
}
20462014

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<h2 id="layout" class="small-section-header"> {# #}
2+
Layout<a href="#layout" class="anchor">§</a> {# #}
3+
</h2> {# #}
4+
<div class="docblock"> {# #}
5+
{% match self.type_layout() %}
6+
{% when Ok(ty_layout) %}
7+
<div class="warning"> {# #}
8+
<p> {# #}
9+
<strong>Note:</strong> Most layout information is <strong>completely {#+ #}
10+
unstable</strong> and may even differ between compilations. {#+ #}
11+
The only exception is types with certain <code>repr(...)</code> {#+ #}
12+
attributes. Please see the Rust Reference’s {#+ #}
13+
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
14+
chapter for details on type layout guarantees. {# #}
15+
</p> {# #}
16+
</div> {# #}
17+
<p><strong>Size:</strong> {{ self.write_size(ty_layout.layout.0.borrow(), 0) | safe }}</p> {# #}
18+
{% if let Some(variants) = self.variants() %}
19+
<p><strong>Size for each variant:</strong></p> {# #}
20+
<ul> {# #}
21+
{% for (index, layout) in variants.iter_enumerated() %}
22+
<li> {# #}
23+
<code>{{ self.variant_name(index.clone()) }}</code>: {#+ #}
24+
{{ self.write_size(layout, self.tag_size()) | safe }}
25+
</li> {# #}
26+
{% endfor %}
27+
</ul> {# #}
28+
{% endif %}
29+
{# This kind of layout error can occur with valid code, e.g. if you try to
30+
get the layout of a generic type such as `Vec<T>`. #}
31+
{% when Err(LayoutError::Unknown(_)) %}
32+
<p><strong>Note:</strong> Unable to compute type layout, {#+ #}
33+
possibly due to this type having generic parameters. {#+ #}
34+
Layout can only be computed for concrete, fully-instantiated types.</p> {# #}
35+
{# This kind of error probably can't happen with valid code, but we don't
36+
want to panic and prevent the docs from building, so we just let the
37+
user know that we couldn't compute the layout. #}
38+
{% when Err(LayoutError::SizeOverflow(_)) %}
39+
<p><strong>Note:</strong> Encountered an error during type layout; {#+ #}
40+
the type was too big.</p> {# #}
41+
{% when Err(LayoutError::NormalizationFailure(_, _)) %}
42+
<p><strong>Note:</strong> Encountered an error during type layout; {#+ #}
43+
the type failed to be normalized.</p> {# #}
44+
{% endmatch %}
45+
</div> {# #}

0 commit comments

Comments
 (0)