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>, } #[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!(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!(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()) }) }