Rollup merge of #109949 - notriddle:notriddle/type-layout, r=jsha
rustdoc: migrate `document_type_layout` to askama
This commit is contained in:
commit
684bdf87f4
5 changed files with 154 additions and 116 deletions
|
@ -32,6 +32,7 @@ mod context;
|
||||||
mod print_item;
|
mod print_item;
|
||||||
mod sidebar;
|
mod sidebar;
|
||||||
mod span_map;
|
mod span_map;
|
||||||
|
mod type_layout;
|
||||||
mod write_shared;
|
mod write_shared;
|
||||||
|
|
||||||
pub(crate) use self::context::*;
|
pub(crate) use self::context::*;
|
||||||
|
|
|
@ -6,16 +6,14 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::CtorKind;
|
use rustc_hir::def::CtorKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_middle::ty::layout::LayoutError;
|
|
||||||
use rustc_middle::ty::{self, Adt, TyCtxt};
|
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
use rustc_target::abi::{LayoutS, Primitive, TagEncoding, Variants};
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::type_layout::document_type_layout;
|
||||||
use super::{
|
use super::{
|
||||||
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
|
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
|
||||||
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
|
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
|
||||||
|
@ -1933,118 +1931,6 @@ fn document_non_exhaustive<'a>(item: &'a clean::Item) -> impl fmt::Display + 'a
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
" (<a href=\"https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\">uninhabited</a>)"
|
|
||||||
).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
display_fn(move |mut f| {
|
|
||||||
if !cx.shared.show_type_layout {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"<h2 id=\"layout\" class=\"small-section-header\"> \
|
|
||||||
Layout<a href=\"#layout\" class=\"anchor\">§</a></h2>"
|
|
||||||
)?;
|
|
||||||
writeln!(f, "<div class=\"docblock\">")?;
|
|
||||||
|
|
||||||
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,
|
|
||||||
"<div class=\"warning\"><p><strong>Note:</strong> Most layout information is \
|
|
||||||
<strong>completely unstable</strong> and may even differ between compilations. \
|
|
||||||
The only exception is types with certain <code>repr(...)</code> attributes. \
|
|
||||||
Please see the Rust Reference’s \
|
|
||||||
<a href=\"https://doc.rust-lang.org/reference/type-layout.html\">“Type Layout”</a> \
|
|
||||||
chapter for details on type layout guarantees.</p></div>"
|
|
||||||
)?;
|
|
||||||
f.write_str("<p><strong>Size:</strong> ")?;
|
|
||||||
write_size_of_layout(&mut f, &ty_layout.layout.0, 0);
|
|
||||||
writeln!(f, "</p>")?;
|
|
||||||
if let Variants::Multiple { variants, tag, tag_encoding, .. } =
|
|
||||||
&ty_layout.layout.variants()
|
|
||||||
{
|
|
||||||
if !variants.is_empty() {
|
|
||||||
f.write_str(
|
|
||||||
"<p><strong>Size for each variant:</strong></p>\
|
|
||||||
<ul>",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
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, "<li><code>{name}</code>: ")?;
|
|
||||||
write_size_of_layout(&mut f, layout, tag_size);
|
|
||||||
writeln!(&mut f, "</li>")?;
|
|
||||||
}
|
|
||||||
f.write_str("</ul>")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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<T>`.
|
|
||||||
Err(LayoutError::Unknown(_)) => {
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"<p><strong>Note:</strong> Unable to compute type layout, \
|
|
||||||
possibly due to this type having generic parameters. \
|
|
||||||
Layout can only be computed for concrete, fully-instantiated types.</p>"
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
// 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,
|
|
||||||
"<p><strong>Note:</strong> Encountered an error during type layout; \
|
|
||||||
the type was too big.</p>"
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Err(LayoutError::NormalizationFailure(_, _)) => {
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"<p><strong>Note:</strong> Encountered an error during type layout; \
|
|
||||||
the type failed to be normalized.</p>"
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(f, "</div>")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pluralize(count: usize) -> &'static str {
|
fn pluralize(count: usize) -> &'static str {
|
||||||
if count > 1 { "s" } else { "" }
|
if count > 1 { "s" } else { "" }
|
||||||
}
|
}
|
||||||
|
|
86
src/librustdoc/html/render/type_layout.rs
Normal file
86
src/librustdoc/html/render/type_layout.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use askama::Template;
|
||||||
|
|
||||||
|
use rustc_data_structures::captures::Captures;
|
||||||
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_middle::span_bug;
|
||||||
|
use rustc_middle::ty::layout::LayoutError;
|
||||||
|
use rustc_middle::ty::Adt;
|
||||||
|
use rustc_span::symbol::Symbol;
|
||||||
|
use rustc_target::abi::{Primitive, TagEncoding, Variants};
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::html::format::display_fn;
|
||||||
|
use crate::html::render::Context;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "type_layout.html")]
|
||||||
|
struct TypeLayout<'cx> {
|
||||||
|
variants: Vec<(Symbol, TypeLayoutSize)>,
|
||||||
|
type_layout_size: Result<TypeLayoutSize, LayoutError<'cx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "type_layout_size.html")]
|
||||||
|
struct TypeLayoutSize {
|
||||||
|
is_unsized: bool,
|
||||||
|
is_uninhabited: bool,
|
||||||
|
size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn document_type_layout<'a, 'cx: 'a>(
|
||||||
|
cx: &'a Context<'cx>,
|
||||||
|
ty_def_id: DefId,
|
||||||
|
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||||
|
display_fn(move |f| {
|
||||||
|
if !cx.shared.show_type_layout {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let tcx = cx.tcx();
|
||||||
|
let param_env = tcx.param_env(ty_def_id);
|
||||||
|
let ty = tcx.type_of(ty_def_id).subst_identity();
|
||||||
|
let type_layout = tcx.layout_of(param_env.and(ty));
|
||||||
|
|
||||||
|
let variants =
|
||||||
|
if let Ok(type_layout) = type_layout &&
|
||||||
|
let Variants::Multiple { variants, tag, tag_encoding, .. } =
|
||||||
|
type_layout.layout.variants() &&
|
||||||
|
!variants.is_empty()
|
||||||
|
{
|
||||||
|
let tag_size =
|
||||||
|
if let TagEncoding::Niche { .. } = tag_encoding {
|
||||||
|
0
|
||||||
|
} else if let Primitive::Int(i, _) = tag.primitive() {
|
||||||
|
i.size().bytes()
|
||||||
|
} else {
|
||||||
|
span_bug!(cx.tcx().def_span(ty_def_id), "tag is neither niche nor int")
|
||||||
|
};
|
||||||
|
variants
|
||||||
|
.iter_enumerated()
|
||||||
|
.map(|(variant_idx, variant_layout)| {
|
||||||
|
let Adt(adt, _) = type_layout.ty.kind() else {
|
||||||
|
span_bug!(cx.tcx().def_span(ty_def_id), "not an adt")
|
||||||
|
};
|
||||||
|
let name = adt.variant(variant_idx).name;
|
||||||
|
let is_unsized = variant_layout.abi.is_unsized();
|
||||||
|
let is_uninhabited = variant_layout.abi.is_uninhabited();
|
||||||
|
let size = variant_layout.size.bytes() - tag_size;
|
||||||
|
let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size };
|
||||||
|
(name, type_layout_size)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| {
|
||||||
|
let is_unsized = layout.abi.is_unsized();
|
||||||
|
let is_uninhabited = layout.abi.is_uninhabited();
|
||||||
|
let size = layout.size.bytes();
|
||||||
|
TypeLayoutSize { is_unsized, is_uninhabited, size }
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(TypeLayout { variants, type_layout_size }.render_into(f).unwrap())
|
||||||
|
})
|
||||||
|
}
|
53
src/librustdoc/html/templates/type_layout.html
Normal file
53
src/librustdoc/html/templates/type_layout.html
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<h2 id="layout" class="small-section-header"> {# #}
|
||||||
|
Layout<a href="#layout" class="anchor">§</a> {# #}
|
||||||
|
</h2> {# #}
|
||||||
|
<div class="docblock"> {# #}
|
||||||
|
{% match type_layout_size %}
|
||||||
|
{% when Ok(type_layout_size) %}
|
||||||
|
<div class="warning"> {# #}
|
||||||
|
<p> {# #}
|
||||||
|
<strong>Note:</strong> Most layout information is <strong>completely {#+ #}
|
||||||
|
unstable</strong> and may even differ between compilations. {#+ #}
|
||||||
|
The only exception is types with certain <code>repr(...)</code> {#+ #}
|
||||||
|
attributes. Please see the Rust Reference’s {#+ #}
|
||||||
|
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
|
||||||
|
chapter for details on type layout guarantees. {# #}
|
||||||
|
</p> {# #}
|
||||||
|
</div> {# #}
|
||||||
|
<p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
|
||||||
|
{% if !variants.is_empty() %}
|
||||||
|
<p> {# #}
|
||||||
|
<strong>Size for each variant:</strong> {# #}
|
||||||
|
</p> {# #}
|
||||||
|
<ul> {# #}
|
||||||
|
{% for (name, layout_size) in variants %}
|
||||||
|
<li> {# #}
|
||||||
|
<code>{{ name }}</code>: {#+ #}
|
||||||
|
{{ layout_size|safe }}
|
||||||
|
</li> {# #}
|
||||||
|
{% endfor %}
|
||||||
|
</ul> {# #}
|
||||||
|
{% 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<T>`. #}
|
||||||
|
{% when Err(LayoutError::Unknown(_)) %}
|
||||||
|
<p> {# #}
|
||||||
|
<strong>Note:</strong> Unable to compute type layout, {#+ #}
|
||||||
|
possibly due to this type having generic parameters. {#+ #}
|
||||||
|
Layout can only be computed for concrete, fully-instantiated types. {# #}
|
||||||
|
</p> {# #}
|
||||||
|
{# 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(_)) %}
|
||||||
|
<p> {# #}
|
||||||
|
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
|
||||||
|
the type was too big. {# #}
|
||||||
|
</p> {# #}
|
||||||
|
{% when Err(LayoutError::NormalizationFailure(_, _)) %}
|
||||||
|
<p> {# #}
|
||||||
|
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
|
||||||
|
the type failed to be normalized. {# #}
|
||||||
|
</p> {# #}
|
||||||
|
{% endmatch %}
|
||||||
|
</div> {# #}
|
12
src/librustdoc/html/templates/type_layout_size.html
Normal file
12
src/librustdoc/html/templates/type_layout_size.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% if is_unsized %}
|
||||||
|
(unsized)
|
||||||
|
{% else %}
|
||||||
|
{% if size == 1 %}
|
||||||
|
1 byte
|
||||||
|
{% else %}
|
||||||
|
{{ size +}} bytes
|
||||||
|
{% endif %}
|
||||||
|
{% if is_uninhabited %}
|
||||||
|
{# +#} (<a href="https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited">uninhabited</a>)
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
Loading…
Add table
Add a link
Reference in a new issue