about summary refs log tree commit diff
path: root/src/librustdoc/html
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-03-06 05:58:06 +0000
committerGitHub <noreply@github.com>2025-03-06 05:58:06 +0000
commitb178f22bd8267155f2e330731a53ef3e4eac28bb (patch)
treef861f7c201007112dc2f2f016855c7e0529e9cc0 /src/librustdoc/html
parent14cfc3ade4538ecf6f684962521685664348b522 (diff)
parentf80cac723acf10a8f9fd05b335ed5797e4f69a1a (diff)
downloadrust-b178f22bd8267155f2e330731a53ef3e4eac28bb.tar.gz
rust-b178f22bd8267155f2e330731a53ef3e4eac28bb.zip
Merge pull request #4220 from rust-lang/rustup-2025-03-06
Automatic Rustup
Diffstat (limited to 'src/librustdoc/html')
-rw-r--r--src/librustdoc/html/format.rs160
-rw-r--r--src/librustdoc/html/render/context.rs5
-rw-r--r--src/librustdoc/html/render/mod.rs1483
-rw-r--r--src/librustdoc/html/render/print_item.rs3184
-rw-r--r--src/librustdoc/html/render/type_layout.rs6
-rw-r--r--src/librustdoc/html/render/write_shared.rs38
-rw-r--r--src/librustdoc/html/sources.rs2
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts17
-rw-r--r--src/librustdoc/html/static/js/search.js69
9 files changed, 2506 insertions, 2458 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 91b4b3ba1eb..ea740508c58 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -15,7 +15,6 @@ use std::iter::{self, once};
 use itertools::Either;
 use rustc_abi::ExternAbi;
 use rustc_attr_parsing::{ConstStability, StabilityLevel, StableSince};
-use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -30,7 +29,7 @@ use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length};
 use crate::clean::types::ExternalLocation;
 use crate::clean::utils::find_nearest_parent_module;
 use crate::clean::{self, ExternalCrate, PrimitiveType};
-use crate::display::Joined as _;
+use crate::display::{Joined as _, MaybeDisplay as _};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyText};
@@ -41,10 +40,10 @@ pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) {
     s.write_fmt(f).unwrap();
 }
 
-pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
-    bounds: &'a [clean::GenericBound],
-    cx: &'a Context<'tcx>,
-) -> impl Display + 'a + Captures<'tcx> {
+pub(crate) fn print_generic_bounds(
+    bounds: &[clean::GenericBound],
+    cx: &Context<'_>,
+) -> impl Display {
     fmt::from_fn(move |f| {
         let mut bounds_dup = FxHashSet::default();
 
@@ -57,10 +56,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
 }
 
 impl clean::GenericParamDef {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| match &self.kind {
             clean::GenericParamDefKind::Lifetime { outlives } => {
                 write!(f, "{}", self.name)?;
@@ -80,7 +76,7 @@ impl clean::GenericParamDef {
                     print_generic_bounds(bounds, cx).fmt(f)?;
                 }
 
-                if let Some(ref ty) = default {
+                if let Some(ty) = default {
                     f.write_str(" = ")?;
                     ty.print(cx).fmt(f)?;
                 }
@@ -107,10 +103,7 @@ impl clean::GenericParamDef {
 }
 
 impl clean::Generics {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
             if real_params.peek().is_none() {
@@ -134,10 +127,7 @@ pub(crate) enum Ending {
     NoNewline,
 }
 
-fn print_where_predicate<'a, 'tcx: 'a>(
-    predicate: &'a clean::WherePredicate,
-    cx: &'a Context<'tcx>,
-) -> impl Display + 'a + Captures<'tcx> {
+fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) -> impl Display {
     fmt::from_fn(move |f| {
         match predicate {
             clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
@@ -173,17 +163,17 @@ fn print_where_predicate<'a, 'tcx: 'a>(
 /// * The Generics from which to emit a where-clause.
 /// * The number of spaces to indent each line with.
 /// * Whether the where-clause needs to add a comma and newline after the last bound.
-pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
-    gens: &'a clean::Generics,
-    cx: &'a Context<'tcx>,
+pub(crate) fn print_where_clause(
+    gens: &clean::Generics,
+    cx: &Context<'_>,
     indent: usize,
     ending: Ending,
-) -> impl Display + 'a + Captures<'tcx> {
-    fmt::from_fn(move |f| {
-        if gens.where_predicates.is_empty() {
-            return Ok(());
-        }
+) -> Option<impl Display> {
+    if gens.where_predicates.is_empty() {
+        return None;
+    }
 
+    Some(fmt::from_fn(move |f| {
         let where_preds = fmt::from_fn(|f| {
             gens.where_predicates
                 .iter()
@@ -246,17 +236,17 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
             }
         };
         write!(f, "{clause}")
-    })
+    }))
 }
 
 impl clean::Lifetime {
-    pub(crate) fn print(&self) -> impl Display + '_ {
+    pub(crate) fn print(&self) -> impl Display {
         self.0.as_str()
     }
 }
 
 impl clean::ConstantKind {
-    pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ {
+    pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display {
         let expr = self.expr(tcx);
         fmt::from_fn(move |f| {
             if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
@@ -265,7 +255,7 @@ impl clean::ConstantKind {
 }
 
 impl clean::PolyTrait {
-    fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
+    fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?;
             self.trait_.print(cx).fmt(f)
@@ -274,10 +264,7 @@ impl clean::PolyTrait {
 }
 
 impl clean::GenericBound {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
             clean::GenericBound::TraitBound(ty, modifiers) => {
@@ -304,7 +291,7 @@ impl clean::GenericBound {
 }
 
 impl clean::GenericArgs {
-    fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
+    fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             match self {
                 clean::GenericArgs::AngleBracketed { args, constraints } => {
@@ -809,11 +796,11 @@ fn primitive_link_fragment(
     Ok(())
 }
 
-fn tybounds<'a, 'tcx: 'a>(
-    bounds: &'a [clean::PolyTrait],
-    lt: &'a Option<clean::Lifetime>,
-    cx: &'a Context<'tcx>,
-) -> impl Display + 'a + Captures<'tcx> {
+fn tybounds(
+    bounds: &[clean::PolyTrait],
+    lt: &Option<clean::Lifetime>,
+    cx: &Context<'_>,
+) -> impl Display {
     fmt::from_fn(move |f| {
         bounds.iter().map(|bound| bound.print(cx)).joined(" + ", f)?;
         if let Some(lt) = lt {
@@ -825,11 +812,11 @@ fn tybounds<'a, 'tcx: 'a>(
     })
 }
 
-fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
-    params: &'a [clean::GenericParamDef],
-    cx: &'a Context<'tcx>,
+fn print_higher_ranked_params_with_space(
+    params: &[clean::GenericParamDef],
+    cx: &Context<'_>,
     keyword: &'static str,
-) -> impl Display + 'a + Captures<'tcx> {
+) -> impl Display {
     fmt::from_fn(move |f| {
         if !params.is_empty() {
             f.write_str(keyword)?;
@@ -841,11 +828,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
     })
 }
 
-pub(crate) fn anchor<'a: 'cx, 'cx>(
-    did: DefId,
-    text: Symbol,
-    cx: &'cx Context<'a>,
-) -> impl Display + Captures<'a> + 'cx {
+pub(crate) fn anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display {
     fmt::from_fn(move |f| {
         let parts = href(did, cx);
         if let Ok((url, short_ty, fqp)) = parts {
@@ -1121,29 +1104,19 @@ fn fmt_type(
 }
 
 impl clean::Type {
-    pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'b + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| fmt_type(self, f, false, cx))
     }
 }
 
 impl clean::Path {
-    pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'b + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
     }
 }
 
 impl clean::Impl {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        use_absolute: bool,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, use_absolute: bool, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             f.write_str("impl")?;
             self.generics.print(cx).fmt(f)?;
@@ -1179,15 +1152,15 @@ impl clean::Impl {
                 self.print_type(&self.for_, f, use_absolute, cx)?;
             }
 
-            print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f)
+            print_where_clause(&self.generics, cx, 0, Ending::Newline).maybe_display().fmt(f)
         })
     }
-    fn print_type<'a, 'tcx: 'a>(
+    fn print_type(
         &self,
         type_: &clean::Type,
         f: &mut fmt::Formatter<'_>,
         use_absolute: bool,
-        cx: &'a Context<'tcx>,
+        cx: &Context<'_>,
     ) -> Result<(), fmt::Error> {
         if let clean::Type::Tuple(types) = type_
             && let [clean::Type::Generic(name)] = &types[..]
@@ -1258,10 +1231,7 @@ impl clean::Impl {
 }
 
 impl clean::Arguments {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             self.values
                 .iter()
@@ -1301,10 +1271,7 @@ impl Display for Indent {
 }
 
 impl clean::FnDecl {
-    pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'b + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
             if f.alternate() {
@@ -1333,12 +1300,12 @@ impl clean::FnDecl {
     ///   are preserved.
     /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
     ///   necessary.
-    pub(crate) fn full_print<'a, 'tcx: 'a>(
-        &'a self,
+    pub(crate) fn full_print(
+        &self,
         header_len: usize,
         indent: usize,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+        cx: &Context<'_>,
+    ) -> impl Display {
         fmt::from_fn(move |f| {
             // First, generate the text form of the declaration, with no line wrapping, and count the bytes.
             let mut counter = WriteCounter(0);
@@ -1420,10 +1387,7 @@ impl clean::FnDecl {
         self.print_output(cx).fmt(f)
     }
 
-    fn print_output<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    fn print_output(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| match &self.output {
             clean::Tuple(tys) if tys.is_empty() => Ok(()),
             ty if f.alternate() => {
@@ -1434,10 +1398,7 @@ impl clean::FnDecl {
     }
 }
 
-pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
-    item: &clean::Item,
-    cx: &'a Context<'tcx>,
-) -> impl Display + 'a + Captures<'tcx> {
+pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>) -> impl Display {
     use std::fmt::Write as _;
     let vis: Cow<'static, str> = match item.visibility(cx.tcx()) {
         None => "".into(),
@@ -1546,10 +1507,7 @@ pub(crate) fn print_constness_with_space(
 }
 
 impl clean::Import {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| match self.kind {
             clean::ImportKind::Simple(name) => {
                 if name == self.source.path.last() {
@@ -1570,10 +1528,7 @@ impl clean::Import {
 }
 
 impl clean::ImportSource {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| match self.did {
             Some(did) => resolved_path(f, did, &self.path, true, false, cx),
             _ => {
@@ -1593,10 +1548,7 @@ impl clean::ImportSource {
 }
 
 impl clean::AssocItemConstraint {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             f.write_str(self.assoc.name.as_str())?;
             self.assoc.args.print(cx).fmt(f)?;
@@ -1627,15 +1579,12 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
     })
 }
 
-pub(crate) fn print_default_space<'a>(v: bool) -> &'a str {
+pub(crate) fn print_default_space(v: bool) -> &'static str {
     if v { "default " } else { "" }
 }
 
 impl clean::GenericArg {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| match self {
             clean::GenericArg::Lifetime(lt) => lt.print().fmt(f),
             clean::GenericArg::Type(ty) => ty.print(cx).fmt(f),
@@ -1646,10 +1595,7 @@ impl clean::GenericArg {
 }
 
 impl clean::Term {
-    pub(crate) fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl Display + 'a + Captures<'tcx> {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| match self {
             clean::Term::Type(ty) => ty.print(cx).fmt(f),
             clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f),
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 146bdd34069..5f69e79f3ab 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -237,8 +237,7 @@ impl<'tcx> Context<'tcx> {
         };
 
         if !render_redirect_pages {
-            let mut page_buffer = String::new();
-            print_item(self, it, &mut page_buffer);
+            let content = print_item(self, it);
             let page = layout::Page {
                 css_class: tyname_s,
                 root_path: &self.root_path(),
@@ -254,7 +253,7 @@ impl<'tcx> Context<'tcx> {
                 BufDisplay(|buf: &mut String| {
                     print_sidebar(self, it, buf);
                 }),
-                page_buffer,
+                content,
                 &self.shared.style_files,
             )
         } else {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 204631063a2..b2ad2fa773a 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -38,7 +38,7 @@ mod type_layout;
 mod write_shared;
 
 use std::collections::VecDeque;
-use std::fmt::{self, Write};
+use std::fmt::{self, Display as _, Write};
 use std::iter::Peekable;
 use std::path::PathBuf;
 use std::{fs, str};
@@ -47,7 +47,6 @@ use rinja::Template;
 use rustc_attr_parsing::{
     ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince,
 };
-use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::Mutability;
 use rustc_hir::def_id::{DefId, DefIdSet};
@@ -82,7 +81,7 @@ use crate::html::{highlight, sources};
 use crate::scrape_examples::{CallData, CallLocation};
 use crate::{DOC_RUST_LANG_ORG_VERSION, try_none};
 
-pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
+pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) }
     })
@@ -310,7 +309,7 @@ impl ItemEntry {
 }
 
 impl ItemEntry {
-    pub(crate) fn print(&self) -> impl fmt::Display + '_ {
+    pub(crate) fn print(&self) -> impl fmt::Display {
         fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)))
     }
 }
@@ -505,12 +504,12 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
     )
 }
 
-fn document<'a, 'cx: 'a>(
-    cx: &'a Context<'cx>,
-    item: &'a clean::Item,
-    parent: Option<&'a clean::Item>,
+fn document(
+    cx: &Context<'_>,
+    item: &clean::Item,
+    parent: Option<&clean::Item>,
     heading_offset: HeadingOffset,
-) -> impl fmt::Display + 'a + Captures<'cx> {
+) -> impl fmt::Display {
     if let Some(ref name) = item.name {
         info!("Documenting {name}");
     }
@@ -526,12 +525,12 @@ fn document<'a, 'cx: 'a>(
 }
 
 /// Render md_text as markdown.
-fn render_markdown<'a, 'cx: 'a>(
-    cx: &'a Context<'cx>,
-    md_text: &'a str,
+fn render_markdown(
+    cx: &Context<'_>,
+    md_text: &str,
     links: Vec<RenderedLink>,
     heading_offset: HeadingOffset,
-) -> impl fmt::Display + 'a + Captures<'cx> {
+) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         write!(
             f,
@@ -552,13 +551,13 @@ fn render_markdown<'a, 'cx: 'a>(
 
 /// Writes a documentation block containing only the first paragraph of the documentation. If the
 /// docs are longer, a "Read more" link is appended to the end.
-fn document_short<'a, 'cx: 'a>(
-    item: &'a clean::Item,
-    cx: &'a Context<'cx>,
-    link: AssocItemLink<'a>,
-    parent: &'a clean::Item,
+fn document_short(
+    item: &clean::Item,
+    cx: &Context<'_>,
+    link: AssocItemLink<'_>,
+    parent: &clean::Item,
     show_def_docs: bool,
-) -> impl fmt::Display + 'a + Captures<'cx> {
+) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         document_item_info(cx, item, Some(parent)).render_into(f).unwrap();
         if !show_def_docs {
@@ -595,28 +594,28 @@ fn document_short<'a, 'cx: 'a>(
     })
 }
 
-fn document_full_collapsible<'a, 'cx: 'a>(
-    item: &'a clean::Item,
-    cx: &'a Context<'cx>,
+fn document_full_collapsible(
+    item: &clean::Item,
+    cx: &Context<'_>,
     heading_offset: HeadingOffset,
-) -> impl fmt::Display + 'a + Captures<'cx> {
+) -> impl fmt::Display {
     document_full_inner(item, cx, true, heading_offset)
 }
 
-fn document_full<'a, 'cx: 'a>(
-    item: &'a clean::Item,
-    cx: &'a Context<'cx>,
+fn document_full(
+    item: &clean::Item,
+    cx: &Context<'_>,
     heading_offset: HeadingOffset,
-) -> impl fmt::Display + 'a + Captures<'cx> {
+) -> impl fmt::Display {
     document_full_inner(item, cx, false, heading_offset)
 }
 
-fn document_full_inner<'a, 'cx: 'a>(
-    item: &'a clean::Item,
-    cx: &'a Context<'cx>,
+fn document_full_inner(
+    item: &clean::Item,
+    cx: &Context<'_>,
     is_collapsible: bool,
     heading_offset: HeadingOffset,
-) -> impl fmt::Display + 'a + Captures<'cx> {
+) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         if let Some(s) = item.opt_doc_value() {
             debug!("Doc block: =====\n{s}\n=====");
@@ -774,9 +773,7 @@ pub(crate) fn render_impls(
             let did = i.trait_did().unwrap();
             let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx());
             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
-            let mut buffer = String::new();
-            render_impl(
-                &mut buffer,
+            let imp = render_impl(
                 cx,
                 i,
                 containing_item,
@@ -791,7 +788,7 @@ pub(crate) fn render_impls(
                     toggle_open_by_default,
                 },
             );
-            buffer
+            imp.to_string()
         })
         .collect::<Vec<_>>();
     rendered_impls.sort();
@@ -799,11 +796,11 @@ pub(crate) fn render_impls(
 }
 
 /// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
-fn assoc_href_attr<'a, 'tcx>(
+fn assoc_href_attr(
     it: &clean::Item,
-    link: AssocItemLink<'a>,
-    cx: &Context<'tcx>,
-) -> Option<impl fmt::Display + 'a + Captures<'tcx>> {
+    link: AssocItemLink<'_>,
+    cx: &Context<'_>,
+) -> Option<impl fmt::Display> {
     let name = it.name.unwrap();
     let item_type = it.type_();
 
@@ -814,7 +811,7 @@ fn assoc_href_attr<'a, 'tcx>(
     }
 
     let href = match link {
-        AssocItemLink::Anchor(Some(ref id)) => Href::AnchorId(id),
+        AssocItemLink::Anchor(Some(id)) => Href::AnchorId(id),
         AssocItemLink::Anchor(None) => Href::Anchor(item_type),
         AssocItemLink::GotoSource(did, provided_methods) => {
             // We're creating a link from the implementation of an associated item to its
@@ -880,7 +877,6 @@ enum AssocConstValue<'a> {
 }
 
 fn assoc_const(
-    w: &mut String,
     it: &clean::Item,
     generics: &clean::Generics,
     ty: &clean::Type,
@@ -888,11 +884,11 @@ fn assoc_const(
     link: AssocItemLink<'_>,
     indent: usize,
     cx: &Context<'_>,
-) {
+) -> impl fmt::Display {
     let tcx = cx.tcx();
-    write_str(
-        w,
-        format_args!(
+    fmt::from_fn(move |w| {
+        write!(
+            w,
             "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
             indent = " ".repeat(indent),
             vis = visibility_print_with_space(it, cx),
@@ -900,28 +896,27 @@ fn assoc_const(
             name = it.name.as_ref().unwrap(),
             generics = generics.print(cx),
             ty = ty.print(cx),
-        ),
-    );
-    if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
-        // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
-        //        hood which adds noisy underscores and a type suffix to number literals.
-        //        This hurts readability in this context especially when more complex expressions
-        //        are involved and it doesn't add much of value.
-        //        Find a way to print constants here without all that jazz.
-        let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx));
-        if match value {
-            AssocConstValue::TraitDefault(_) => true, // always show
-            AssocConstValue::Impl(_) => repr != "_",  // show if there is a meaningful value to show
-            AssocConstValue::None => unreachable!(),
-        } {
-            write_str(w, format_args!(" = {}", Escape(&repr)));
+        )?;
+        if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
+            // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
+            //        hood which adds noisy underscores and a type suffix to number literals.
+            //        This hurts readability in this context especially when more complex expressions
+            //        are involved and it doesn't add much of value.
+            //        Find a way to print constants here without all that jazz.
+            let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx));
+            if match value {
+                AssocConstValue::TraitDefault(_) => true, // always show
+                AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show
+                AssocConstValue::None => unreachable!(),
+            } {
+                write!(w, " = {}", Escape(&repr))?;
+            }
         }
-    }
-    write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline)));
+        write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display())
+    })
 }
 
 fn assoc_type(
-    w: &mut String,
     it: &clean::Item,
     generics: &clean::Generics,
     bounds: &[clean::GenericBound],
@@ -929,30 +924,29 @@ fn assoc_type(
     link: AssocItemLink<'_>,
     indent: usize,
     cx: &Context<'_>,
-) {
-    write_str(
-        w,
-        format_args!(
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        write!(
+            w,
             "{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
             indent = " ".repeat(indent),
             vis = visibility_print_with_space(it, cx),
             href = assoc_href_attr(it, link, cx).maybe_display(),
             name = it.name.as_ref().unwrap(),
             generics = generics.print(cx),
-        ),
-    );
-    if !bounds.is_empty() {
-        write_str(w, format_args!(": {}", print_generic_bounds(bounds, cx)));
-    }
-    // Render the default before the where-clause which aligns with the new recommended style. See #89122.
-    if let Some(default) = default {
-        write_str(w, format_args!(" = {}", default.print(cx)));
-    }
-    write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline)));
+        )?;
+        if !bounds.is_empty() {
+            write!(w, ": {}", print_generic_bounds(bounds, cx))?;
+        }
+        // Render the default before the where-clause which aligns with the new recommended style. See #89122.
+        if let Some(default) = default {
+            write!(w, " = {}", default.print(cx))?;
+        }
+        write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display())
+    })
 }
 
 fn assoc_method(
-    w: &mut String,
     meth: &clean::Item,
     g: &clean::Generics,
     d: &clean::FnDecl,
@@ -960,7 +954,7 @@ fn assoc_method(
     parent: ItemType,
     cx: &Context<'_>,
     render_mode: RenderMode,
-) {
+) -> impl fmt::Display {
     let tcx = cx.tcx();
     let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
     let name = meth.name.as_ref().unwrap();
@@ -976,61 +970,53 @@ fn assoc_method(
         ),
         RenderMode::ForDeref { .. } => "",
     };
-    let asyncness = header.asyncness.print_with_space();
-    let safety = header.safety.print_with_space();
-    let abi = print_abi_with_space(header.abi).to_string();
-    let href = assoc_href_attr(meth, link, cx).maybe_display();
-
-    // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
-    let generics_len = format!("{:#}", g.print(cx)).len();
-    let mut header_len = "fn ".len()
-        + vis.len()
-        + defaultness.len()
-        + constness.len()
-        + asyncness.len()
-        + safety.len()
-        + abi.len()
-        + name.as_str().len()
-        + generics_len;
-
-    let notable_traits = notable_traits_button(&d.output, cx).maybe_display();
-
-    let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
-        header_len += 4;
-        let indent_str = "    ";
-        write_str(w, format_args!("{}", render_attributes_in_pre(meth, indent_str, cx)));
-        (4, indent_str, Ending::NoNewline)
-    } else {
-        render_attributes_in_code(w, meth, cx);
-        (0, "", Ending::Newline)
-    };
-    w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
-    write_str(
-        w,
-        format_args!(
+
+    fmt::from_fn(move |w| {
+        let asyncness = header.asyncness.print_with_space();
+        let safety = header.safety.print_with_space();
+        let abi = print_abi_with_space(header.abi).to_string();
+        let href = assoc_href_attr(meth, link, cx).maybe_display();
+
+        // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
+        let generics_len = format!("{:#}", g.print(cx)).len();
+        let mut header_len = "fn ".len()
+            + vis.len()
+            + defaultness.len()
+            + constness.len()
+            + asyncness.len()
+            + safety.len()
+            + abi.len()
+            + name.as_str().len()
+            + generics_len;
+
+        let notable_traits = notable_traits_button(&d.output, cx).maybe_display();
+
+        let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
+            header_len += 4;
+            let indent_str = "    ";
+            write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx))?;
+            (4, indent_str, Ending::NoNewline)
+        } else {
+            render_attributes_in_code(w, meth, cx);
+            (0, "", Ending::Newline)
+        };
+        write!(
+            w,
             "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
-         <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
+            <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
             indent = indent_str,
-            vis = vis,
-            defaultness = defaultness,
-            constness = constness,
-            asyncness = asyncness,
-            safety = safety,
-            abi = abi,
-            href = href,
-            name = name,
             generics = g.print(cx),
             decl = d.full_print(header_len, indent, cx),
-            where_clause = print_where_clause(g, cx, indent, end_newline),
-        ),
-    );
+            where_clause = print_where_clause(g, cx, indent, end_newline).maybe_display(),
+        )
+    })
 }
 
 /// Writes a span containing the versions at which an item became stable and/or const-stable. For
 /// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
 /// write a span containing "1.0.0 (const: 1.45.0)".
 ///
-/// Returns `true` if a stability annotation was rendered.
+/// Returns `None` if there is no stability annotation to be rendered.
 ///
 /// Stability and const-stability are considered separately. If the item is unstable, no version
 /// will be written. If the item is const-unstable, "const: unstable" will be appended to the
@@ -1041,11 +1027,10 @@ fn assoc_method(
 /// will include the const-stable version, but no stable version will be emitted, as a natural
 /// consequence of the above rules.
 fn render_stability_since_raw_with_extra(
-    w: &mut String,
     stable_version: Option<StableSince>,
     const_stability: Option<ConstStability>,
     extra_class: &str,
-) -> bool {
+) -> Option<impl fmt::Display> {
     let mut title = String::new();
     let mut stability = String::new();
 
@@ -1095,14 +1080,9 @@ fn render_stability_since_raw_with_extra(
         }
     }
 
-    if !stability.is_empty() {
-        write_str(
-            w,
-            format_args!(r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#),
-        );
-    }
-
-    !stability.is_empty()
+    (!stability.is_empty()).then_some(fmt::from_fn(move |w| {
+        write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#)
+    }))
 }
 
 fn since_to_string(since: &StableSince) -> Option<String> {
@@ -1115,31 +1095,25 @@ fn since_to_string(since: &StableSince) -> Option<String> {
 
 #[inline]
 fn render_stability_since_raw(
-    w: &mut String,
     ver: Option<StableSince>,
     const_stability: Option<ConstStability>,
-) -> bool {
-    render_stability_since_raw_with_extra(w, ver, const_stability, "")
+) -> Option<impl fmt::Display> {
+    render_stability_since_raw_with_extra(ver, const_stability, "")
 }
 
 fn render_assoc_item(
-    w: &mut String,
     item: &clean::Item,
     link: AssocItemLink<'_>,
     parent: ItemType,
     cx: &Context<'_>,
     render_mode: RenderMode,
-) {
-    match &item.kind {
-        clean::StrippedItem(..) => {}
-        clean::RequiredMethodItem(m) => {
-            assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
-        }
-        clean::MethodItem(m, _) => {
-            assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
+) -> impl fmt::Display {
+    fmt::from_fn(move |f| match &item.kind {
+        clean::StrippedItem(..) => Ok(()),
+        clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => {
+            assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
         }
         clean::RequiredAssocConstItem(generics, ty) => assoc_const(
-            w,
             item,
             generics,
             ty,
@@ -1147,9 +1121,9 @@ fn render_assoc_item(
             link,
             if parent == ItemType::Trait { 4 } else { 0 },
             cx,
-        ),
+        )
+        .fmt(f),
         clean::ProvidedAssocConstItem(ci) => assoc_const(
-            w,
             item,
             &ci.generics,
             &ci.type_,
@@ -1157,9 +1131,9 @@ fn render_assoc_item(
             link,
             if parent == ItemType::Trait { 4 } else { 0 },
             cx,
-        ),
+        )
+        .fmt(f),
         clean::ImplAssocConstItem(ci) => assoc_const(
-            w,
             item,
             &ci.generics,
             &ci.type_,
@@ -1167,9 +1141,9 @@ fn render_assoc_item(
             link,
             if parent == ItemType::Trait { 4 } else { 0 },
             cx,
-        ),
-        clean::RequiredAssocTypeItem(ref generics, ref bounds) => assoc_type(
-            w,
+        )
+        .fmt(f),
+        clean::RequiredAssocTypeItem(generics, bounds) => assoc_type(
             item,
             generics,
             bounds,
@@ -1177,9 +1151,9 @@ fn render_assoc_item(
             link,
             if parent == ItemType::Trait { 4 } else { 0 },
             cx,
-        ),
-        clean::AssocTypeItem(ref ty, ref bounds) => assoc_type(
-            w,
+        )
+        .fmt(f),
+        clean::AssocTypeItem(ty, bounds) => assoc_type(
             item,
             &ty.generics,
             bounds,
@@ -1187,18 +1161,15 @@ fn render_assoc_item(
             link,
             if parent == ItemType::Trait { 4 } else { 0 },
             cx,
-        ),
+        )
+        .fmt(f),
         _ => panic!("render_assoc_item called on non-associated-item"),
-    }
+    })
 }
 
 // When an attribute is rendered inside a `<pre>` tag, it is formatted using
 // a whitespace prefix and newline.
-fn render_attributes_in_pre<'a, 'tcx: 'a>(
-    it: &'a clean::Item,
-    prefix: &'a str,
-    cx: &'a Context<'tcx>,
-) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
+fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         for a in it.attributes(cx.tcx(), cx.cache(), false) {
             writeln!(f, "{prefix}{a}")?;
@@ -1231,28 +1202,28 @@ impl<'a> AssocItemLink<'a> {
 }
 
 pub fn write_section_heading(
-    w: &mut impl fmt::Write,
     title: &str,
     id: &str,
     extra_class: Option<&str>,
     extra: impl fmt::Display,
-) {
-    let (extra_class, whitespace) = match extra_class {
-        Some(extra) => (extra, " "),
-        None => ("", ""),
-    };
-    write!(
-        w,
-        "<h2 id=\"{id}\" class=\"{extra_class}{whitespace}section-header\">\
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        let (extra_class, whitespace) = match extra_class {
+            Some(extra) => (extra, " "),
+            None => ("", ""),
+        };
+        write!(
+            w,
+            "<h2 id=\"{id}\" class=\"{extra_class}{whitespace}section-header\">\
             {title}\
             <a href=\"#{id}\" class=\"anchor\">ยง</a>\
          </h2>{extra}",
-    )
-    .unwrap();
+        )
+    })
 }
 
-fn write_impl_section_heading(w: &mut impl fmt::Write, title: &str, id: &str) {
-    write_section_heading(w, title, id, None, "")
+fn write_impl_section_heading(title: &str, id: &str) -> impl fmt::Display {
+    write_section_heading(title, id, None, "")
 }
 
 pub(crate) fn render_all_impls(
@@ -1269,35 +1240,43 @@ pub(crate) fn render_all_impls(
         buf
     };
     if !impls.is_empty() {
-        write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations");
-        write!(w, "<div id=\"trait-implementations-list\">{impls}</div>").unwrap();
+        write!(
+            w,
+            "{}<div id=\"trait-implementations-list\">{impls}</div>",
+            write_impl_section_heading("Trait Implementations", "trait-implementations")
+        )
+        .unwrap();
     }
 
     if !synthetic.is_empty() {
-        write_impl_section_heading(
-            &mut w,
-            "Auto Trait Implementations",
-            "synthetic-implementations",
-        );
-        w.write_str("<div id=\"synthetic-implementations-list\">").unwrap();
+        write!(
+            w,
+            "{}<div id=\"synthetic-implementations-list\">",
+            write_impl_section_heading("Auto Trait Implementations", "synthetic-implementations",)
+        )
+        .unwrap();
         render_impls(cx, &mut w, synthetic, containing_item, false);
         w.write_str("</div>").unwrap();
     }
 
     if !blanket_impl.is_empty() {
-        write_impl_section_heading(&mut w, "Blanket Implementations", "blanket-implementations");
-        w.write_str("<div id=\"blanket-implementations-list\">").unwrap();
+        write!(
+            w,
+            "{}<div id=\"blanket-implementations-list\">",
+            write_impl_section_heading("Blanket Implementations", "blanket-implementations")
+        )
+        .unwrap();
         render_impls(cx, &mut w, blanket_impl, containing_item, false);
         w.write_str("</div>").unwrap();
     }
 }
 
-fn render_assoc_items<'a, 'cx: 'a>(
-    cx: &'a Context<'cx>,
-    containing_item: &'a clean::Item,
+fn render_assoc_items(
+    cx: &Context<'_>,
+    containing_item: &clean::Item,
     it: DefId,
-    what: AssocItemRender<'a>,
-) -> impl fmt::Display + 'a + Captures<'cx> {
+    what: AssocItemRender<'_>,
+) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         let mut derefs = DefIdSet::default();
         derefs.insert(it);
@@ -1323,25 +1302,34 @@ fn render_assoc_items_inner(
         let mut tmp_buf = String::new();
         let (render_mode, id, class_html) = match what {
             AssocItemRender::All => {
-                write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
+                write_str(
+                    &mut tmp_buf,
+                    format_args!(
+                        "{}",
+                        write_impl_section_heading("Implementations", "implementations")
+                    ),
+                );
                 (RenderMode::Normal, "implementations-list".to_owned(), "")
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                 let id =
                     cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
                 let derived_id = cx.derive_id(&id);
-                tmp_buf.push_str("<details class=\"toggle big-toggle\" open><summary>");
                 close_tags.push("</details>");
-                write_impl_section_heading(
+                write_str(
                     &mut tmp_buf,
-                    &format!(
-                        "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
-                        trait_ = trait_.print(cx),
-                        type_ = type_.print(cx),
+                    format_args!(
+                        "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
+                        write_impl_section_heading(
+                            &format!(
+                                "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
+                                trait_ = trait_.print(cx),
+                                type_ = type_.print(cx),
+                            ),
+                            &id,
+                        )
                     ),
-                    &id,
                 );
-                tmp_buf.push_str("</summary>");
                 if let Some(def_id) = type_.def_id(cx.cache()) {
                     cx.deref_id_map.borrow_mut().insert(def_id, id);
                 }
@@ -1350,21 +1338,26 @@ fn render_assoc_items_inner(
         };
         let mut impls_buf = String::new();
         for i in &non_trait {
-            render_impl(
+            write_str(
                 &mut impls_buf,
-                cx,
-                i,
-                containing_item,
-                AssocItemLink::Anchor(None),
-                render_mode,
-                None,
-                &[],
-                ImplRenderingParameters {
-                    show_def_docs: true,
-                    show_default_items: true,
-                    show_non_assoc_items: true,
-                    toggle_open_by_default: true,
-                },
+                format_args!(
+                    "{}",
+                    render_impl(
+                        cx,
+                        i,
+                        containing_item,
+                        AssocItemLink::Anchor(None),
+                        render_mode,
+                        None,
+                        &[],
+                        ImplRenderingParameters {
+                            show_def_docs: true,
+                            show_default_items: true,
+                            show_non_assoc_items: true,
+                            toggle_open_by_default: true,
+                        },
+                    )
+                ),
             );
         }
         if !impls_buf.is_empty() {
@@ -1468,10 +1461,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
     }
 }
 
-pub(crate) fn notable_traits_button<'a, 'tcx>(
-    ty: &'a clean::Type,
-    cx: &'a Context<'tcx>,
-) -> Option<impl fmt::Display + 'a + Captures<'tcx>> {
+pub(crate) fn notable_traits_button(
+    ty: &clean::Type,
+    cx: &Context<'_>,
+) -> Option<impl fmt::Display> {
     let mut has_notable_trait = false;
 
     if ty.is_unit() {
@@ -1564,20 +1557,23 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
                 );
                 for it in &impl_.items {
                     if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
-                        out.push_str("<div class=\"where\">    ");
                         let empty_set = FxIndexSet::default();
                         let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
-                        assoc_type(
+                        write_str(
                             &mut out,
-                            it,
-                            &tydef.generics,
-                            &[], // intentionally leaving out bounds
-                            Some(&tydef.type_),
-                            src_link,
-                            0,
-                            cx,
+                            format_args!(
+                                "<div class=\"where\">    {};</div>",
+                                assoc_type(
+                                    it,
+                                    &tydef.generics,
+                                    &[], // intentionally leaving out bounds
+                                    Some(&tydef.type_),
+                                    src_link,
+                                    0,
+                                    cx,
+                                )
+                            ),
                         );
-                        out.push_str(";</div>");
                     }
                 }
             }
@@ -1623,7 +1619,6 @@ struct ImplRenderingParameters {
 }
 
 fn render_impl(
-    w: &mut String,
     cx: &Context<'_>,
     i: &Impl,
     parent: &clean::Item,
@@ -1632,513 +1627,549 @@ fn render_impl(
     use_absolute: Option<bool>,
     aliases: &[String],
     rendering_params: ImplRenderingParameters,
-) {
-    let cache = &cx.shared.cache;
-    let traits = &cache.traits;
-    let trait_ = i.trait_did().map(|did| &traits[&did]);
-    let mut close_tags = <Vec<&str>>::with_capacity(2);
-
-    // For trait implementations, the `interesting` output contains all methods that have doc
-    // comments, and the `boring` output contains all methods that do not. The distinction is
-    // used to allow hiding the boring methods.
-    // `containing_item` is used for rendering stability info. If the parent is a trait impl,
-    // `containing_item` will the grandparent, since trait impls can't have stability attached.
-    fn doc_impl_item(
-        boring: &mut String,
-        interesting: &mut String,
-        cx: &Context<'_>,
-        item: &clean::Item,
-        parent: &clean::Item,
-        link: AssocItemLink<'_>,
-        render_mode: RenderMode,
-        is_default_item: bool,
-        trait_: Option<&clean::Trait>,
-        rendering_params: ImplRenderingParameters,
-    ) {
-        let item_type = item.type_();
-        let name = item.name.as_ref().unwrap();
-
-        let render_method_item = rendering_params.show_non_assoc_items
-            && match render_mode {
-                RenderMode::Normal => true,
-                RenderMode::ForDeref { mut_: deref_mut_ } => {
-                    should_render_item(item, deref_mut_, cx.tcx())
-                }
-            };
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        let cache = &cx.shared.cache;
+        let traits = &cache.traits;
+        let trait_ = i.trait_did().map(|did| &traits[&did]);
+        let mut close_tags = <Vec<&str>>::with_capacity(2);
+
+        // For trait implementations, the `interesting` output contains all methods that have doc
+        // comments, and the `boring` output contains all methods that do not. The distinction is
+        // used to allow hiding the boring methods.
+        // `containing_item` is used for rendering stability info. If the parent is a trait impl,
+        // `containing_item` will the grandparent, since trait impls can't have stability attached.
+        fn doc_impl_item(
+            boring: &mut String,
+            interesting: &mut String,
+            cx: &Context<'_>,
+            item: &clean::Item,
+            parent: &clean::Item,
+            link: AssocItemLink<'_>,
+            render_mode: RenderMode,
+            is_default_item: bool,
+            trait_: Option<&clean::Trait>,
+            rendering_params: ImplRenderingParameters,
+        ) {
+            let item_type = item.type_();
+            let name = item.name.as_ref().unwrap();
+
+            let render_method_item = rendering_params.show_non_assoc_items
+                && match render_mode {
+                    RenderMode::Normal => true,
+                    RenderMode::ForDeref { mut_: deref_mut_ } => {
+                        should_render_item(item, deref_mut_, cx.tcx())
+                    }
+                };
 
-        let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
-
-        let mut doc_buffer = String::new();
-        let mut info_buffer = String::new();
-        let mut short_documented = true;
-
-        if render_method_item {
-            if !is_default_item {
-                if let Some(t) = trait_ {
-                    // The trait item may have been stripped so we might not
-                    // find any documentation or stability for it.
-                    if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
-                        // We need the stability of the item from the trait
-                        // because impls can't have a stability.
-                        if !item.doc_value().is_empty() {
-                            document_item_info(cx, it, Some(parent))
-                                .render_into(&mut info_buffer)
-                                .unwrap();
+            let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
+
+            let mut doc_buffer = String::new();
+            let mut info_buffer = String::new();
+            let mut short_documented = true;
+
+            if render_method_item {
+                if !is_default_item {
+                    if let Some(t) = trait_ {
+                        // The trait item may have been stripped so we might not
+                        // find any documentation or stability for it.
+                        if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
+                            // We need the stability of the item from the trait
+                            // because impls can't have a stability.
+                            if !item.doc_value().is_empty() {
+                                document_item_info(cx, it, Some(parent))
+                                    .render_into(&mut info_buffer)
+                                    .unwrap();
+                                write_str(
+                                    &mut doc_buffer,
+                                    format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
+                                );
+                                short_documented = false;
+                            } else {
+                                // In case the item isn't documented,
+                                // provide short documentation from the trait.
+                                write_str(
+                                    &mut doc_buffer,
+                                    format_args!(
+                                        "{}",
+                                        document_short(
+                                            it,
+                                            cx,
+                                            link,
+                                            parent,
+                                            rendering_params.show_def_docs,
+                                        )
+                                    ),
+                                );
+                            }
+                        }
+                    } else {
+                        document_item_info(cx, item, Some(parent))
+                            .render_into(&mut info_buffer)
+                            .unwrap();
+                        if rendering_params.show_def_docs {
                             write_str(
                                 &mut doc_buffer,
                                 format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
                             );
                             short_documented = false;
-                        } else {
-                            // In case the item isn't documented,
-                            // provide short documentation from the trait.
-                            write_str(
-                                &mut doc_buffer,
-                                format_args!(
-                                    "{}",
-                                    document_short(
-                                        it,
-                                        cx,
-                                        link,
-                                        parent,
-                                        rendering_params.show_def_docs,
-                                    )
-                                ),
-                            );
                         }
                     }
                 } else {
-                    document_item_info(cx, item, Some(parent))
-                        .render_into(&mut info_buffer)
-                        .unwrap();
-                    if rendering_params.show_def_docs {
-                        write_str(
-                            &mut doc_buffer,
-                            format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
-                        );
-                        short_documented = false;
-                    }
+                    write_str(
+                        &mut doc_buffer,
+                        format_args!(
+                            "{}",
+                            document_short(item, cx, link, parent, rendering_params.show_def_docs)
+                        ),
+                    );
                 }
-            } else {
+            }
+            let w = if short_documented && trait_.is_some() { interesting } else { boring };
+
+            let toggled = !doc_buffer.is_empty();
+            if toggled {
+                let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
                 write_str(
-                    &mut doc_buffer,
-                    format_args!(
-                        "{}",
-                        document_short(item, cx, link, parent, rendering_params.show_def_docs)
-                    ),
+                    w,
+                    format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
                 );
             }
-        }
-        let w = if short_documented && trait_.is_some() { interesting } else { boring };
-
-        let toggled = !doc_buffer.is_empty();
-        if toggled {
-            let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write_str(
-                w,
-                format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
-            );
-        }
-        match &item.kind {
-            clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
-                // Only render when the method is not static or we allow static methods
-                if render_method_item {
-                    let id = cx.derive_id(format!("{item_type}.{name}"));
-                    let source_id = trait_
-                        .and_then(|trait_| {
-                            trait_
-                                .items
-                                .iter()
-                                .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
-                        })
-                        .map(|item| format!("{}.{name}", item.type_()));
+            match &item.kind {
+                clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
+                    // Only render when the method is not static or we allow static methods
+                    if render_method_item {
+                        let id = cx.derive_id(format!("{item_type}.{name}"));
+                        let source_id = trait_
+                            .and_then(|trait_| {
+                                trait_
+                                    .items
+                                    .iter()
+                                    .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
+                            })
+                            .map(|item| format!("{}.{name}", item.type_()));
+                        write_str(
+                            w,
+                            format_args!(
+                                "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                                {}",
+                                render_rightside(cx, item, render_mode)
+                            ),
+                        );
+                        if trait_.is_some() {
+                            // Anchors are only used on trait impls.
+                            write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
+                        }
+                        write_str(
+                            w,
+                            format_args!(
+                                "<h4 class=\"code-header\">{}</h4></section>",
+                                render_assoc_item(
+                                    item,
+                                    link.anchor(source_id.as_ref().unwrap_or(&id)),
+                                    ItemType::Impl,
+                                    cx,
+                                    render_mode,
+                                ),
+                            ),
+                        );
+                    }
+                }
+                clean::RequiredAssocConstItem(generics, ty) => {
+                    let source_id = format!("{item_type}.{name}");
+                    let id = cx.derive_id(&source_id);
                     write_str(
                         w,
-                        format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
+                        format_args!(
+                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                            {}",
+                            render_rightside(cx, item, render_mode)
+                        ),
                     );
-                    render_rightside(w, cx, item, render_mode);
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
                         write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
                     }
-                    w.push_str("<h4 class=\"code-header\">");
-                    render_assoc_item(
+                    write_str(
                         w,
-                        item,
-                        link.anchor(source_id.as_ref().unwrap_or(&id)),
-                        ItemType::Impl,
-                        cx,
-                        render_mode,
+                        format_args!(
+                            "<h4 class=\"code-header\">{}</h4></section>",
+                            assoc_const(
+                                item,
+                                generics,
+                                ty,
+                                AssocConstValue::None,
+                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                                0,
+                                cx,
+                            )
+                        ),
                     );
-                    w.push_str("</h4></section>");
                 }
-            }
-            clean::RequiredAssocConstItem(ref generics, ref ty) => {
-                let source_id = format!("{item_type}.{name}");
-                let id = cx.derive_id(&source_id);
-                write_str(
-                    w,
-                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
-                );
-                render_rightside(w, cx, item, render_mode);
-                if trait_.is_some() {
-                    // Anchors are only used on trait impls.
-                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
+                clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
+                    let source_id = format!("{item_type}.{name}");
+                    let id = cx.derive_id(&source_id);
+                    write_str(
+                        w,
+                        format_args!(
+                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                            {}",
+                            render_rightside(cx, item, render_mode)
+                        ),
+                    );
+                    if trait_.is_some() {
+                        // Anchors are only used on trait impls.
+                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
+                    }
+                    write_str(
+                        w,
+                        format_args!(
+                            "<h4 class=\"code-header\">{}</h4></section>",
+                            assoc_const(
+                                item,
+                                &ci.generics,
+                                &ci.type_,
+                                match item.kind {
+                                    clean::ProvidedAssocConstItem(_) =>
+                                        AssocConstValue::TraitDefault(&ci.kind),
+                                    clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
+                                    _ => unreachable!(),
+                                },
+                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                                0,
+                                cx,
+                            )
+                        ),
+                    );
                 }
-                w.push_str("<h4 class=\"code-header\">");
-                assoc_const(
-                    w,
-                    item,
-                    generics,
-                    ty,
-                    AssocConstValue::None,
-                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                    0,
-                    cx,
-                );
-                w.push_str("</h4></section>");
-            }
-            clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
-                let source_id = format!("{item_type}.{name}");
-                let id = cx.derive_id(&source_id);
-                write_str(
-                    w,
-                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
-                );
-                render_rightside(w, cx, item, render_mode);
-                if trait_.is_some() {
-                    // Anchors are only used on trait impls.
-                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
+                clean::RequiredAssocTypeItem(generics, bounds) => {
+                    let source_id = format!("{item_type}.{name}");
+                    let id = cx.derive_id(&source_id);
+                    write_str(
+                        w,
+                        format_args!(
+                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                            {}",
+                            render_rightside(cx, item, render_mode)
+                        ),
+                    );
+                    if trait_.is_some() {
+                        // Anchors are only used on trait impls.
+                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
+                    }
+                    write_str(
+                        w,
+                        format_args!(
+                            "<h4 class=\"code-header\">{}</h4></section>",
+                            assoc_type(
+                                item,
+                                generics,
+                                bounds,
+                                None,
+                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                                0,
+                                cx,
+                            )
+                        ),
+                    );
                 }
-                w.push_str("<h4 class=\"code-header\">");
-                assoc_const(
-                    w,
-                    item,
-                    &ci.generics,
-                    &ci.type_,
-                    match item.kind {
-                        clean::ProvidedAssocConstItem(_) => AssocConstValue::TraitDefault(&ci.kind),
-                        clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
-                        _ => unreachable!(),
-                    },
-                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                    0,
-                    cx,
-                );
-                w.push_str("</h4></section>");
+                clean::AssocTypeItem(tydef, _bounds) => {
+                    let source_id = format!("{item_type}.{name}");
+                    let id = cx.derive_id(&source_id);
+                    write_str(
+                        w,
+                        format_args!(
+                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+                            {}",
+                            render_rightside(cx, item, render_mode)
+                        ),
+                    );
+                    if trait_.is_some() {
+                        // Anchors are only used on trait impls.
+                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
+                    }
+                    write_str(
+                        w,
+                        format_args!(
+                            "<h4 class=\"code-header\">{}</h4></section>",
+                            assoc_type(
+                                item,
+                                &tydef.generics,
+                                &[], // intentionally leaving out bounds
+                                Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
+                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                                0,
+                                cx,
+                            )
+                        ),
+                    );
+                }
+                clean::StrippedItem(..) => return,
+                _ => panic!("can't make docs for trait item with name {:?}", item.name),
             }
-            clean::RequiredAssocTypeItem(ref generics, ref bounds) => {
-                let source_id = format!("{item_type}.{name}");
-                let id = cx.derive_id(&source_id);
-                write_str(
-                    w,
-                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
-                );
-                render_rightside(w, cx, item, render_mode);
-                if trait_.is_some() {
-                    // Anchors are only used on trait impls.
-                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
+
+            w.push_str(&info_buffer);
+            if toggled {
+                w.push_str("</summary>");
+                w.push_str(&doc_buffer);
+                w.push_str("</details>");
+            }
+        }
+
+        let mut impl_items = String::new();
+        let mut default_impl_items = String::new();
+        let impl_ = i.inner_impl();
+
+        // Impl items are grouped by kinds:
+        //
+        // 1. Constants
+        // 2. Types
+        // 3. Functions
+        //
+        // This order is because you can have associated constants used in associated types (like array
+        // length), and both in associcated functions. So with this order, when reading from top to
+        // bottom, you should see items definitions before they're actually used most of the time.
+        let mut assoc_types = Vec::new();
+        let mut methods = Vec::new();
+
+        if !impl_.is_negative_trait_impl() {
+            for trait_item in &impl_.items {
+                match trait_item.kind {
+                    clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
+                        methods.push(trait_item)
+                    }
+                    clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
+                        assoc_types.push(trait_item)
+                    }
+                    clean::RequiredAssocConstItem(..)
+                    | clean::ProvidedAssocConstItem(_)
+                    | clean::ImplAssocConstItem(_) => {
+                        // We render it directly since they're supposed to come first.
+                        doc_impl_item(
+                            &mut default_impl_items,
+                            &mut impl_items,
+                            cx,
+                            trait_item,
+                            if trait_.is_some() { &i.impl_item } else { parent },
+                            link,
+                            render_mode,
+                            false,
+                            trait_,
+                            rendering_params,
+                        );
+                    }
+                    _ => {}
                 }
-                w.push_str("<h4 class=\"code-header\">");
-                assoc_type(
-                    w,
-                    item,
-                    generics,
-                    bounds,
-                    None,
-                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                    0,
+            }
+
+            for assoc_type in assoc_types {
+                doc_impl_item(
+                    &mut default_impl_items,
+                    &mut impl_items,
                     cx,
+                    assoc_type,
+                    if trait_.is_some() { &i.impl_item } else { parent },
+                    link,
+                    render_mode,
+                    false,
+                    trait_,
+                    rendering_params,
                 );
-                w.push_str("</h4></section>");
             }
-            clean::AssocTypeItem(tydef, _bounds) => {
-                let source_id = format!("{item_type}.{name}");
-                let id = cx.derive_id(&source_id);
-                write_str(
-                    w,
-                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
-                );
-                render_rightside(w, cx, item, render_mode);
-                if trait_.is_some() {
-                    // Anchors are only used on trait impls.
-                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">ยง</a>"));
-                }
-                w.push_str("<h4 class=\"code-header\">");
-                assoc_type(
-                    w,
-                    item,
-                    &tydef.generics,
-                    &[], // intentionally leaving out bounds
-                    Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
-                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                    0,
+            for method in methods {
+                doc_impl_item(
+                    &mut default_impl_items,
+                    &mut impl_items,
                     cx,
+                    method,
+                    if trait_.is_some() { &i.impl_item } else { parent },
+                    link,
+                    render_mode,
+                    false,
+                    trait_,
+                    rendering_params,
                 );
-                w.push_str("</h4></section>");
             }
-            clean::StrippedItem(..) => return,
-            _ => panic!("can't make docs for trait item with name {:?}", item.name),
         }
 
-        w.push_str(&info_buffer);
-        if toggled {
-            w.push_str("</summary>");
-            w.push_str(&doc_buffer);
-            w.push_str("</details>");
-        }
-    }
-
-    let mut impl_items = String::new();
-    let mut default_impl_items = String::new();
-    let impl_ = i.inner_impl();
-
-    // Impl items are grouped by kinds:
-    //
-    // 1. Constants
-    // 2. Types
-    // 3. Functions
-    //
-    // This order is because you can have associated constants used in associated types (like array
-    // length), and both in associcated functions. So with this order, when reading from top to
-    // bottom, you should see items definitions before they're actually used most of the time.
-    let mut assoc_types = Vec::new();
-    let mut methods = Vec::new();
-
-    if !impl_.is_negative_trait_impl() {
-        for trait_item in &impl_.items {
-            match trait_item.kind {
-                clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(trait_item),
-                clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
-                    assoc_types.push(trait_item)
+        fn render_default_items(
+            boring: &mut String,
+            interesting: &mut String,
+            cx: &Context<'_>,
+            t: &clean::Trait,
+            i: &clean::Impl,
+            parent: &clean::Item,
+            render_mode: RenderMode,
+            rendering_params: ImplRenderingParameters,
+        ) {
+            for trait_item in &t.items {
+                // Skip over any default trait items that are impossible to reference
+                // (e.g. if it has a `Self: Sized` bound on an unsized type).
+                if let Some(impl_def_id) = parent.item_id.as_def_id()
+                    && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
+                    && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
+                {
+                    continue;
                 }
-                clean::RequiredAssocConstItem(..)
-                | clean::ProvidedAssocConstItem(_)
-                | clean::ImplAssocConstItem(_) => {
-                    // We render it directly since they're supposed to come first.
-                    doc_impl_item(
-                        &mut default_impl_items,
-                        &mut impl_items,
-                        cx,
-                        trait_item,
-                        if trait_.is_some() { &i.impl_item } else { parent },
-                        link,
-                        render_mode,
-                        false,
-                        trait_,
-                        rendering_params,
-                    );
+
+                let n = trait_item.name;
+                if i.items.iter().any(|m| m.name == n) {
+                    continue;
                 }
-                _ => {}
-            }
-        }
+                let did = i.trait_.as_ref().unwrap().def_id();
+                let provided_methods = i.provided_trait_methods(cx.tcx());
+                let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
 
-        for assoc_type in assoc_types {
-            doc_impl_item(
-                &mut default_impl_items,
-                &mut impl_items,
-                cx,
-                assoc_type,
-                if trait_.is_some() { &i.impl_item } else { parent },
-                link,
-                render_mode,
-                false,
-                trait_,
-                rendering_params,
-            );
-        }
-        for method in methods {
-            doc_impl_item(
-                &mut default_impl_items,
-                &mut impl_items,
-                cx,
-                method,
-                if trait_.is_some() { &i.impl_item } else { parent },
-                link,
-                render_mode,
-                false,
-                trait_,
-                rendering_params,
-            );
+                doc_impl_item(
+                    boring,
+                    interesting,
+                    cx,
+                    trait_item,
+                    parent,
+                    assoc_link,
+                    render_mode,
+                    true,
+                    Some(t),
+                    rendering_params,
+                );
+            }
         }
-    }
 
-    fn render_default_items(
-        boring: &mut String,
-        interesting: &mut String,
-        cx: &Context<'_>,
-        t: &clean::Trait,
-        i: &clean::Impl,
-        parent: &clean::Item,
-        render_mode: RenderMode,
-        rendering_params: ImplRenderingParameters,
-    ) {
-        for trait_item in &t.items {
-            // Skip over any default trait items that are impossible to reference
-            // (e.g. if it has a `Self: Sized` bound on an unsized type).
-            if let Some(impl_def_id) = parent.item_id.as_def_id()
-                && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
-                && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
+        // If we've implemented a trait, then also emit documentation for all
+        // default items which weren't overridden in the implementation block.
+        // We don't emit documentation for default items if they appear in the
+        // Implementations on Foreign Types or Implementors sections.
+        if rendering_params.show_default_items {
+            if let Some(t) = trait_
+                && !impl_.is_negative_trait_impl()
             {
-                continue;
-            }
-
-            let n = trait_item.name;
-            if i.items.iter().any(|m| m.name == n) {
-                continue;
+                render_default_items(
+                    &mut default_impl_items,
+                    &mut impl_items,
+                    cx,
+                    t,
+                    impl_,
+                    &i.impl_item,
+                    render_mode,
+                    rendering_params,
+                );
             }
-            let did = i.trait_.as_ref().unwrap().def_id();
-            let provided_methods = i.provided_trait_methods(cx.tcx());
-            let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
-
-            doc_impl_item(
-                boring,
-                interesting,
-                cx,
-                trait_item,
-                parent,
-                assoc_link,
-                render_mode,
-                true,
-                Some(t),
-                rendering_params,
-            );
-        }
-    }
-
-    // If we've implemented a trait, then also emit documentation for all
-    // default items which weren't overridden in the implementation block.
-    // We don't emit documentation for default items if they appear in the
-    // Implementations on Foreign Types or Implementors sections.
-    if rendering_params.show_default_items {
-        if let Some(t) = trait_
-            && !impl_.is_negative_trait_impl()
-        {
-            render_default_items(
-                &mut default_impl_items,
-                &mut impl_items,
-                cx,
-                t,
-                impl_,
-                &i.impl_item,
-                render_mode,
-                rendering_params,
-            );
         }
-    }
-    if render_mode == RenderMode::Normal {
-        let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
-        if toggled {
-            close_tags.push("</details>");
-            write_str(
-                w,
-                format_args!(
+        if render_mode == RenderMode::Normal {
+            let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
+            if toggled {
+                close_tags.push("</details>");
+                write!(
+                    w,
                     "<details class=\"toggle implementors-toggle\"{}>\
                         <summary>",
                     if rendering_params.toggle_open_by_default { " open" } else { "" }
-                ),
-            );
-        }
+                )?;
+            }
 
-        let (before_dox, after_dox) = i
-            .impl_item
-            .opt_doc_value()
-            .map(|dox| {
-                Markdown {
-                    content: &dox,
-                    links: &i.impl_item.links(cx),
-                    ids: &mut cx.id_map.borrow_mut(),
-                    error_codes: cx.shared.codes,
-                    edition: cx.shared.edition(),
-                    playground: &cx.shared.playground,
-                    heading_offset: HeadingOffset::H4,
-                }
-                .split_summary_and_content()
-            })
-            .unwrap_or((None, None));
-        render_impl_summary(
-            w,
-            cx,
-            i,
-            parent,
-            rendering_params.show_def_docs,
-            use_absolute,
-            aliases,
-            &before_dox,
-        );
-        if toggled {
-            w.push_str("</summary>");
-        }
+            let (before_dox, after_dox) = i
+                .impl_item
+                .opt_doc_value()
+                .map(|dox| {
+                    Markdown {
+                        content: &dox,
+                        links: &i.impl_item.links(cx),
+                        ids: &mut cx.id_map.borrow_mut(),
+                        error_codes: cx.shared.codes,
+                        edition: cx.shared.edition(),
+                        playground: &cx.shared.playground,
+                        heading_offset: HeadingOffset::H4,
+                    }
+                    .split_summary_and_content()
+                })
+                .unwrap_or((None, None));
+            write!(
+                w,
+                "{}",
+                render_impl_summary(
+                    cx,
+                    i,
+                    parent,
+                    rendering_params.show_def_docs,
+                    use_absolute,
+                    aliases,
+                    before_dox.as_deref(),
+                )
+            )?;
+            if toggled {
+                w.write_str("</summary>")?;
+            }
 
-        if before_dox.is_some() {
-            if trait_.is_none() && impl_.items.is_empty() {
-                w.push_str(
-                    "<div class=\"item-info\">\
+            if before_dox.is_some() {
+                if trait_.is_none() && impl_.items.is_empty() {
+                    w.write_str(
+                        "<div class=\"item-info\">\
                          <div class=\"stab empty-impl\">This impl block contains no items.</div>\
                      </div>",
-                );
+                    )?;
+                }
+                if let Some(after_dox) = after_dox {
+                    write!(w, "<div class=\"docblock\">{after_dox}</div>")?;
+                }
             }
-            if let Some(after_dox) = after_dox {
-                write_str(w, format_args!("<div class=\"docblock\">{after_dox}</div>"));
+            if !default_impl_items.is_empty() || !impl_items.is_empty() {
+                w.write_str("<div class=\"impl-items\">")?;
+                close_tags.push("</div>");
             }
         }
         if !default_impl_items.is_empty() || !impl_items.is_empty() {
-            w.push_str("<div class=\"impl-items\">");
-            close_tags.push("</div>");
+            w.write_str(&default_impl_items)?;
+            w.write_str(&impl_items)?;
         }
-    }
-    if !default_impl_items.is_empty() || !impl_items.is_empty() {
-        w.push_str(&default_impl_items);
-        w.push_str(&impl_items);
-    }
-    for tag in close_tags.into_iter().rev() {
-        w.push_str(tag);
-    }
+        for tag in close_tags.into_iter().rev() {
+            w.write_str(tag)?;
+        }
+        Ok(())
+    })
 }
 
 // Render the items that appear on the right side of methods, impls, and
 // associated types. For example "1.0.0 (const: 1.39.0) ยท source".
-fn render_rightside(w: &mut String, cx: &Context<'_>, item: &clean::Item, render_mode: RenderMode) {
+fn render_rightside(
+    cx: &Context<'_>,
+    item: &clean::Item,
+    render_mode: RenderMode,
+) -> impl fmt::Display {
     let tcx = cx.tcx();
 
-    // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
-    // this condition.
-    let const_stability = match render_mode {
-        RenderMode::Normal => item.const_stability(tcx),
-        RenderMode::ForDeref { .. } => None,
-    };
-    let src_href = cx.src_href(item);
-    let has_src_ref = src_href.is_some();
-
-    let mut rightside = String::new();
-    let has_stability = render_stability_since_raw_with_extra(
-        &mut rightside,
-        item.stable_since(tcx),
-        const_stability,
-        if has_src_ref { "" } else { " rightside" },
-    );
-    if let Some(link) = src_href {
-        if has_stability {
-            write_str(
-                &mut rightside,
-                format_args!(" ยท <a class=\"src\" href=\"{link}\">Source</a>"),
-            );
-        } else {
-            write_str(
-                &mut rightside,
-                format_args!("<a class=\"src rightside\" href=\"{link}\">Source</a>"),
-            );
+    fmt::from_fn(move |w| {
+        // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+        // this condition.
+        let const_stability = match render_mode {
+            RenderMode::Normal => item.const_stability(tcx),
+            RenderMode::ForDeref { .. } => None,
+        };
+        let src_href = cx.src_href(item);
+        let stability = render_stability_since_raw_with_extra(
+            item.stable_since(tcx),
+            const_stability,
+            if src_href.is_some() { "" } else { " rightside" },
+        );
+
+        match (stability, src_href) {
+            (Some(stability), Some(link)) => {
+                write!(
+                    w,
+                    "<span class=\"rightside\">{stability} ยท <a class=\"src\" href=\"{link}\">Source</a></span>",
+                )
+            }
+            (Some(stability), None) => {
+                write!(w, "{stability}")
+            }
+            (None, Some(link)) => {
+                write!(w, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
+            }
+            (None, None) => Ok(()),
         }
-    }
-    if has_stability && has_src_ref {
-        write_str(w, format_args!("<span class=\"rightside\">{rightside}</span>"));
-    } else {
-        w.push_str(&rightside);
-    }
+    })
 }
 
 pub(crate) fn render_impl_summary(
-    w: &mut String,
     cx: &Context<'_>,
     i: &Impl,
     parent: &clean::Item,
@@ -2147,67 +2178,67 @@ pub(crate) fn render_impl_summary(
     // This argument is used to reference same type with different paths to avoid duplication
     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
     aliases: &[String],
-    doc: &Option<String>,
-) {
-    let inner_impl = i.inner_impl();
-    let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));
-    let aliases = (!aliases.is_empty())
-        .then_some(fmt::from_fn(|f| {
-            write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f)))
-        }))
-        .maybe_display();
-    write_str(w, format_args!("<section id=\"{id}\" class=\"impl\"{aliases}>"));
-    render_rightside(w, cx, &i.impl_item, RenderMode::Normal);
-    write_str(
-        w,
-        format_args!(
-            "<a href=\"#{id}\" class=\"anchor\">ยง</a>\
-            <h3 class=\"code-header\">"
-        ),
-    );
-
-    if let Some(use_absolute) = use_absolute {
-        write_str(w, format_args!("{}", inner_impl.print(use_absolute, cx)));
-        if show_def_docs {
-            for it in &inner_impl.items {
-                if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
-                    w.push_str("<div class=\"where\">  ");
-                    assoc_type(
-                        w,
-                        it,
-                        &tydef.generics,
-                        &[], // intentionally leaving out bounds
-                        Some(&tydef.type_),
-                        AssocItemLink::Anchor(None),
-                        0,
-                        cx,
-                    );
-                    w.push_str(";</div>");
+    doc: Option<&str>,
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        let inner_impl = i.inner_impl();
+        let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));
+        let aliases = (!aliases.is_empty())
+            .then_some(fmt::from_fn(|f| {
+                write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f)))
+            }))
+            .maybe_display();
+        write!(
+            w,
+            "<section id=\"{id}\" class=\"impl\"{aliases}>\
+                {}\
+                <a href=\"#{id}\" class=\"anchor\">ยง</a>\
+                <h3 class=\"code-header\">",
+            render_rightside(cx, &i.impl_item, RenderMode::Normal)
+        )?;
+
+        if let Some(use_absolute) = use_absolute {
+            write!(w, "{}", inner_impl.print(use_absolute, cx))?;
+            if show_def_docs {
+                for it in &inner_impl.items {
+                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
+                        write!(
+                            w,
+                            "<div class=\"where\">  {};</div>",
+                            assoc_type(
+                                it,
+                                &tydef.generics,
+                                &[], // intentionally leaving out bounds
+                                Some(&tydef.type_),
+                                AssocItemLink::Anchor(None),
+                                0,
+                                cx,
+                            )
+                        )?;
+                    }
                 }
             }
+        } else {
+            write!(w, "{}", inner_impl.print(false, cx))?;
         }
-    } else {
-        write_str(w, format_args!("{}", inner_impl.print(false, cx)));
-    }
-    w.push_str("</h3>");
+        w.write_str("</h3>")?;
 
-    let is_trait = inner_impl.trait_.is_some();
-    if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
-        write_str(
-            w,
-            format_args!(
+        let is_trait = inner_impl.trait_.is_some();
+        if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
+            write!(
+                w,
                 "<span class=\"item-info\">\
-                 <div class=\"stab portability\">{portability}</div>\
-             </span>",
-            ),
-        );
-    }
+                    <div class=\"stab portability\">{portability}</div>\
+                </span>",
+            )?;
+        }
 
-    if let Some(doc) = doc {
-        write_str(w, format_args!("<div class=\"docblock\">{doc}</div>"));
-    }
+        if let Some(doc) = doc {
+            write!(w, "<div class=\"docblock\">{doc}</div>")?;
+        }
 
-    w.push_str("</section>");
+        w.write_str("</section>")
+    })
 }
 
 pub(crate) fn small_url_encode(s: String) -> String {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index f3201147039..c599a84ee44 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1,10 +1,9 @@
 use std::cmp::Ordering;
 use std::fmt;
-use std::fmt::Display;
+use std::fmt::{Display, Write as _};
 
 use rinja::Template;
 use rustc_abi::VariantIdx;
-use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
@@ -32,7 +31,7 @@ use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
 use crate::html::format::{
     Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
-    print_constness_with_space, print_where_clause, visibility_print_with_space, write_str,
+    print_constness_with_space, print_where_clause, visibility_print_with_space,
 };
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
@@ -92,44 +91,32 @@ macro_rules! item_template {
 macro_rules! item_template_methods {
     () => {};
     (document $($rest:tt)*) => {
-        fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            fmt::from_fn(move |f| {
-                let (item, cx) = self.item_and_cx();
-                let v = document(cx, item, None, HeadingOffset::H2);
-                write!(f, "{v}")
-            })
+        fn document(&self) -> impl fmt::Display {
+            let (item, cx) = self.item_and_cx();
+            document(cx, item, None, HeadingOffset::H2)
         }
         item_template_methods!($($rest)*);
     };
     (document_type_layout $($rest:tt)*) => {
-        fn document_type_layout<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            fmt::from_fn(move |f| {
-                let (item, cx) = self.item_and_cx();
-                let def_id = item.item_id.expect_def_id();
-                let v = document_type_layout(cx, def_id);
-                write!(f, "{v}")
-            })
+        fn document_type_layout(&self) -> impl fmt::Display {
+            let (item, cx) = self.item_and_cx();
+            let def_id = item.item_id.expect_def_id();
+            document_type_layout(cx, def_id)
         }
         item_template_methods!($($rest)*);
     };
     (render_attributes_in_pre $($rest:tt)*) => {
-        fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            fmt::from_fn(move |f| {
-                let (item, cx) = self.item_and_cx();
-                let v = render_attributes_in_pre(item, "", cx);
-                write!(f, "{v}")
-            })
+        fn render_attributes_in_pre(&self) -> impl fmt::Display {
+            let (item, cx) = self.item_and_cx();
+            render_attributes_in_pre(item, "", cx)
         }
         item_template_methods!($($rest)*);
     };
     (render_assoc_items $($rest:tt)*) => {
-        fn render_assoc_items<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
-            fmt::from_fn(move |f| {
-                let (item, cx) = self.item_and_cx();
-                let def_id = item.item_id.expect_def_id();
-                let v = render_assoc_items(cx, item, def_id, AssocItemRender::All);
-                write!(f, "{v}")
-            })
+        fn render_assoc_items(&self) -> impl fmt::Display {
+            let (item, cx) = self.item_and_cx();
+            let def_id = item.item_id.expect_def_id();
+            render_assoc_items(cx, item, def_id, AssocItemRender::All)
         }
         item_template_methods!($($rest)*);
     };
@@ -162,132 +149,136 @@ struct ItemVars<'a> {
     src_href: Option<&'a str>,
 }
 
-/// Calls `print_where_clause` and returns `true` if a `where` clause was generated.
-fn print_where_clause_and_check<'a, 'tcx: 'a>(
-    buffer: &mut String,
-    gens: &'a clean::Generics,
-    cx: &'a Context<'tcx>,
-) -> bool {
-    let len_before = buffer.len();
-    write_str(buffer, format_args!("{}", print_where_clause(gens, cx, 0, Ending::Newline)));
-    len_before != buffer.len()
-}
-
-pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut String) {
+pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Display {
     debug_assert!(!item.is_stripped());
-    let typ = match item.kind {
-        clean::ModuleItem(_) => {
-            if item.is_crate() {
-                "Crate "
-            } else {
-                "Module "
-            }
-        }
-        clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ",
-        clean::TraitItem(..) => "Trait ",
-        clean::StructItem(..) => "Struct ",
-        clean::UnionItem(..) => "Union ",
-        clean::EnumItem(..) => "Enum ",
-        clean::TypeAliasItem(..) => "Type Alias ",
-        clean::MacroItem(..) => "Macro ",
-        clean::ProcMacroItem(ref mac) => match mac.kind {
-            MacroKind::Bang => "Macro ",
-            MacroKind::Attr => "Attribute Macro ",
-            MacroKind::Derive => "Derive Macro ",
-        },
-        clean::PrimitiveItem(..) => "Primitive Type ",
-        clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ",
-        clean::ConstantItem(..) => "Constant ",
-        clean::ForeignTypeItem => "Foreign Type ",
-        clean::KeywordItem => "Keyword ",
-        clean::TraitAliasItem(..) => "Trait Alias ",
-        _ => {
-            // We don't generate pages for any other type.
-            unreachable!();
-        }
-    };
-    let stability_since_raw = {
-        let mut buf = String::new();
-        render_stability_since_raw(
-            &mut buf,
-            item.stable_since(cx.tcx()),
-            item.const_stability(cx.tcx()),
-        );
-        buf
-    };
 
-    // Write source tag
-    //
-    // When this item is part of a `crate use` in a downstream crate, the
-    // source link in the downstream documentation will actually come back to
-    // this page, and this link will be auto-clicked. The `id` attribute is
-    // used to find the link to auto-click.
-    let src_href =
-        if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None };
-
-    let path_components = if item.is_primitive() || item.is_keyword() {
-        vec![]
-    } else {
-        let cur = &cx.current;
-        let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() };
-        cur.iter()
-            .enumerate()
-            .take(amt)
-            .map(|(i, component)| PathComponent {
-                path: "../".repeat(cur.len() - i - 1),
-                name: *component,
-            })
-            .collect()
-    };
+    fmt::from_fn(|buf| {
+        let typ = match item.kind {
+            clean::ModuleItem(_) => {
+                if item.is_crate() {
+                    "Crate "
+                } else {
+                    "Module "
+                }
+            }
+            clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ",
+            clean::TraitItem(..) => "Trait ",
+            clean::StructItem(..) => "Struct ",
+            clean::UnionItem(..) => "Union ",
+            clean::EnumItem(..) => "Enum ",
+            clean::TypeAliasItem(..) => "Type Alias ",
+            clean::MacroItem(..) => "Macro ",
+            clean::ProcMacroItem(ref mac) => match mac.kind {
+                MacroKind::Bang => "Macro ",
+                MacroKind::Attr => "Attribute Macro ",
+                MacroKind::Derive => "Derive Macro ",
+            },
+            clean::PrimitiveItem(..) => "Primitive Type ",
+            clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ",
+            clean::ConstantItem(..) => "Constant ",
+            clean::ForeignTypeItem => "Foreign Type ",
+            clean::KeywordItem => "Keyword ",
+            clean::TraitAliasItem(..) => "Trait Alias ",
+            _ => {
+                // We don't generate pages for any other type.
+                unreachable!();
+            }
+        };
+        let stability_since_raw =
+            render_stability_since_raw(item.stable_since(cx.tcx()), item.const_stability(cx.tcx()))
+                .maybe_display()
+                .to_string();
+
+        // Write source tag
+        //
+        // When this item is part of a `crate use` in a downstream crate, the
+        // source link in the downstream documentation will actually come back to
+        // this page, and this link will be auto-clicked. The `id` attribute is
+        // used to find the link to auto-click.
+        let src_href =
+            if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None };
+
+        let path_components = if item.is_primitive() || item.is_keyword() {
+            vec![]
+        } else {
+            let cur = &cx.current;
+            let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() };
+            cur.iter()
+                .enumerate()
+                .take(amt)
+                .map(|(i, component)| PathComponent {
+                    path: "../".repeat(cur.len() - i - 1),
+                    name: *component,
+                })
+                .collect()
+        };
 
-    let item_vars = ItemVars {
-        typ,
-        name: item.name.as_ref().unwrap().as_str(),
-        item_type: &item.type_().to_string(),
-        path_components,
-        stability_since_raw: &stability_since_raw,
-        src_href: src_href.as_deref(),
-    };
+        let item_vars = ItemVars {
+            typ,
+            name: item.name.as_ref().unwrap().as_str(),
+            item_type: &item.type_().to_string(),
+            path_components,
+            stability_since_raw: &stability_since_raw,
+            src_href: src_href.as_deref(),
+        };
 
-    item_vars.render_into(buf).unwrap();
+        item_vars.render_into(buf).unwrap();
 
-    match &item.kind {
-        clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
-        clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
-            item_function(buf, cx, item, f)
-        }
-        clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
-        clean::StructItem(ref s) => item_struct(buf, cx, item, s),
-        clean::UnionItem(ref s) => item_union(buf, cx, item, s),
-        clean::EnumItem(ref e) => item_enum(buf, cx, item, e),
-        clean::TypeAliasItem(ref t) => item_type_alias(buf, cx, item, t),
-        clean::MacroItem(ref m) => item_macro(buf, cx, item, m),
-        clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m),
-        clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
-        clean::StaticItem(ref i) => item_static(buf, cx, item, i, None),
-        clean::ForeignStaticItem(ref i, safety) => item_static(buf, cx, item, i, Some(*safety)),
-        clean::ConstantItem(ci) => item_constant(buf, cx, item, &ci.generics, &ci.type_, &ci.kind),
-        clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
-        clean::KeywordItem => item_keyword(buf, cx, item),
-        clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta),
-        _ => {
-            // We don't generate pages for any other type.
-            unreachable!();
-        }
-    }
+        match &item.kind {
+            clean::ModuleItem(m) => {
+                write!(buf, "{}", item_module(cx, item, &m.items))
+            }
+            clean::FunctionItem(f) | clean::ForeignFunctionItem(f, _) => {
+                write!(buf, "{}", item_function(cx, item, f))
+            }
+            clean::TraitItem(t) => write!(buf, "{}", item_trait(cx, item, t)),
+            clean::StructItem(s) => {
+                write!(buf, "{}", item_struct(cx, item, s))
+            }
+            clean::UnionItem(s) => write!(buf, "{}", item_union(cx, item, s)),
+            clean::EnumItem(e) => write!(buf, "{}", item_enum(cx, item, e)),
+            clean::TypeAliasItem(t) => {
+                write!(buf, "{}", item_type_alias(cx, item, t))
+            }
+            clean::MacroItem(m) => write!(buf, "{}", item_macro(cx, item, m)),
+            clean::ProcMacroItem(m) => {
+                write!(buf, "{}", item_proc_macro(cx, item, m))
+            }
+            clean::PrimitiveItem(_) => write!(buf, "{}", item_primitive(cx, item)),
+            clean::StaticItem(i) => {
+                write!(buf, "{}", item_static(cx, item, i, None))
+            }
+            clean::ForeignStaticItem(i, safety) => {
+                write!(buf, "{}", item_static(cx, item, i, Some(*safety)))
+            }
+            clean::ConstantItem(ci) => {
+                write!(buf, "{}", item_constant(cx, item, &ci.generics, &ci.type_, &ci.kind))
+            }
+            clean::ForeignTypeItem => {
+                write!(buf, "{}", item_foreign_type(cx, item))
+            }
+            clean::KeywordItem => write!(buf, "{}", item_keyword(cx, item)),
+            clean::TraitAliasItem(ta) => {
+                write!(buf, "{}", item_trait_alias(cx, item, ta))
+            }
+            _ => {
+                // We don't generate pages for any other type.
+                unreachable!();
+            }
+        }?;
 
-    // Render notable-traits.js used for all methods in this module.
-    let mut types_with_notable_traits = cx.types_with_notable_traits.borrow_mut();
-    if !types_with_notable_traits.is_empty() {
-        write_str(
-            buf,
-            format_args!(
+        // Render notable-traits.js used for all methods in this module.
+        let mut types_with_notable_traits = cx.types_with_notable_traits.borrow_mut();
+        if !types_with_notable_traits.is_empty() {
+            write!(
+                buf,
                 r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
-                notable_traits_json(types_with_notable_traits.iter(), cx)
-            ),
-        );
-        types_with_notable_traits.clear();
-    }
+                notable_traits_json(types_with_notable_traits.iter(), cx),
+            )?;
+            types_with_notable_traits.clear();
+        }
+        Ok(())
+    })
 }
 
 /// For large structs, enums, unions, etc, determine whether to hide their fields
@@ -314,192 +305,194 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display {
     fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>);
 }
 
-fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
-    write_str(w, format_args!("{}", document(cx, item, None, HeadingOffset::H2)));
-
-    let mut not_stripped_items =
-        items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
-
-    // the order of item types in the listing
-    fn reorder(ty: ItemType) -> u8 {
-        match ty {
-            ItemType::ExternCrate => 0,
-            ItemType::Import => 1,
-            ItemType::Primitive => 2,
-            ItemType::Module => 3,
-            ItemType::Macro => 4,
-            ItemType::Struct => 5,
-            ItemType::Enum => 6,
-            ItemType::Constant => 7,
-            ItemType::Static => 8,
-            ItemType::Trait => 9,
-            ItemType::Function => 10,
-            ItemType::TypeAlias => 12,
-            ItemType::Union => 13,
-            _ => 14 + ty as u8,
+fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        write!(w, "{}", document(cx, item, None, HeadingOffset::H2))?;
+
+        let mut not_stripped_items =
+            items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
+
+        // the order of item types in the listing
+        fn reorder(ty: ItemType) -> u8 {
+            match ty {
+                ItemType::ExternCrate => 0,
+                ItemType::Import => 1,
+                ItemType::Primitive => 2,
+                ItemType::Module => 3,
+                ItemType::Macro => 4,
+                ItemType::Struct => 5,
+                ItemType::Enum => 6,
+                ItemType::Constant => 7,
+                ItemType::Static => 8,
+                ItemType::Trait => 9,
+                ItemType::Function => 10,
+                ItemType::TypeAlias => 12,
+                ItemType::Union => 13,
+                _ => 14 + ty as u8,
+            }
         }
-    }
 
-    fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
-        let rty1 = reorder(i1.type_());
-        let rty2 = reorder(i2.type_());
-        if rty1 != rty2 {
-            return rty1.cmp(&rty2);
-        }
-        let is_stable1 = i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
-        let is_stable2 = i2.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
-        if is_stable1 != is_stable2 {
-            // true is bigger than false in the standard bool ordering,
-            // but we actually want stable items to come first
-            return is_stable2.cmp(&is_stable1);
+        fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
+            let rty1 = reorder(i1.type_());
+            let rty2 = reorder(i2.type_());
+            if rty1 != rty2 {
+                return rty1.cmp(&rty2);
+            }
+            let is_stable1 =
+                i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
+            let is_stable2 =
+                i2.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
+            if is_stable1 != is_stable2 {
+                // true is bigger than false in the standard bool ordering,
+                // but we actually want stable items to come first
+                return is_stable2.cmp(&is_stable1);
+            }
+            let lhs = i1.name.unwrap_or(kw::Empty);
+            let rhs = i2.name.unwrap_or(kw::Empty);
+            compare_names(lhs.as_str(), rhs.as_str())
         }
-        let lhs = i1.name.unwrap_or(kw::Empty);
-        let rhs = i2.name.unwrap_or(kw::Empty);
-        compare_names(lhs.as_str(), rhs.as_str())
-    }
 
-    let tcx = cx.tcx();
+        let tcx = cx.tcx();
 
-    match cx.shared.module_sorting {
-        ModuleSorting::Alphabetical => {
-            not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
-        }
-        ModuleSorting::DeclarationOrder => {}
-    }
-    // This call is to remove re-export duplicates in cases such as:
-    //
-    // ```
-    // pub(crate) mod foo {
-    //     pub(crate) mod bar {
-    //         pub(crate) trait Double { fn foo(); }
-    //     }
-    // }
-    //
-    // pub(crate) use foo::bar::*;
-    // pub(crate) use foo::*;
-    // ```
-    //
-    // `Double` will appear twice in the generated docs.
-    //
-    // FIXME: This code is quite ugly and could be improved. Small issue: DefId
-    // can be identical even if the elements are different (mostly in imports).
-    // So in case this is an import, we keep everything by adding a "unique id"
-    // (which is the position in the vector).
-    not_stripped_items.dedup_by_key(|(idx, i)| {
-        (
-            i.item_id,
-            if i.name.is_some() { Some(full_path(cx, i)) } else { None },
-            i.type_(),
-            if i.is_import() { *idx } else { 0 },
-        )
-    });
+        match cx.shared.module_sorting {
+            ModuleSorting::Alphabetical => {
+                not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
+            }
+            ModuleSorting::DeclarationOrder => {}
+        }
+        // This call is to remove re-export duplicates in cases such as:
+        //
+        // ```
+        // pub(crate) mod foo {
+        //     pub(crate) mod bar {
+        //         pub(crate) trait Double { fn foo(); }
+        //     }
+        // }
+        //
+        // pub(crate) use foo::bar::*;
+        // pub(crate) use foo::*;
+        // ```
+        //
+        // `Double` will appear twice in the generated docs.
+        //
+        // FIXME: This code is quite ugly and could be improved. Small issue: DefId
+        // can be identical even if the elements are different (mostly in imports).
+        // So in case this is an import, we keep everything by adding a "unique id"
+        // (which is the position in the vector).
+        not_stripped_items.dedup_by_key(|(idx, i)| {
+            (
+                i.item_id,
+                if i.name.is_some() { Some(full_path(cx, i)) } else { None },
+                i.type_(),
+                if i.is_import() { *idx } else { 0 },
+            )
+        });
 
-    debug!("{not_stripped_items:?}");
-    let mut last_section = None;
+        debug!("{not_stripped_items:?}");
+        let mut last_section = None;
 
-    for (_, myitem) in &not_stripped_items {
-        let my_section = item_ty_to_section(myitem.type_());
-        if Some(my_section) != last_section {
-            if last_section.is_some() {
-                w.push_str(ITEM_TABLE_CLOSE);
+        for (_, myitem) in &not_stripped_items {
+            let my_section = item_ty_to_section(myitem.type_());
+            if Some(my_section) != last_section {
+                if last_section.is_some() {
+                    w.write_str(ITEM_TABLE_CLOSE)?;
+                }
+                last_section = Some(my_section);
+                let section_id = my_section.id();
+                let tag =
+                    if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN };
+                write!(
+                    w,
+                    "{}",
+                    write_section_heading(my_section.name(), &cx.derive_id(section_id), None, tag)
+                )?;
             }
-            last_section = Some(my_section);
-            let section_id = my_section.id();
-            let tag =
-                if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN };
-            write_section_heading(w, my_section.name(), &cx.derive_id(section_id), None, tag);
-        }
 
-        match myitem.kind {
-            clean::ExternCrateItem { ref src } => {
-                use crate::html::format::anchor;
+            match myitem.kind {
+                clean::ExternCrateItem { ref src } => {
+                    use crate::html::format::anchor;
 
-                match *src {
-                    Some(src) => {
-                        write_str(
-                            w,
-                            format_args!(
+                    match *src {
+                        Some(src) => {
+                            write!(
+                                w,
                                 "<dt><code>{}extern crate {} as {};",
                                 visibility_print_with_space(myitem, cx),
                                 anchor(myitem.item_id.expect_def_id(), src, cx),
                                 EscapeBodyTextWithWbr(myitem.name.unwrap().as_str())
-                            ),
-                        );
-                    }
-                    None => {
-                        write_str(
-                            w,
-                            format_args!(
+                            )?;
+                        }
+                        None => {
+                            write!(
+                                w,
                                 "<dt><code>{}extern crate {};",
                                 visibility_print_with_space(myitem, cx),
                                 anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx)
-                            ),
-                        );
+                            )?;
+                        }
                     }
+                    w.write_str("</code></dt>")?;
                 }
-                w.push_str("</code></dt>");
-            }
 
-            clean::ImportItem(ref import) => {
-                let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| {
-                    extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string()
-                });
+                clean::ImportItem(ref import) => {
+                    let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| {
+                        extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string()
+                    });
 
-                let id = match import.kind {
-                    clean::ImportKind::Simple(s) => {
-                        format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
-                    }
-                    clean::ImportKind::Glob => String::new(),
-                };
-                write_str(
-                    w,
-                    format_args!(
+                    let id = match import.kind {
+                        clean::ImportKind::Simple(s) => {
+                            format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
+                        }
+                        clean::ImportKind::Glob => String::new(),
+                    };
+                    write!(
+                        w,
                         "<dt{id}>\
                             <code>{vis}{imp}</code>{stab_tags}\
                         </dt>",
                         vis = visibility_print_with_space(myitem, cx),
                         imp = import.print(cx)
-                    ),
-                );
-            }
-
-            _ => {
-                if myitem.name.is_none() {
-                    continue;
+                    )?;
                 }
 
-                let unsafety_flag = match myitem.kind {
-                    clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
-                        if myitem.fn_header(tcx).unwrap().is_unsafe() =>
-                    {
-                        "<sup title=\"unsafe function\">โš </sup>"
+                _ => {
+                    if myitem.name.is_none() {
+                        continue;
                     }
-                    clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
-                        "<sup title=\"unsafe static\">โš </sup>"
-                    }
-                    _ => "",
-                };
 
-                let visibility_and_hidden = match myitem.visibility(tcx) {
-                    Some(ty::Visibility::Restricted(_)) => {
-                        if myitem.is_doc_hidden() {
-                            // Don't separate with a space when there are two of them
-                            "<span title=\"Restricted Visibility\">&nbsp;๐Ÿ”’</span><span title=\"Hidden item\">๐Ÿ‘ป</span> "
-                        } else {
-                            "<span title=\"Restricted Visibility\">&nbsp;๐Ÿ”’</span> "
+                    let unsafety_flag = match myitem.kind {
+                        clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
+                            if myitem.fn_header(tcx).unwrap().is_unsafe() =>
+                        {
+                            "<sup title=\"unsafe function\">โš </sup>"
                         }
-                    }
-                    _ if myitem.is_doc_hidden() => "<span title=\"Hidden item\">&nbsp;๐Ÿ‘ป</span> ",
-                    _ => "",
-                };
-
-                let docs =
-                    MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string();
-                let (docs_before, docs_after) =
-                    if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
-                write_str(
-                    w,
-                    format_args!(
+                        clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
+                            "<sup title=\"unsafe static\">โš </sup>"
+                        }
+                        _ => "",
+                    };
+
+                    let visibility_and_hidden = match myitem.visibility(tcx) {
+                        Some(ty::Visibility::Restricted(_)) => {
+                            if myitem.is_doc_hidden() {
+                                // Don't separate with a space when there are two of them
+                                "<span title=\"Restricted Visibility\">&nbsp;๐Ÿ”’</span><span title=\"Hidden item\">๐Ÿ‘ป</span> "
+                            } else {
+                                "<span title=\"Restricted Visibility\">&nbsp;๐Ÿ”’</span> "
+                            }
+                        }
+                        _ if myitem.is_doc_hidden() => {
+                            "<span title=\"Hidden item\">&nbsp;๐Ÿ‘ป</span> "
+                        }
+                        _ => "",
+                    };
+
+                    let docs =
+                        MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string();
+                    let (docs_before, docs_after) =
+                        if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
+                    write!(
+                        w,
                         "<dt>\
                             <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
                             {visibility_and_hidden}\
@@ -514,27 +507,28 @@ fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[cl
                         unsafety_flag = unsafety_flag,
                         href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
                         title = format_args!("{} {}", myitem.type_(), full_path(cx, myitem)),
-                    ),
-                );
+                    )?;
+                }
             }
         }
-    }
 
-    if last_section.is_some() {
-        w.push_str(ITEM_TABLE_CLOSE);
-    }
+        if last_section.is_some() {
+            w.write_str(ITEM_TABLE_CLOSE)?;
+        }
+        Ok(())
+    })
 }
 
 /// Render the stability, deprecation and portability tags that are displayed in the item's summary
 /// at the module level.
-fn extra_info_tags<'a, 'tcx: 'a>(
-    tcx: TyCtxt<'tcx>,
-    item: &'a clean::Item,
-    parent: &'a clean::Item,
+fn extra_info_tags(
+    tcx: TyCtxt<'_>,
+    item: &clean::Item,
+    parent: &clean::Item,
     import_def_id: Option<DefId>,
-) -> impl Display + 'a + Captures<'tcx> {
+) -> impl Display {
     fmt::from_fn(move |f| {
-        fn tag_html<'a>(class: &'a str, title: &'a str, contents: &'a str) -> impl Display + 'a {
+        fn tag_html(class: &str, title: &str, contents: &str) -> impl Display {
             fmt::from_fn(move |f| {
                 write!(
                     f,
@@ -583,44 +577,43 @@ fn extra_info_tags<'a, 'tcx: 'a>(
     })
 }
 
-fn item_function(w: &mut String, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
-    let tcx = cx.tcx();
-    let header = it.fn_header(tcx).expect("printing a function which isn't a function");
-    debug!(
-        "item_function/const: {:?} {:?} {:?} {:?}",
-        it.name,
-        &header.constness,
-        it.stable_since(tcx),
-        it.const_stability(tcx),
-    );
-    let constness = print_constness_with_space(
-        &header.constness,
-        it.stable_since(tcx),
-        it.const_stability(tcx),
-    );
-    let safety = header.safety.print_with_space();
-    let abi = print_abi_with_space(header.abi).to_string();
-    let asyncness = header.asyncness.print_with_space();
-    let visibility = visibility_print_with_space(it, cx).to_string();
-    let name = it.name.unwrap();
-
-    let generics_len = format!("{:#}", f.generics.print(cx)).len();
-    let header_len = "fn ".len()
-        + visibility.len()
-        + constness.len()
-        + asyncness.len()
-        + safety.len()
-        + abi.len()
-        + name.as_str().len()
-        + generics_len;
-
-    let notable_traits = notable_traits_button(&f.decl.output, cx).maybe_display();
-
-    wrap_item(w, |w| {
-        w.reserve(header_len);
-        write_str(
-            w,
-            format_args!(
+fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        let tcx = cx.tcx();
+        let header = it.fn_header(tcx).expect("printing a function which isn't a function");
+        debug!(
+            "item_function/const: {:?} {:?} {:?} {:?}",
+            it.name,
+            &header.constness,
+            it.stable_since(tcx),
+            it.const_stability(tcx),
+        );
+        let constness = print_constness_with_space(
+            &header.constness,
+            it.stable_since(tcx),
+            it.const_stability(tcx),
+        );
+        let safety = header.safety.print_with_space();
+        let abi = print_abi_with_space(header.abi).to_string();
+        let asyncness = header.asyncness.print_with_space();
+        let visibility = visibility_print_with_space(it, cx).to_string();
+        let name = it.name.unwrap();
+
+        let generics_len = format!("{:#}", f.generics.print(cx)).len();
+        let header_len = "fn ".len()
+            + visibility.len()
+            + constness.len()
+            + asyncness.len()
+            + safety.len()
+            + abi.len()
+            + name.as_str().len()
+            + generics_len;
+
+        let notable_traits = notable_traits_button(&f.decl.output, cx).maybe_display();
+
+        wrap_item(w, |w| {
+            write!(
+                w,
                 "{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
                 {name}{generics}{decl}{notable_traits}{where_clause}",
                 attrs = render_attributes_in_pre(it, "", cx),
@@ -631,35 +624,37 @@ fn item_function(w: &mut String, cx: &Context<'_>, it: &clean::Item, f: &clean::
                 abi = abi,
                 name = name,
                 generics = f.generics.print(cx),
-                where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
+                where_clause =
+                    print_where_clause(&f.generics, cx, 0, Ending::Newline).maybe_display(),
                 decl = f.decl.full_print(header_len, 0, cx),
-            ),
-        );
-    });
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+            )
+        })?;
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+    })
 }
 
-fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
-    let tcx = cx.tcx();
-    let bounds = bounds(&t.bounds, false, cx);
-    let required_types =
-        t.items.iter().filter(|m| m.is_required_associated_type()).collect::<Vec<_>>();
-    let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
-    let required_consts =
-        t.items.iter().filter(|m| m.is_required_associated_const()).collect::<Vec<_>>();
-    let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
-    let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
-    let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
-    let count_types = required_types.len() + provided_types.len();
-    let count_consts = required_consts.len() + provided_consts.len();
-    let count_methods = required_methods.len() + provided_methods.len();
-    let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone();
-
-    // Output the trait definition
-    wrap_item(w, |mut w| {
-        write_str(
-            w,
-            format_args!(
+fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        let tcx = cx.tcx();
+        let bounds = bounds(&t.bounds, false, cx);
+        let required_types =
+            t.items.iter().filter(|m| m.is_required_associated_type()).collect::<Vec<_>>();
+        let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
+        let required_consts =
+            t.items.iter().filter(|m| m.is_required_associated_const()).collect::<Vec<_>>();
+        let provided_consts =
+            t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
+        let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
+        let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
+        let count_types = required_types.len() + provided_types.len();
+        let count_consts = required_consts.len() + provided_consts.len();
+        let count_methods = required_methods.len() + provided_methods.len();
+        let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone();
+
+        // Output the trait definition
+        wrap_item(w, |mut w| {
+            write!(
+                w,
                 "{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
                 attrs = render_attributes_in_pre(it, "", cx),
                 vis = visibility_print_with_space(it, cx),
@@ -667,747 +662,808 @@ fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                 is_auto = if t.is_auto(tcx) { "auto " } else { "" },
                 name = it.name.unwrap(),
                 generics = t.generics.print(cx),
-            ),
-        );
-
-        if !t.generics.where_predicates.is_empty() {
-            write_str(
-                w,
-                format_args!("{}", print_where_clause(&t.generics, cx, 0, Ending::Newline)),
-            );
-        } else {
-            w.push_str(" ");
-        }
+            )?;
 
-        if t.items.is_empty() {
-            w.push_str("{ }");
-        } else {
-            // FIXME: we should be using a derived_id for the Anchors here
-            w.push_str("{\n");
-            let mut toggle = false;
-
-            // If there are too many associated types, hide _everything_
-            if should_hide_fields(count_types) {
-                toggle = true;
-                toggle_open(
-                    &mut w,
-                    format_args!("{} associated items", count_types + count_consts + count_methods),
-                );
+            if !t.generics.where_predicates.is_empty() {
+                write!(
+                    w,
+                    "{}",
+                    print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display()
+                )?;
+            } else {
+                w.write_char(' ')?;
             }
-            for types in [&required_types, &provided_types] {
-                for t in types {
-                    render_assoc_item(
-                        w,
-                        t,
-                        AssocItemLink::Anchor(None),
-                        ItemType::Trait,
-                        cx,
-                        RenderMode::Normal,
+
+            if t.items.is_empty() {
+                w.write_str("{ }")
+            } else {
+                // FIXME: we should be using a derived_id for the Anchors here
+                w.write_str("{\n")?;
+                let mut toggle = false;
+
+                // If there are too many associated types, hide _everything_
+                if should_hide_fields(count_types) {
+                    toggle = true;
+                    toggle_open(
+                        &mut w,
+                        format_args!(
+                            "{} associated items",
+                            count_types + count_consts + count_methods
+                        ),
                     );
-                    w.push_str(";\n");
                 }
-            }
-            // If there are too many associated constants, hide everything after them
-            // We also do this if the types + consts is large because otherwise we could
-            // render a bunch of types and _then_ a bunch of consts just because both were
-            // _just_ under the limit
-            if !toggle && should_hide_fields(count_types + count_consts) {
-                toggle = true;
-                toggle_open(
-                    &mut w,
-                    format_args!(
-                        "{count_consts} associated constant{plural_const} and \
+                for types in [&required_types, &provided_types] {
+                    for t in types {
+                        writeln!(
+                            w,
+                            "{};",
+                            render_assoc_item(
+                                t,
+                                AssocItemLink::Anchor(None),
+                                ItemType::Trait,
+                                cx,
+                                RenderMode::Normal,
+                            )
+                        )?;
+                    }
+                }
+                // If there are too many associated constants, hide everything after them
+                // We also do this if the types + consts is large because otherwise we could
+                // render a bunch of types and _then_ a bunch of consts just because both were
+                // _just_ under the limit
+                if !toggle && should_hide_fields(count_types + count_consts) {
+                    toggle = true;
+                    toggle_open(
+                        &mut w,
+                        format_args!(
+                            "{count_consts} associated constant{plural_const} and \
                          {count_methods} method{plural_method}",
-                        plural_const = pluralize(count_consts),
-                        plural_method = pluralize(count_methods),
-                    ),
-                );
-            }
-            if count_types != 0 && (count_consts != 0 || count_methods != 0) {
-                w.push_str("\n");
-            }
-            for consts in [&required_consts, &provided_consts] {
-                for c in consts {
-                    render_assoc_item(
-                        w,
-                        c,
-                        AssocItemLink::Anchor(None),
-                        ItemType::Trait,
-                        cx,
-                        RenderMode::Normal,
+                            plural_const = pluralize(count_consts),
+                            plural_method = pluralize(count_methods),
+                        ),
                     );
-                    w.push_str(";\n");
                 }
-            }
-            if !toggle && should_hide_fields(count_methods) {
-                toggle = true;
-                toggle_open(&mut w, format_args!("{count_methods} methods"));
-            }
-            if count_consts != 0 && count_methods != 0 {
-                w.push_str("\n");
-            }
-
-            if !required_methods.is_empty() {
-                write_str(
-                    w,
-                    format_args_nl!("    // Required method{}", pluralize(required_methods.len())),
-                );
-            }
-            for (pos, m) in required_methods.iter().enumerate() {
-                render_assoc_item(
-                    w,
-                    m,
-                    AssocItemLink::Anchor(None),
-                    ItemType::Trait,
-                    cx,
-                    RenderMode::Normal,
-                );
-                w.push_str(";\n");
+                if count_types != 0 && (count_consts != 0 || count_methods != 0) {
+                    w.write_str("\n")?;
+                }
+                for consts in [&required_consts, &provided_consts] {
+                    for c in consts {
+                        writeln!(
+                            w,
+                            "{};",
+                            render_assoc_item(
+                                c,
+                                AssocItemLink::Anchor(None),
+                                ItemType::Trait,
+                                cx,
+                                RenderMode::Normal,
+                            )
+                        )?;
+                    }
+                }
+                if !toggle && should_hide_fields(count_methods) {
+                    toggle = true;
+                    toggle_open(&mut w, format_args!("{count_methods} methods"));
+                }
+                if count_consts != 0 && count_methods != 0 {
+                    w.write_str("\n")?;
+                }
 
-                if pos < required_methods.len() - 1 {
-                    w.push_str("<span class=\"item-spacer\"></span>");
+                if !required_methods.is_empty() {
+                    writeln!(w, "    // Required method{}", pluralize(required_methods.len()))?;
                 }
-            }
-            if !required_methods.is_empty() && !provided_methods.is_empty() {
-                w.push_str("\n");
-            }
+                for (pos, m) in required_methods.iter().enumerate() {
+                    writeln!(
+                        w,
+                        "{};",
+                        render_assoc_item(
+                            m,
+                            AssocItemLink::Anchor(None),
+                            ItemType::Trait,
+                            cx,
+                            RenderMode::Normal,
+                        )
+                    )?;
 
-            if !provided_methods.is_empty() {
-                write_str(
-                    w,
-                    format_args_nl!("    // Provided method{}", pluralize(provided_methods.len())),
-                );
-            }
-            for (pos, m) in provided_methods.iter().enumerate() {
-                render_assoc_item(
-                    w,
-                    m,
-                    AssocItemLink::Anchor(None),
-                    ItemType::Trait,
-                    cx,
-                    RenderMode::Normal,
-                );
+                    if pos < required_methods.len() - 1 {
+                        w.write_str("<span class=\"item-spacer\"></span>")?;
+                    }
+                }
+                if !required_methods.is_empty() && !provided_methods.is_empty() {
+                    w.write_str("\n")?;
+                }
 
-                w.push_str(" { ... }\n");
+                if !provided_methods.is_empty() {
+                    writeln!(w, "    // Provided method{}", pluralize(provided_methods.len()))?;
+                }
+                for (pos, m) in provided_methods.iter().enumerate() {
+                    writeln!(
+                        w,
+                        "{} {{ ... }}",
+                        render_assoc_item(
+                            m,
+                            AssocItemLink::Anchor(None),
+                            ItemType::Trait,
+                            cx,
+                            RenderMode::Normal,
+                        )
+                    )?;
 
-                if pos < provided_methods.len() - 1 {
-                    w.push_str("<span class=\"item-spacer\"></span>");
+                    if pos < provided_methods.len() - 1 {
+                        w.write_str("<span class=\"item-spacer\"></span>")?;
+                    }
                 }
+                if toggle {
+                    toggle_close(&mut w);
+                }
+                w.write_str("}")
             }
-            if toggle {
-                toggle_close(&mut w);
-            }
-            w.push_str("}");
-        }
-    });
+        })?;
 
-    // Trait documentation
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+        // Trait documentation
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
 
-    fn trait_item(w: &mut String, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) {
-        let name = m.name.unwrap();
-        info!("Documenting {name} on {ty_name:?}", ty_name = t.name);
-        let item_type = m.type_();
-        let id = cx.derive_id(format!("{item_type}.{name}"));
+        fn trait_item(cx: &Context<'_>, m: &clean::Item, t: &clean::Item) -> impl fmt::Display {
+            fmt::from_fn(|w| {
+                let name = m.name.unwrap();
+                info!("Documenting {name} on {ty_name:?}", ty_name = t.name);
+                let item_type = m.type_();
+                let id = cx.derive_id(format!("{item_type}.{name}"));
 
-        let mut content = String::new();
-        write_str(&mut content, format_args!("{}", document_full(m, cx, HeadingOffset::H5)));
+                let content = document_full(m, cx, HeadingOffset::H5).to_string();
 
-        let toggled = !content.is_empty();
-        if toggled {
-            let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write_str(
-                w,
-                format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
-            );
-        }
-        write_str(w, format_args!("<section id=\"{id}\" class=\"method\">"));
-        render_rightside(w, cx, m, RenderMode::Normal);
-        write_str(w, format_args!("<h4 class=\"code-header\">"));
-        render_assoc_item(
-            w,
-            m,
-            AssocItemLink::Anchor(Some(&id)),
-            ItemType::Impl,
-            cx,
-            RenderMode::Normal,
-        );
-        w.push_str("</h4></section>");
-        document_item_info(cx, m, Some(t)).render_into(w).unwrap();
-        if toggled {
-            write_str(w, format_args!("</summary>"));
-            w.push_str(&content);
-            write_str(w, format_args!("</details>"));
+                let toggled = !content.is_empty();
+                if toggled {
+                    let method_toggle_class =
+                        if item_type.is_method() { " method-toggle" } else { "" };
+                    write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>")?;
+                }
+                write!(
+                    w,
+                    "<section id=\"{id}\" class=\"method\">\
+                    {}\
+                    <h4 class=\"code-header\">{}</h4></section>",
+                    render_rightside(cx, m, RenderMode::Normal),
+                    render_assoc_item(
+                        m,
+                        AssocItemLink::Anchor(Some(&id)),
+                        ItemType::Impl,
+                        cx,
+                        RenderMode::Normal,
+                    )
+                )?;
+                document_item_info(cx, m, Some(t)).render_into(w).unwrap();
+                if toggled {
+                    write!(w, "</summary>{content}</details>")?;
+                }
+                Ok(())
+            })
         }
-    }
 
-    if !required_consts.is_empty() {
-        write_section_heading(
-            w,
-            "Required Associated Constants",
-            "required-associated-consts",
-            None,
-            "<div class=\"methods\">",
-        );
-        for t in required_consts {
-            trait_item(w, cx, t, it);
+        if !required_consts.is_empty() {
+            write!(
+                w,
+                "{}",
+                write_section_heading(
+                    "Required Associated Constants",
+                    "required-associated-consts",
+                    None,
+                    "<div class=\"methods\">",
+                )
+            )?;
+            for t in required_consts {
+                write!(w, "{}", trait_item(cx, t, it))?;
+            }
+            w.write_str("</div>")?;
         }
-        w.push_str("</div>");
-    }
-    if !provided_consts.is_empty() {
-        write_section_heading(
-            w,
-            "Provided Associated Constants",
-            "provided-associated-consts",
-            None,
-            "<div class=\"methods\">",
-        );
-        for t in provided_consts {
-            trait_item(w, cx, t, it);
+        if !provided_consts.is_empty() {
+            write!(
+                w,
+                "{}",
+                write_section_heading(
+                    "Provided Associated Constants",
+                    "provided-associated-consts",
+                    None,
+                    "<div class=\"methods\">",
+                )
+            )?;
+            for t in provided_consts {
+                write!(w, "{}", trait_item(cx, t, it))?;
+            }
+            w.write_str("</div>")?;
         }
-        w.push_str("</div>");
-    }
 
-    if !required_types.is_empty() {
-        write_section_heading(
-            w,
-            "Required Associated Types",
-            "required-associated-types",
-            None,
-            "<div class=\"methods\">",
-        );
-        for t in required_types {
-            trait_item(w, cx, t, it);
+        if !required_types.is_empty() {
+            write!(
+                w,
+                "{}",
+                write_section_heading(
+                    "Required Associated Types",
+                    "required-associated-types",
+                    None,
+                    "<div class=\"methods\">",
+                )
+            )?;
+            for t in required_types {
+                write!(w, "{}", trait_item(cx, t, it))?;
+            }
+            w.write_str("</div>")?;
         }
-        w.push_str("</div>");
-    }
-    if !provided_types.is_empty() {
-        write_section_heading(
-            w,
-            "Provided Associated Types",
-            "provided-associated-types",
-            None,
-            "<div class=\"methods\">",
-        );
-        for t in provided_types {
-            trait_item(w, cx, t, it);
+        if !provided_types.is_empty() {
+            write!(
+                w,
+                "{}",
+                write_section_heading(
+                    "Provided Associated Types",
+                    "provided-associated-types",
+                    None,
+                    "<div class=\"methods\">",
+                )
+            )?;
+            for t in provided_types {
+                write!(w, "{}", trait_item(cx, t, it))?;
+            }
+            w.write_str("</div>")?;
         }
-        w.push_str("</div>");
-    }
-
-    // Output the documentation for each function individually
-    if !required_methods.is_empty() || must_implement_one_of_functions.is_some() {
-        write_section_heading(
-            w,
-            "Required Methods",
-            "required-methods",
-            None,
-            "<div class=\"methods\">",
-        );
 
-        if let Some(list) = must_implement_one_of_functions.as_deref() {
-            write_str(
+        // Output the documentation for each function individually
+        if !required_methods.is_empty() || must_implement_one_of_functions.is_some() {
+            write!(
                 w,
-                format_args!(
+                "{}",
+                write_section_heading(
+                    "Required Methods",
+                    "required-methods",
+                    None,
+                    "<div class=\"methods\">",
+                )
+            )?;
+
+            if let Some(list) = must_implement_one_of_functions.as_deref() {
+                write!(
+                    w,
                     "<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
-                    fmt::from_fn(|f| list.iter().joined("`, `", f))
-                ),
-            );
-        }
+                    fmt::from_fn(|f| list.iter().joined("`, `", f)),
+                )?;
+            }
 
-        for m in required_methods {
-            trait_item(w, cx, m, it);
+            for m in required_methods {
+                write!(w, "{}", trait_item(cx, m, it))?;
+            }
+            w.write_str("</div>")?;
         }
-        w.push_str("</div>");
-    }
-    if !provided_methods.is_empty() {
-        write_section_heading(
-            w,
-            "Provided Methods",
-            "provided-methods",
-            None,
-            "<div class=\"methods\">",
-        );
-        for m in provided_methods {
-            trait_item(w, cx, m, it);
+        if !provided_methods.is_empty() {
+            write!(
+                w,
+                "{}",
+                write_section_heading(
+                    "Provided Methods",
+                    "provided-methods",
+                    None,
+                    "<div class=\"methods\">",
+                )
+            )?;
+            for m in provided_methods {
+                write!(w, "{}", trait_item(cx, m, it))?;
+            }
+            w.write_str("</div>")?;
         }
-        w.push_str("</div>");
-    }
 
-    // If there are methods directly on this trait object, render them here.
-    write_str(
-        w,
-        format_args!(
+        // If there are methods directly on this trait object, render them here.
+        write!(
+            w,
             "{}",
             render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
-        ),
-    );
+        )?;
 
-    let mut extern_crates = FxIndexSet::default();
+        let mut extern_crates = FxIndexSet::default();
 
-    if !t.is_dyn_compatible(cx.tcx()) {
-        write_section_heading(
-            w,
-            "Dyn Compatibility",
-            "dyn-compatibility",
-            None,
-            format!(
-                "<div class=\"dyn-compatibility-info\"><p>This trait is <b>not</b> \
-                <a href=\"{base}/reference/items/traits.html#dyn-compatibility\">dyn compatible</a>.</p>\
-                <p><i>In older versions of Rust, dyn compatibility was called \"object safety\", \
-                so this trait is not object safe.</i></p></div>",
-                base = crate::clean::utils::DOC_RUST_LANG_ORG_VERSION
-            ),
-        );
-    }
+        if !t.is_dyn_compatible(cx.tcx()) {
+            write!(
+                w,
+                "{}",
+                write_section_heading(
+                    "Dyn Compatibility",
+                    "dyn-compatibility",
+                    None,
+                    format!(
+                        "<div class=\"dyn-compatibility-info\"><p>This trait is <b>not</b> \
+                        <a href=\"{base}/reference/items/traits.html#dyn-compatibility\">dyn compatible</a>.</p>\
+                        <p><i>In older versions of Rust, dyn compatibility was called \"object safety\", \
+                        so this trait is not object safe.</i></p></div>",
+                        base = crate::clean::utils::DOC_RUST_LANG_ORG_VERSION
+                    ),
+                ),
+            )?;
+        }
 
-    if let Some(implementors) = cx.shared.cache.implementors.get(&it.item_id.expect_def_id()) {
-        // The DefId is for the first Type found with that name. The bool is
-        // if any Types with the same name but different DefId have been found.
-        let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
-        for implementor in implementors {
-            if let Some(did) =
-                implementor.inner_impl().for_.without_borrowed_ref().def_id(&cx.shared.cache)
-                && !did.is_local()
-            {
-                extern_crates.insert(did.krate);
-            }
-            match implementor.inner_impl().for_.without_borrowed_ref() {
-                clean::Type::Path { ref path } if !path.is_assoc_ty() => {
-                    let did = path.def_id();
-                    let &mut (prev_did, ref mut has_duplicates) =
-                        implementor_dups.entry(path.last()).or_insert((did, false));
-                    if prev_did != did {
-                        *has_duplicates = true;
+        if let Some(implementors) = cx.shared.cache.implementors.get(&it.item_id.expect_def_id()) {
+            // The DefId is for the first Type found with that name. The bool is
+            // if any Types with the same name but different DefId have been found.
+            let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
+            for implementor in implementors {
+                if let Some(did) =
+                    implementor.inner_impl().for_.without_borrowed_ref().def_id(&cx.shared.cache)
+                    && !did.is_local()
+                {
+                    extern_crates.insert(did.krate);
+                }
+                match implementor.inner_impl().for_.without_borrowed_ref() {
+                    clean::Type::Path { path } if !path.is_assoc_ty() => {
+                        let did = path.def_id();
+                        let &mut (prev_did, ref mut has_duplicates) =
+                            implementor_dups.entry(path.last()).or_insert((did, false));
+                        if prev_did != did {
+                            *has_duplicates = true;
+                        }
                     }
+                    _ => {}
                 }
-                _ => {}
             }
-        }
-
-        let (local, mut foreign) =
-            implementors.iter().partition::<Vec<_>, _>(|i| i.is_on_local_type(cx));
 
-        let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
-            local.iter().partition(|i| i.inner_impl().kind.is_auto());
+            let (local, mut foreign) =
+                implementors.iter().partition::<Vec<_>, _>(|i| i.is_on_local_type(cx));
 
-        synthetic.sort_by_cached_key(|i| ImplString::new(i, cx));
-        concrete.sort_by_cached_key(|i| ImplString::new(i, cx));
-        foreign.sort_by_cached_key(|i| ImplString::new(i, cx));
+            let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
+                local.iter().partition(|i| i.inner_impl().kind.is_auto());
 
-        if !foreign.is_empty() {
-            write_section_heading(w, "Implementations on Foreign Types", "foreign-impls", None, "");
+            synthetic.sort_by_cached_key(|i| ImplString::new(i, cx));
+            concrete.sort_by_cached_key(|i| ImplString::new(i, cx));
+            foreign.sort_by_cached_key(|i| ImplString::new(i, cx));
 
-            for implementor in foreign {
-                let provided_methods = implementor.inner_impl().provided_trait_methods(tcx);
-                let assoc_link =
-                    AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods);
-                render_impl(
+            if !foreign.is_empty() {
+                write!(
                     w,
-                    cx,
-                    implementor,
-                    it,
-                    assoc_link,
-                    RenderMode::Normal,
-                    None,
-                    &[],
-                    ImplRenderingParameters {
-                        show_def_docs: false,
-                        show_default_items: false,
-                        show_non_assoc_items: true,
-                        toggle_open_by_default: false,
-                    },
-                );
-            }
-        }
+                    "{}",
+                    write_section_heading(
+                        "Implementations on Foreign Types",
+                        "foreign-impls",
+                        None,
+                        ""
+                    )
+                )?;
 
-        write_section_heading(
-            w,
-            "Implementors",
-            "implementors",
-            None,
-            "<div id=\"implementors-list\">",
-        );
-        for implementor in concrete {
-            render_implementor(cx, implementor, it, w, &implementor_dups, &[]);
-        }
-        w.push_str("</div>");
+                for implementor in foreign {
+                    let provided_methods = implementor.inner_impl().provided_trait_methods(tcx);
+                    let assoc_link =
+                        AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods);
+                    write!(
+                        w,
+                        "{}",
+                        render_impl(
+                            cx,
+                            implementor,
+                            it,
+                            assoc_link,
+                            RenderMode::Normal,
+                            None,
+                            &[],
+                            ImplRenderingParameters {
+                                show_def_docs: false,
+                                show_default_items: false,
+                                show_non_assoc_items: true,
+                                toggle_open_by_default: false,
+                            },
+                        )
+                    )?;
+                }
+            }
 
-        if t.is_auto(tcx) {
-            write_section_heading(
+            write!(
                 w,
-                "Auto implementors",
-                "synthetic-implementors",
-                None,
-                "<div id=\"synthetic-implementors-list\">",
-            );
-            for implementor in synthetic {
-                render_implementor(
-                    cx,
-                    implementor,
-                    it,
-                    w,
-                    &implementor_dups,
-                    &collect_paths_for_type(
-                        implementor.inner_impl().for_.clone(),
-                        &cx.shared.cache,
-                    ),
-                );
+                "{}",
+                write_section_heading(
+                    "Implementors",
+                    "implementors",
+                    None,
+                    "<div id=\"implementors-list\">",
+                )
+            )?;
+            for implementor in concrete {
+                write!(w, "{}", render_implementor(cx, implementor, it, &implementor_dups, &[]))?;
             }
-            w.push_str("</div>");
-        }
-    } else {
-        // even without any implementations to write in, we still want the heading and list, so the
-        // implementors javascript file pulled in below has somewhere to write the impls into
-        write_section_heading(
-            w,
-            "Implementors",
-            "implementors",
-            None,
-            "<div id=\"implementors-list\"></div>",
-        );
+            w.write_str("</div>")?;
 
-        if t.is_auto(tcx) {
-            write_section_heading(
+            if t.is_auto(tcx) {
+                write!(
+                    w,
+                    "{}",
+                    write_section_heading(
+                        "Auto implementors",
+                        "synthetic-implementors",
+                        None,
+                        "<div id=\"synthetic-implementors-list\">",
+                    )
+                )?;
+                for implementor in synthetic {
+                    write!(
+                        w,
+                        "{}",
+                        render_implementor(
+                            cx,
+                            implementor,
+                            it,
+                            &implementor_dups,
+                            &collect_paths_for_type(
+                                implementor.inner_impl().for_.clone(),
+                                &cx.shared.cache,
+                            ),
+                        )
+                    )?;
+                }
+                w.write_str("</div>")?;
+            }
+        } else {
+            // even without any implementations to write in, we still want the heading and list, so the
+            // implementors javascript file pulled in below has somewhere to write the impls into
+            write!(
                 w,
-                "Auto implementors",
-                "synthetic-implementors",
-                None,
-                "<div id=\"synthetic-implementors-list\"></div>",
-            );
-        }
-    }
+                "{}",
+                write_section_heading(
+                    "Implementors",
+                    "implementors",
+                    None,
+                    "<div id=\"implementors-list\"></div>",
+                )
+            )?;
 
-    // [RUSTDOCIMPL] trait.impl
-    //
-    // Include implementors in crates that depend on the current crate.
-    //
-    // This is complicated by the way rustdoc is invoked, which is basically
-    // the same way rustc is invoked: it gets called, one at a time, for each
-    // crate. When building the rustdocs for the current crate, rustdoc can
-    // see crate metadata for its dependencies, but cannot see metadata for its
-    // dependents.
-    //
-    // To make this work, we generate a "hook" at this stage, and our
-    // dependents can "plug in" to it when they build. For simplicity's sake,
-    // it's [JSONP]: a JavaScript file with the data we need (and can parse),
-    // surrounded by a tiny wrapper that the Rust side ignores, but allows the
-    // JavaScript side to include without having to worry about Same Origin
-    // Policy. The code for *that* is in `write_shared.rs`.
-    //
-    // This is further complicated by `#[doc(inline)]`. We want all copies
-    // of an inlined trait to reference the same JS file, to address complex
-    // dependency graphs like this one (lower crates depend on higher crates):
-    //
-    // ```text
-    //  --------------------------------------------
-    //  |            crate A: trait Foo            |
-    //  --------------------------------------------
-    //      |                               |
-    //  --------------------------------    |
-    //  | crate B: impl A::Foo for Bar |    |
-    //  --------------------------------    |
-    //      |                               |
-    //  ---------------------------------------------
-    //  | crate C: #[doc(inline)] use A::Foo as Baz |
-    //  |          impl Baz for Quux                |
-    //  ---------------------------------------------
-    // ```
-    //
-    // Basically, we want `C::Baz` and `A::Foo` to show the same set of
-    // impls, which is easier if they both treat `/trait.impl/A/trait.Foo.js`
-    // as the Single Source of Truth.
-    //
-    // We also want the `impl Baz for Quux` to be written to
-    // `trait.Foo.js`. However, when we generate plain HTML for `C::Baz`,
-    // we're going to want to generate plain HTML for `impl Baz for Quux` too,
-    // because that'll load faster, and it's better for SEO. And we don't want
-    // the same impl to show up twice on the same page.
-    //
-    // To make this work, the trait.impl/A/trait.Foo.js JS file has a structure kinda
-    // like this:
-    //
-    // ```js
-    // JSONP({
-    // "B": {"impl A::Foo for Bar"},
-    // "C": {"impl Baz for Quux"},
-    // });
-    // ```
-    //
-    // First of all, this means we can rebuild a crate, and it'll replace its own
-    // data if something changes. That is, `rustdoc` is idempotent. The other
-    // advantage is that we can list the crates that get included in the HTML,
-    // and ignore them when doing the JavaScript-based part of rendering.
-    // So C's HTML will have something like this:
-    //
-    // ```html
-    // <script src="/trait.impl/A/trait.Foo.js"
-    //     data-ignore-extern-crates="A,B" async></script>
-    // ```
-    //
-    // And, when the JS runs, anything in data-ignore-extern-crates is known
-    // to already be in the HTML, and will be ignored.
-    //
-    // [JSONP]: https://en.wikipedia.org/wiki/JSONP
-    let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..")
-        .take(cx.current.len())
-        .chain(std::iter::once("trait.impl"))
-        .collect();
-    if let Some(did) = it.item_id.as_def_id()
-        && let get_extern = { || cx.shared.cache.external_paths.get(&did).map(|s| &s.0) }
-        && let Some(fqp) = cx.shared.cache.exact_paths.get(&did).or_else(get_extern)
-    {
-        js_src_path.extend(fqp[..fqp.len() - 1].iter().copied());
-        js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap()));
-    } else {
-        js_src_path.extend(cx.current.iter().copied());
-        js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap()));
-    }
-    let extern_crates = fmt::from_fn(|f| {
-        if !extern_crates.is_empty() {
-            f.write_str(" data-ignore-extern-crates=\"")?;
-            extern_crates.iter().map(|&cnum| tcx.crate_name(cnum)).joined(",", f)?;
-            f.write_str("\"")?;
+            if t.is_auto(tcx) {
+                write!(
+                    w,
+                    "{}",
+                    write_section_heading(
+                        "Auto implementors",
+                        "synthetic-implementors",
+                        None,
+                        "<div id=\"synthetic-implementors-list\"></div>",
+                    )
+                )?;
+            }
         }
-        Ok(())
-    });
-    write_str(
-        w,
-        format_args!(
+
+        // [RUSTDOCIMPL] trait.impl
+        //
+        // Include implementors in crates that depend on the current crate.
+        //
+        // This is complicated by the way rustdoc is invoked, which is basically
+        // the same way rustc is invoked: it gets called, one at a time, for each
+        // crate. When building the rustdocs for the current crate, rustdoc can
+        // see crate metadata for its dependencies, but cannot see metadata for its
+        // dependents.
+        //
+        // To make this work, we generate a "hook" at this stage, and our
+        // dependents can "plug in" to it when they build. For simplicity's sake,
+        // it's [JSONP]: a JavaScript file with the data we need (and can parse),
+        // surrounded by a tiny wrapper that the Rust side ignores, but allows the
+        // JavaScript side to include without having to worry about Same Origin
+        // Policy. The code for *that* is in `write_shared.rs`.
+        //
+        // This is further complicated by `#[doc(inline)]`. We want all copies
+        // of an inlined trait to reference the same JS file, to address complex
+        // dependency graphs like this one (lower crates depend on higher crates):
+        //
+        // ```text
+        //  --------------------------------------------
+        //  |            crate A: trait Foo            |
+        //  --------------------------------------------
+        //      |                               |
+        //  --------------------------------    |
+        //  | crate B: impl A::Foo for Bar |    |
+        //  --------------------------------    |
+        //      |                               |
+        //  ---------------------------------------------
+        //  | crate C: #[doc(inline)] use A::Foo as Baz |
+        //  |          impl Baz for Quux                |
+        //  ---------------------------------------------
+        // ```
+        //
+        // Basically, we want `C::Baz` and `A::Foo` to show the same set of
+        // impls, which is easier if they both treat `/trait.impl/A/trait.Foo.js`
+        // as the Single Source of Truth.
+        //
+        // We also want the `impl Baz for Quux` to be written to
+        // `trait.Foo.js`. However, when we generate plain HTML for `C::Baz`,
+        // we're going to want to generate plain HTML for `impl Baz for Quux` too,
+        // because that'll load faster, and it's better for SEO. And we don't want
+        // the same impl to show up twice on the same page.
+        //
+        // To make this work, the trait.impl/A/trait.Foo.js JS file has a structure kinda
+        // like this:
+        //
+        // ```js
+        // JSONP({
+        // "B": {"impl A::Foo for Bar"},
+        // "C": {"impl Baz for Quux"},
+        // });
+        // ```
+        //
+        // First of all, this means we can rebuild a crate, and it'll replace its own
+        // data if something changes. That is, `rustdoc` is idempotent. The other
+        // advantage is that we can list the crates that get included in the HTML,
+        // and ignore them when doing the JavaScript-based part of rendering.
+        // So C's HTML will have something like this:
+        //
+        // ```html
+        // <script src="/trait.impl/A/trait.Foo.js"
+        //     data-ignore-extern-crates="A,B" async></script>
+        // ```
+        //
+        // And, when the JS runs, anything in data-ignore-extern-crates is known
+        // to already be in the HTML, and will be ignored.
+        //
+        // [JSONP]: https://en.wikipedia.org/wiki/JSONP
+        let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..")
+            .take(cx.current.len())
+            .chain(std::iter::once("trait.impl"))
+            .collect();
+        if let Some(did) = it.item_id.as_def_id()
+            && let get_extern = { || cx.shared.cache.external_paths.get(&did).map(|s| &s.0) }
+            && let Some(fqp) = cx.shared.cache.exact_paths.get(&did).or_else(get_extern)
+        {
+            js_src_path.extend(fqp[..fqp.len() - 1].iter().copied());
+            js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap()));
+        } else {
+            js_src_path.extend(cx.current.iter().copied());
+            js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap()));
+        }
+        let extern_crates = fmt::from_fn(|f| {
+            if !extern_crates.is_empty() {
+                f.write_str(" data-ignore-extern-crates=\"")?;
+                extern_crates.iter().map(|&cnum| tcx.crate_name(cnum)).joined(",", f)?;
+                f.write_str("\"")?;
+            }
+            Ok(())
+        });
+        write!(
+            w,
             "<script src=\"{src}\"{extern_crates} async></script>",
             src = js_src_path.finish()
-        ),
-    );
+        )
+    })
 }
 
 fn item_trait_alias(
-    w: &mut impl fmt::Write,
     cx: &Context<'_>,
     it: &clean::Item,
     t: &clean::TraitAlias,
-) {
-    wrap_item(w, |w| {
+) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        wrap_item(w, |w| {
+            write!(
+                w,
+                "{attrs}trait {name}{generics}{where_b} = {bounds};",
+                attrs = render_attributes_in_pre(it, "", cx),
+                name = it.name.unwrap(),
+                generics = t.generics.print(cx),
+                where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(),
+                bounds = bounds(&t.bounds, true, cx),
+            )
+        })?;
+
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
+        // Render any items associated directly to this alias, as otherwise they
+        // won't be visible anywhere in the docs. It would be nice to also show
+        // associated items from the aliased type (see discussion in #32077), but
+        // we need #14072 to make sense of the generics.
         write!(
             w,
-            "{attrs}trait {name}{generics}{where_b} = {bounds};",
-            attrs = render_attributes_in_pre(it, "", cx),
-            name = it.name.unwrap(),
-            generics = t.generics.print(cx),
-            where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline),
-            bounds = bounds(&t.bounds, true, cx),
+            "{}",
+            render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
         )
-        .unwrap();
-    });
-
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
-    // Render any items associated directly to this alias, as otherwise they
-    // won't be visible anywhere in the docs. It would be nice to also show
-    // associated items from the aliased type (see discussion in #32077), but
-    // we need #14072 to make sense of the generics.
-    write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
-        .unwrap();
+    })
 }
 
-fn item_type_alias(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) {
-    wrap_item(w, |w| {
-        write_str(
-            w,
-            format_args!(
+fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        wrap_item(w, |w| {
+            write!(
+                w,
                 "{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
                 attrs = render_attributes_in_pre(it, "", cx),
                 vis = visibility_print_with_space(it, cx),
                 name = it.name.unwrap(),
                 generics = t.generics.print(cx),
-                where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
+                where_clause =
+                    print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(),
                 type_ = t.type_.print(cx),
-            ),
-        );
-    });
+            )
+        })?;
 
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
 
-    if let Some(inner_type) = &t.inner_type {
-        write_section_heading(w, "Aliased Type", "aliased-type", None, "");
+        if let Some(inner_type) = &t.inner_type {
+            write!(w, "{}", write_section_heading("Aliased Type", "aliased-type", None, ""),)?;
 
-        match inner_type {
-            clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => {
-                let variants_iter = || variants.iter().filter(|i| !i.is_stripped());
-                let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
-                let enum_def_id = ty.ty_adt_def().unwrap().did();
+            match inner_type {
+                clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => {
+                    let variants_iter = || variants.iter().filter(|i| !i.is_stripped());
+                    let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity();
+                    let enum_def_id = ty.ty_adt_def().unwrap().did();
 
-                wrap_item(w, |w| {
-                    let variants_len = variants.len();
-                    let variants_count = variants_iter().count();
-                    let has_stripped_entries = variants_len != variants_count;
+                    wrap_item(w, |w| {
+                        let variants_len = variants.len();
+                        let variants_count = variants_iter().count();
+                        let has_stripped_entries = variants_len != variants_count;
 
-                    write_str(w, format_args!("enum {}{}", it.name.unwrap(), t.generics.print(cx)));
-                    render_enum_fields(
-                        w,
-                        cx,
-                        Some(&t.generics),
-                        variants,
-                        variants_count,
-                        has_stripped_entries,
-                        *is_non_exhaustive,
-                        enum_def_id,
-                    )
-                });
-                item_variants(w, cx, it, variants, enum_def_id);
-            }
-            clean::TypeAliasInnerType::Union { fields } => {
-                wrap_item(w, |w| {
-                    let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
-                    let has_stripped_fields = fields.len() != fields_count;
+                        write!(
+                            w,
+                            "enum {}{}{}",
+                            it.name.unwrap(),
+                            t.generics.print(cx),
+                            render_enum_fields(
+                                cx,
+                                Some(&t.generics),
+                                variants,
+                                variants_count,
+                                has_stripped_entries,
+                                *is_non_exhaustive,
+                                enum_def_id,
+                            )
+                        )
+                    })?;
+                    write!(w, "{}", item_variants(cx, it, variants, enum_def_id))?;
+                }
+                clean::TypeAliasInnerType::Union { fields } => {
+                    wrap_item(w, |w| {
+                        let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
+                        let has_stripped_fields = fields.len() != fields_count;
 
-                    write_str(
-                        w,
-                        format_args!("union {}{}", it.name.unwrap(), t.generics.print(cx)),
-                    );
-                    render_struct_fields(
-                        w,
-                        Some(&t.generics),
-                        None,
-                        fields,
-                        "",
-                        true,
-                        has_stripped_fields,
-                        cx,
-                    );
-                });
-                item_fields(w, cx, it, fields, None);
-            }
-            clean::TypeAliasInnerType::Struct { ctor_kind, fields } => {
-                wrap_item(w, |w| {
-                    let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
-                    let has_stripped_fields = fields.len() != fields_count;
+                        write!(
+                            w,
+                            "union {}{}{}",
+                            it.name.unwrap(),
+                            t.generics.print(cx),
+                            render_struct_fields(
+                                Some(&t.generics),
+                                None,
+                                fields,
+                                "",
+                                true,
+                                has_stripped_fields,
+                                cx,
+                            ),
+                        )
+                    })?;
+                    write!(w, "{}", item_fields(cx, it, fields, None))?;
+                }
+                clean::TypeAliasInnerType::Struct { ctor_kind, fields } => {
+                    wrap_item(w, |w| {
+                        let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
+                        let has_stripped_fields = fields.len() != fields_count;
 
-                    write_str(
-                        w,
-                        format_args!("struct {}{}", it.name.unwrap(), t.generics.print(cx)),
-                    );
-                    render_struct_fields(
-                        w,
-                        Some(&t.generics),
-                        *ctor_kind,
-                        fields,
-                        "",
-                        true,
-                        has_stripped_fields,
-                        cx,
-                    );
-                });
-                item_fields(w, cx, it, fields, None);
+                        write!(
+                            w,
+                            "struct {}{}{}",
+                            it.name.unwrap(),
+                            t.generics.print(cx),
+                            render_struct_fields(
+                                Some(&t.generics),
+                                *ctor_kind,
+                                fields,
+                                "",
+                                true,
+                                has_stripped_fields,
+                                cx,
+                            ),
+                        )
+                    })?;
+                    write!(w, "{}", item_fields(cx, it, fields, None))?;
+                }
             }
         }
-    }
 
-    let def_id = it.item_id.expect_def_id();
-    // Render any items associated directly to this alias, as otherwise they
-    // won't be visible anywhere in the docs. It would be nice to also show
-    // associated items from the aliased type (see discussion in #32077), but
-    // we need #14072 to make sense of the generics.
-    write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
-    write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
-
-    // [RUSTDOCIMPL] type.impl
-    //
-    // Include type definitions from the alias target type.
-    //
-    // Earlier versions of this code worked by having `render_assoc_items`
-    // include this data directly. That generates *O*`(types*impls)` of HTML
-    // text, and some real crates have a lot of types and impls.
-    //
-    // To create the same UX without generating half a gigabyte of HTML for a
-    // crate that only contains 20 megabytes of actual documentation[^115718],
-    // rustdoc stashes these type-alias-inlined docs in a [JSONP]
-    // "database-lite". The file itself is generated in `write_shared.rs`,
-    // and hooks into functions provided by `main.js`.
-    //
-    // The format of `trait.impl` and `type.impl` JS files are superficially
-    // similar. Each line, except the JSONP wrapper itself, belongs to a crate,
-    // and they are otherwise separate (rustdoc should be idempotent). The
-    // "meat" of the file is HTML strings, so the frontend code is very simple.
-    // Links are relative to the doc root, though, so the frontend needs to fix
-    // that up, and inlined docs can reuse these files.
-    //
-    // However, there are a few differences, caused by the sophisticated
-    // features that type aliases have. Consider this crate graph:
-    //
-    // ```text
-    //  ---------------------------------
-    //  | crate A: struct Foo<T>        |
-    //  |          type Bar = Foo<i32>  |
-    //  |          impl X for Foo<i8>   |
-    //  |          impl Y for Foo<i32>  |
-    //  ---------------------------------
-    //      |
-    //  ----------------------------------
-    //  | crate B: type Baz = A::Foo<i8> |
-    //  |          type Xyy = A::Foo<i8> |
-    //  |          impl Z for Xyy        |
-    //  ----------------------------------
-    // ```
-    //
-    // The type.impl/A/struct.Foo.js JS file has a structure kinda like this:
-    //
-    // ```js
-    // JSONP({
-    // "A": [["impl Y for Foo<i32>", "Y", "A::Bar"]],
-    // "B": [["impl X for Foo<i8>", "X", "B::Baz", "B::Xyy"], ["impl Z for Xyy", "Z", "B::Baz"]],
-    // });
-    // ```
-    //
-    // When the type.impl file is loaded, only the current crate's docs are
-    // actually used. The main reason to bundle them together is that there's
-    // enough duplication in them for DEFLATE to remove the redundancy.
-    //
-    // The contents of a crate are a list of impl blocks, themselves
-    // represented as lists. The first item in the sublist is the HTML block,
-    // the second item is the name of the trait (which goes in the sidebar),
-    // and all others are the names of type aliases that successfully match.
-    //
-    // This way:
-    //
-    // - There's no need to generate these files for types that have no aliases
-    //   in the current crate. If a dependent crate makes a type alias, it'll
-    //   take care of generating its own docs.
-    // - There's no need to reimplement parts of the type checker in
-    //   JavaScript. The Rust backend does the checking, and includes its
-    //   results in the file.
-    // - Docs defined directly on the type alias are dropped directly in the
-    //   HTML by `render_assoc_items`, and are accessible without JavaScript.
-    //   The JSONP file will not list impl items that are known to be part
-    //   of the main HTML file already.
-    //
-    // [JSONP]: https://en.wikipedia.org/wiki/JSONP
-    // [^115718]: https://github.com/rust-lang/rust/issues/115718
-    let cache = &cx.shared.cache;
-    if let Some(target_did) = t.type_.def_id(cache) &&
-        let get_extern = { || cache.external_paths.get(&target_did) } &&
-        let Some(&(ref target_fqp, target_type)) = cache.paths.get(&target_did).or_else(get_extern) &&
-        target_type.is_adt() && // primitives cannot be inlined
-        let Some(self_did) = it.item_id.as_def_id() &&
-        let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) } &&
-        let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local)
-    {
-        let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..")
-            .take(cx.current.len())
-            .chain(std::iter::once("type.impl"))
-            .collect();
-        js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied());
-        js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap()));
-        let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f));
-        write_str(
+        let def_id = it.item_id.expect_def_id();
+        // Render any items associated directly to this alias, as otherwise they
+        // won't be visible anywhere in the docs. It would be nice to also show
+        // associated items from the aliased type (see discussion in #32077), but
+        // we need #14072 to make sense of the generics.
+        write!(
             w,
-            format_args!(
+            "{}{}",
+            render_assoc_items(cx, it, def_id, AssocItemRender::All),
+            document_type_layout(cx, def_id)
+        )?;
+
+        // [RUSTDOCIMPL] type.impl
+        //
+        // Include type definitions from the alias target type.
+        //
+        // Earlier versions of this code worked by having `render_assoc_items`
+        // include this data directly. That generates *O*`(types*impls)` of HTML
+        // text, and some real crates have a lot of types and impls.
+        //
+        // To create the same UX without generating half a gigabyte of HTML for a
+        // crate that only contains 20 megabytes of actual documentation[^115718],
+        // rustdoc stashes these type-alias-inlined docs in a [JSONP]
+        // "database-lite". The file itself is generated in `write_shared.rs`,
+        // and hooks into functions provided by `main.js`.
+        //
+        // The format of `trait.impl` and `type.impl` JS files are superficially
+        // similar. Each line, except the JSONP wrapper itself, belongs to a crate,
+        // and they are otherwise separate (rustdoc should be idempotent). The
+        // "meat" of the file is HTML strings, so the frontend code is very simple.
+        // Links are relative to the doc root, though, so the frontend needs to fix
+        // that up, and inlined docs can reuse these files.
+        //
+        // However, there are a few differences, caused by the sophisticated
+        // features that type aliases have. Consider this crate graph:
+        //
+        // ```text
+        //  ---------------------------------
+        //  | crate A: struct Foo<T>        |
+        //  |          type Bar = Foo<i32>  |
+        //  |          impl X for Foo<i8>   |
+        //  |          impl Y for Foo<i32>  |
+        //  ---------------------------------
+        //      |
+        //  ----------------------------------
+        //  | crate B: type Baz = A::Foo<i8> |
+        //  |          type Xyy = A::Foo<i8> |
+        //  |          impl Z for Xyy        |
+        //  ----------------------------------
+        // ```
+        //
+        // The type.impl/A/struct.Foo.js JS file has a structure kinda like this:
+        //
+        // ```js
+        // JSONP({
+        // "A": [["impl Y for Foo<i32>", "Y", "A::Bar"]],
+        // "B": [["impl X for Foo<i8>", "X", "B::Baz", "B::Xyy"], ["impl Z for Xyy", "Z", "B::Baz"]],
+        // });
+        // ```
+        //
+        // When the type.impl file is loaded, only the current crate's docs are
+        // actually used. The main reason to bundle them together is that there's
+        // enough duplication in them for DEFLATE to remove the redundancy.
+        //
+        // The contents of a crate are a list of impl blocks, themselves
+        // represented as lists. The first item in the sublist is the HTML block,
+        // the second item is the name of the trait (which goes in the sidebar),
+        // and all others are the names of type aliases that successfully match.
+        //
+        // This way:
+        //
+        // - There's no need to generate these files for types that have no aliases
+        //   in the current crate. If a dependent crate makes a type alias, it'll
+        //   take care of generating its own docs.
+        // - There's no need to reimplement parts of the type checker in
+        //   JavaScript. The Rust backend does the checking, and includes its
+        //   results in the file.
+        // - Docs defined directly on the type alias are dropped directly in the
+        //   HTML by `render_assoc_items`, and are accessible without JavaScript.
+        //   The JSONP file will not list impl items that are known to be part
+        //   of the main HTML file already.
+        //
+        // [JSONP]: https://en.wikipedia.org/wiki/JSONP
+        // [^115718]: https://github.com/rust-lang/rust/issues/115718
+        let cache = &cx.shared.cache;
+        if let Some(target_did) = t.type_.def_id(cache)
+            && let get_extern = { || cache.external_paths.get(&target_did) }
+            && let Some(&(ref target_fqp, target_type)) =
+                cache.paths.get(&target_did).or_else(get_extern)
+            && target_type.is_adt() // primitives cannot be inlined
+            && let Some(self_did) = it.item_id.as_def_id()
+            && let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) }
+            && let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local)
+        {
+            let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..")
+                .take(cx.current.len())
+                .chain(std::iter::once("type.impl"))
+                .collect();
+            js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied());
+            js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap()));
+            let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f));
+            write!(
+                w,
                 "<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>",
-                src = js_src_path.finish()
-            ),
-        );
-    }
+                src = js_src_path.finish(),
+            )?;
+        }
+        Ok(())
+    })
 }
 
-fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
+fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display {
     item_template!(
         #[template(path = "item_union.html")]
         struct ItemUnion<'a, 'cx> {
@@ -1419,35 +1475,20 @@ fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
     );
 
     impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
-        fn render_union<'b>(&'b self) -> impl Display + Captures<'a> + 'b + Captures<'cx> {
-            fmt::from_fn(move |f| {
-                let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx);
-                write!(f, "{v}")
-            })
+        fn render_union(&self) -> impl Display {
+            render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx)
         }
 
-        fn document_field<'b>(
-            &'b self,
-            field: &'a clean::Item,
-        ) -> impl Display + Captures<'a> + 'b + Captures<'cx> {
-            fmt::from_fn(move |f| {
-                let v = document(self.cx, field, Some(self.it), HeadingOffset::H3);
-                write!(f, "{v}")
-            })
+        fn document_field(&self, field: &'a clean::Item) -> impl Display {
+            document(self.cx, field, Some(self.it), HeadingOffset::H3)
         }
 
         fn stability_field(&self, field: &clean::Item) -> Option<String> {
             field.stability_class(self.cx.tcx())
         }
 
-        fn print_ty<'b>(
-            &'b self,
-            ty: &'a clean::Type,
-        ) -> impl Display + Captures<'a> + 'b + Captures<'cx> {
-            fmt::from_fn(move |f| {
-                let v = ty.print(self.cx);
-                write!(f, "{v}")
-            })
+        fn print_ty(&self, ty: &'a clean::Type) -> impl Display {
+            ty.print(self.cx)
         }
 
         fn fields_iter(
@@ -1464,13 +1505,13 @@ fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
         }
     }
 
-    ItemUnion { cx, it, s }.render_into(w).unwrap();
+    fmt::from_fn(|w| {
+        ItemUnion { cx, it, s }.render_into(w).unwrap();
+        Ok(())
+    })
 }
 
-fn print_tuple_struct_fields<'a, 'cx: 'a>(
-    cx: &'a Context<'cx>,
-    s: &'a [clean::Item],
-) -> impl Display + 'a + Captures<'cx> {
+fn print_tuple_struct_fields(cx: &Context<'_>, s: &[clean::Item]) -> impl Display {
     fmt::from_fn(|f| {
         if !s.is_empty()
             && s.iter().all(|field| {
@@ -1492,40 +1533,42 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
     })
 }
 
-fn item_enum(w: &mut String, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
-    let count_variants = e.variants().count();
-    wrap_item(w, |w| {
-        render_attributes_in_code(w, it, cx);
-        write_str(
-            w,
-            format_args!(
-                "{}enum {}{}",
+fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        let count_variants = e.variants().count();
+        wrap_item(w, |w| {
+            render_attributes_in_code(w, it, cx);
+            write!(
+                w,
+                "{}enum {}{}{}",
                 visibility_print_with_space(it, cx),
                 it.name.unwrap(),
                 e.generics.print(cx),
-            ),
-        );
-
-        render_enum_fields(
-            w,
-            cx,
-            Some(&e.generics),
-            &e.variants,
-            count_variants,
-            e.has_stripped_entries(),
-            it.is_non_exhaustive(),
-            it.def_id().unwrap(),
-        );
-    });
+                render_enum_fields(
+                    cx,
+                    Some(&e.generics),
+                    &e.variants,
+                    count_variants,
+                    e.has_stripped_entries(),
+                    it.is_non_exhaustive(),
+                    it.def_id().unwrap(),
+                ),
+            )
+        })?;
 
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
 
-    if count_variants != 0 {
-        item_variants(w, cx, it, &e.variants, it.def_id().unwrap());
-    }
-    let def_id = it.item_id.expect_def_id();
-    write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
-    write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
+        if count_variants != 0 {
+            write!(w, "{}", item_variants(cx, it, &e.variants, it.def_id().unwrap()))?;
+        }
+        let def_id = it.item_id.expect_def_id();
+        write!(
+            w,
+            "{}{}",
+            render_assoc_items(cx, it, def_id, AssocItemRender::All),
+            document_type_layout(cx, def_id)
+        )
+    })
 }
 
 /// It'll return false if any variant is not a C-like variant. Otherwise it'll return true if at
@@ -1554,32 +1597,33 @@ fn should_show_enum_discriminant(
 }
 
 fn display_c_like_variant(
-    w: &mut String,
     cx: &Context<'_>,
     item: &clean::Item,
     variant: &clean::Variant,
     index: VariantIdx,
     should_show_enum_discriminant: bool,
     enum_def_id: DefId,
-) {
-    let name = item.name.unwrap();
-    if let Some(ref value) = variant.discriminant {
-        write_str(w, format_args!("{} = {}", name.as_str(), value.value(cx.tcx(), true)));
-    } else if should_show_enum_discriminant {
-        let adt_def = cx.tcx().adt_def(enum_def_id);
-        let discr = adt_def.discriminant_for_variant(cx.tcx(), index);
-        if discr.ty.is_signed() {
-            write_str(w, format_args!("{} = {}", name.as_str(), discr.val as i128));
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        let name = item.name.unwrap();
+        if let Some(ref value) = variant.discriminant {
+            write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true))?;
+        } else if should_show_enum_discriminant {
+            let adt_def = cx.tcx().adt_def(enum_def_id);
+            let discr = adt_def.discriminant_for_variant(cx.tcx(), index);
+            if discr.ty.is_signed() {
+                write!(w, "{} = {}", name.as_str(), discr.val as i128)?;
+            } else {
+                write!(w, "{} = {}", name.as_str(), discr.val)?;
+            }
         } else {
-            write_str(w, format_args!("{} = {}", name.as_str(), discr.val));
+            write!(w, "{name}")?;
         }
-    } else {
-        w.push_str(name.as_str());
-    }
+        Ok(())
+    })
 }
 
 fn render_enum_fields(
-    mut w: &mut String,
     cx: &Context<'_>,
     g: Option<&clean::Generics>,
     variants: &IndexVec<VariantIdx, clean::Item>,
@@ -1587,422 +1631,452 @@ fn render_enum_fields(
     has_stripped_entries: bool,
     is_non_exhaustive: bool,
     enum_def_id: DefId,
-) {
-    let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants);
-    if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) {
-        // If there wasn't a `where` clause, we add a whitespace.
-        w.push_str(" ");
-    }
-
-    let variants_stripped = has_stripped_entries;
-    if count_variants == 0 && !variants_stripped {
-        w.push_str("{}");
-    } else {
-        w.push_str("{\n");
-        let toggle = should_hide_fields(count_variants);
-        if toggle {
-            toggle_open(&mut w, format_args!("{count_variants} variants"));
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        let should_show_enum_discriminant =
+            should_show_enum_discriminant(cx, enum_def_id, variants);
+        if let Some(generics) = g
+            && let Some(where_clause) = print_where_clause(generics, cx, 0, Ending::Newline)
+        {
+            write!(w, "{where_clause}")?;
+        } else {
+            // If there wasn't a `where` clause, we add a whitespace.
+            w.write_char(' ')?;
         }
-        const TAB: &str = "    ";
-        for (index, v) in variants.iter_enumerated() {
-            if v.is_stripped() {
-                continue;
+
+        let variants_stripped = has_stripped_entries;
+        if count_variants == 0 && !variants_stripped {
+            w.write_str("{}")
+        } else {
+            w.write_str("{\n")?;
+            let toggle = should_hide_fields(count_variants);
+            if toggle {
+                toggle_open(&mut *w, format_args!("{count_variants} variants"));
             }
-            w.push_str(TAB);
-            match v.kind {
-                clean::VariantItem(ref var) => match var.kind {
-                    clean::VariantKind::CLike => display_c_like_variant(
-                        w,
-                        cx,
-                        v,
-                        var,
-                        index,
-                        should_show_enum_discriminant,
-                        enum_def_id,
-                    ),
-                    clean::VariantKind::Tuple(ref s) => {
-                        write_str(
-                            w,
-                            format_args!(
-                                "{}({})",
-                                v.name.unwrap(),
-                                print_tuple_struct_fields(cx, s)
-                            ),
-                        );
-                    }
-                    clean::VariantKind::Struct(ref s) => {
-                        render_struct(w, v, None, None, &s.fields, TAB, false, cx);
-                    }
-                },
-                _ => unreachable!(),
+            const TAB: &str = "    ";
+            for (index, v) in variants.iter_enumerated() {
+                if v.is_stripped() {
+                    continue;
+                }
+                w.write_str(TAB)?;
+                match v.kind {
+                    clean::VariantItem(ref var) => match var.kind {
+                        clean::VariantKind::CLike => {
+                            write!(
+                                w,
+                                "{}",
+                                display_c_like_variant(
+                                    cx,
+                                    v,
+                                    var,
+                                    index,
+                                    should_show_enum_discriminant,
+                                    enum_def_id,
+                                )
+                            )?;
+                        }
+                        clean::VariantKind::Tuple(ref s) => {
+                            write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s))?;
+                        }
+                        clean::VariantKind::Struct(ref s) => {
+                            write!(
+                                w,
+                                "{}",
+                                render_struct(v, None, None, &s.fields, TAB, false, cx)
+                            )?;
+                        }
+                    },
+                    _ => unreachable!(),
+                }
+                w.write_str(",\n")?;
             }
-            w.push_str(",\n");
-        }
 
-        if variants_stripped && !is_non_exhaustive {
-            w.push_str("    <span class=\"comment\">// some variants omitted</span>\n");
-        }
-        if toggle {
-            toggle_close(&mut w);
+            if variants_stripped && !is_non_exhaustive {
+                w.write_str("    <span class=\"comment\">// some variants omitted</span>\n")?;
+            }
+            if toggle {
+                toggle_close(&mut *w);
+            }
+            w.write_str("}")
         }
-        w.push_str("}");
-    }
+    })
 }
 
 fn item_variants(
-    w: &mut String,
     cx: &Context<'_>,
     it: &clean::Item,
     variants: &IndexVec<VariantIdx, clean::Item>,
     enum_def_id: DefId,
-) {
-    let tcx = cx.tcx();
-    write_section_heading(
-        w,
-        &format!("Variants{}", document_non_exhaustive_header(it)),
-        "variants",
-        Some("variants"),
-        format!("{}<div class=\"variants\">", document_non_exhaustive(it)),
-    );
-
-    let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants);
-    for (index, variant) in variants.iter_enumerated() {
-        if variant.is_stripped() {
-            continue;
-        }
-        let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
-        write_str(
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        let tcx = cx.tcx();
+        write!(
             w,
-            format_args!(
-                "<section id=\"{id}\" class=\"variant\">\
-                <a href=\"#{id}\" class=\"anchor\">ยง</a>"
+            "{}",
+            write_section_heading(
+                &format!("Variants{}", document_non_exhaustive_header(it)),
+                "variants",
+                Some("variants"),
+                format!("{}<div class=\"variants\">", document_non_exhaustive(it)),
             ),
-        );
-        render_stability_since_raw_with_extra(
-            w,
-            variant.stable_since(tcx),
-            variant.const_stability(tcx),
-            " rightside",
-        );
-        w.push_str("<h3 class=\"code-header\">");
-        if let clean::VariantItem(ref var) = variant.kind
-            && let clean::VariantKind::CLike = var.kind
-        {
-            display_c_like_variant(
+        )?;
+
+        let should_show_enum_discriminant =
+            should_show_enum_discriminant(cx, enum_def_id, variants);
+        for (index, variant) in variants.iter_enumerated() {
+            if variant.is_stripped() {
+                continue;
+            }
+            let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
+            write!(
                 w,
-                cx,
-                variant,
-                var,
-                index,
-                should_show_enum_discriminant,
-                enum_def_id,
-            );
-        } else {
-            w.push_str(variant.name.unwrap().as_str());
-        }
+                "<section id=\"{id}\" class=\"variant\">\
+                    <a href=\"#{id}\" class=\"anchor\">ยง</a>\
+                    {}\
+                    <h3 class=\"code-header\">",
+                render_stability_since_raw_with_extra(
+                    variant.stable_since(tcx),
+                    variant.const_stability(tcx),
+                    " rightside",
+                )
+                .maybe_display()
+            )?;
+            if let clean::VariantItem(ref var) = variant.kind
+                && let clean::VariantKind::CLike = var.kind
+            {
+                write!(
+                    w,
+                    "{}",
+                    display_c_like_variant(
+                        cx,
+                        variant,
+                        var,
+                        index,
+                        should_show_enum_discriminant,
+                        enum_def_id,
+                    )
+                )?;
+            } else {
+                w.write_str(variant.name.unwrap().as_str())?;
+            }
 
-        let clean::VariantItem(variant_data) = &variant.kind else { unreachable!() };
+            let clean::VariantItem(variant_data) = &variant.kind else { unreachable!() };
 
-        if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
-            write_str(w, format_args!("({})", print_tuple_struct_fields(cx, s)));
-        }
-        w.push_str("</h3></section>");
+            if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
+                write!(w, "({})", print_tuple_struct_fields(cx, s))?;
+            }
+            w.write_str("</h3></section>")?;
 
-        write_str(w, format_args!("{}", document(cx, variant, Some(it), HeadingOffset::H4)));
+            write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4))?;
 
-        let heading_and_fields = match &variant_data.kind {
-            clean::VariantKind::Struct(s) => {
-                // If there is no field to display, no need to add the heading.
-                if s.fields.iter().any(|f| !f.is_doc_hidden()) {
-                    Some(("Fields", &s.fields))
-                } else {
-                    None
+            let heading_and_fields = match &variant_data.kind {
+                clean::VariantKind::Struct(s) => {
+                    // If there is no field to display, no need to add the heading.
+                    if s.fields.iter().any(|f| !f.is_doc_hidden()) {
+                        Some(("Fields", &s.fields))
+                    } else {
+                        None
+                    }
                 }
-            }
-            clean::VariantKind::Tuple(fields) => {
-                // Documentation on tuple variant fields is rare, so to reduce noise we only emit
-                // the section if at least one field is documented.
-                if fields.iter().any(|f| !f.doc_value().is_empty()) {
-                    Some(("Tuple Fields", fields))
-                } else {
-                    None
+                clean::VariantKind::Tuple(fields) => {
+                    // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+                    // the section if at least one field is documented.
+                    if fields.iter().any(|f| !f.doc_value().is_empty()) {
+                        Some(("Tuple Fields", fields))
+                    } else {
+                        None
+                    }
                 }
-            }
-            clean::VariantKind::CLike => None,
-        };
+                clean::VariantKind::CLike => None,
+            };
 
-        if let Some((heading, fields)) = heading_and_fields {
-            let variant_id =
-                cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
-            write_str(
-                w,
-                format_args!(
+            if let Some((heading, fields)) = heading_and_fields {
+                let variant_id =
+                    cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
+                write!(
+                    w,
                     "<div class=\"sub-variant\" id=\"{variant_id}\">\
                         <h4>{heading}</h4>\
                         {}",
                     document_non_exhaustive(variant)
-                ),
-            );
-            for field in fields {
-                match field.kind {
-                    clean::StrippedItem(box clean::StructFieldItem(_)) => {}
-                    clean::StructFieldItem(ref ty) => {
-                        let id = cx.derive_id(format!(
-                            "variant.{}.field.{}",
-                            variant.name.unwrap(),
-                            field.name.unwrap()
-                        ));
-                        write_str(
-                            w,
-                            format_args!(
+                )?;
+                for field in fields {
+                    match field.kind {
+                        clean::StrippedItem(box clean::StructFieldItem(_)) => {}
+                        clean::StructFieldItem(ref ty) => {
+                            let id = cx.derive_id(format!(
+                                "variant.{}.field.{}",
+                                variant.name.unwrap(),
+                                field.name.unwrap()
+                            ));
+                            write!(
+                                w,
                                 "<div class=\"sub-variant-field\">\
                                     <span id=\"{id}\" class=\"section-header\">\
                                         <a href=\"#{id}\" class=\"anchor field\">ยง</a>\
                                         <code>{f}: {t}</code>\
-                                    </span>",
+                                    </span>\
+                                    {doc}\
+                                </div>",
                                 f = field.name.unwrap(),
                                 t = ty.print(cx),
-                            ),
-                        );
-                        write_str(
-                            w,
-                            format_args!(
-                                "{}</div>",
-                                document(cx, field, Some(variant), HeadingOffset::H5),
-                            ),
-                        );
+                                doc = document(cx, field, Some(variant), HeadingOffset::H5),
+                            )?;
+                        }
+                        _ => unreachable!(),
                     }
-                    _ => unreachable!(),
                 }
+                w.write_str("</div>")?;
             }
-            w.push_str("</div>");
         }
-    }
-    write_str(w, format_args!("</div>"));
+        w.write_str("</div>")
+    })
 }
 
-fn item_macro(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
-    wrap_item(w, |w| {
-        // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
-        if !t.macro_rules {
-            write_str(w, format_args!("{}", visibility_print_with_space(it, cx)));
-        }
-        write_str(w, format_args!("{}", Escape(&t.source)));
-    });
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+fn item_macro(cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        wrap_item(w, |w| {
+            // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
+            if !t.macro_rules {
+                write!(w, "{}", visibility_print_with_space(it, cx))?;
+            }
+            write!(w, "{}", Escape(&t.source))
+        })?;
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+    })
 }
 
-fn item_proc_macro(
-    w: &mut impl fmt::Write,
-    cx: &Context<'_>,
-    it: &clean::Item,
-    m: &clean::ProcMacro,
-) {
-    wrap_item(w, |buffer| {
-        let name = it.name.expect("proc-macros always have names");
-        match m.kind {
-            MacroKind::Bang => {
-                write!(buffer, "{name}!() {{ <span class=\"comment\">/* proc-macro */</span> }}")
-                    .unwrap();
-            }
-            MacroKind::Attr => {
-                write!(buffer, "#[{name}]").unwrap();
-            }
-            MacroKind::Derive => {
-                write!(buffer, "#[derive({name})]").unwrap();
-                if !m.helpers.is_empty() {
-                    buffer
-                        .write_str(
+fn item_proc_macro(cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        wrap_item(w, |w| {
+            let name = it.name.expect("proc-macros always have names");
+            match m.kind {
+                MacroKind::Bang => {
+                    write!(w, "{name}!() {{ <span class=\"comment\">/* proc-macro */</span> }}")?;
+                }
+                MacroKind::Attr => {
+                    write!(w, "#[{name}]")?;
+                }
+                MacroKind::Derive => {
+                    write!(w, "#[derive({name})]")?;
+                    if !m.helpers.is_empty() {
+                        w.write_str(
                             "\n{\n    \
-                        <span class=\"comment\">// Attributes available to this derive:</span>\n",
-                        )
-                        .unwrap();
-                    for attr in &m.helpers {
-                        writeln!(buffer, "    #[{attr}]").unwrap();
+                            <span class=\"comment\">// Attributes available to this derive:</span>\n",
+                        )?;
+                        for attr in &m.helpers {
+                            writeln!(w, "    #[{attr}]")?;
+                        }
+                        w.write_str("}\n")?;
                     }
-                    buffer.write_str("}\n").unwrap();
                 }
             }
-        }
-    });
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
+            Ok(())
+        })?;
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+    })
 }
 
-fn item_primitive(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) {
-    let def_id = it.item_id.expect_def_id();
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
-    if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
-        write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)).unwrap();
-    } else {
-        // We handle the "reference" primitive type on its own because we only want to list
-        // implementations on generic types.
-        let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&cx.shared, it);
-
-        render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl);
-    }
+fn item_primitive(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        let def_id = it.item_id.expect_def_id();
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
+        if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
+            write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All))?;
+        } else {
+            // We handle the "reference" primitive type on its own because we only want to list
+            // implementations on generic types.
+            let (concrete, synthetic, blanket_impl) =
+                get_filtered_impls_for_reference(&cx.shared, it);
+
+            render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl);
+        }
+        Ok(())
+    })
 }
 
 fn item_constant(
-    w: &mut String,
     cx: &Context<'_>,
     it: &clean::Item,
     generics: &clean::Generics,
     ty: &clean::Type,
     c: &clean::ConstantKind,
-) {
-    wrap_item(w, |w| {
-        let tcx = cx.tcx();
-        render_attributes_in_code(w, it, cx);
+) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        wrap_item(w, |w| {
+            let tcx = cx.tcx();
+            render_attributes_in_code(w, it, cx);
 
-        write_str(
-            w,
-            format_args!(
+            write!(
+                w,
                 "{vis}const {name}{generics}: {typ}{where_clause}",
                 vis = visibility_print_with_space(it, cx),
                 name = it.name.unwrap(),
                 generics = generics.print(cx),
                 typ = ty.print(cx),
-                where_clause = print_where_clause(generics, cx, 0, Ending::NoNewline)
-            ),
-        );
+                where_clause =
+                    print_where_clause(generics, cx, 0, Ending::NoNewline).maybe_display(),
+            )?;
 
-        // FIXME: The code below now prints
-        //            ` = _; // 100i32`
-        //        if the expression is
-        //            `50 + 50`
-        //        which looks just wrong.
-        //        Should we print
-        //            ` = 100i32;`
-        //        instead?
-
-        let value = c.value(tcx);
-        let is_literal = c.is_literal(tcx);
-        let expr = c.expr(tcx);
-        if value.is_some() || is_literal {
-            write_str(w, format_args!(" = {expr};", expr = Escape(&expr)));
-        } else {
-            w.push_str(";");
-        }
+            // FIXME: The code below now prints
+            //            ` = _; // 100i32`
+            //        if the expression is
+            //            `50 + 50`
+            //        which looks just wrong.
+            //        Should we print
+            //            ` = 100i32;`
+            //        instead?
+
+            let value = c.value(tcx);
+            let is_literal = c.is_literal(tcx);
+            let expr = c.expr(tcx);
+            if value.is_some() || is_literal {
+                write!(w, " = {expr};", expr = Escape(&expr))?;
+            } else {
+                w.write_str(";")?;
+            }
 
-        if !is_literal {
-            if let Some(value) = &value {
-                let value_lowercase = value.to_lowercase();
-                let expr_lowercase = expr.to_lowercase();
+            if !is_literal {
+                if let Some(value) = &value {
+                    let value_lowercase = value.to_lowercase();
+                    let expr_lowercase = expr.to_lowercase();
 
-                if value_lowercase != expr_lowercase
-                    && value_lowercase.trim_end_matches("i32") != expr_lowercase
-                {
-                    write_str(w, format_args!(" // {value}", value = Escape(value)));
+                    if value_lowercase != expr_lowercase
+                        && value_lowercase.trim_end_matches("i32") != expr_lowercase
+                    {
+                        write!(w, " // {value}", value = Escape(value))?;
+                    }
                 }
             }
-        }
-    });
+            Ok(())
+        })?;
 
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+    })
 }
 
-fn item_struct(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
-    wrap_item(w, |w| {
-        render_attributes_in_code(w, it, cx);
-        render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
-    });
-
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        wrap_item(w, |w| {
+            render_attributes_in_code(w, it, cx);
+            write!(
+                w,
+                "{}",
+                render_struct(it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx)
+            )
+        })?;
 
-    item_fields(w, cx, it, &s.fields, s.ctor_kind);
+        let def_id = it.item_id.expect_def_id();
 
-    let def_id = it.item_id.expect_def_id();
-    write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
-    write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
+        write!(
+            w,
+            "{}{}{}{}",
+            document(cx, it, None, HeadingOffset::H2),
+            item_fields(cx, it, &s.fields, s.ctor_kind),
+            render_assoc_items(cx, it, def_id, AssocItemRender::All),
+            document_type_layout(cx, def_id),
+        )
+    })
 }
 
 fn item_fields(
-    w: &mut String,
     cx: &Context<'_>,
     it: &clean::Item,
     fields: &[clean::Item],
     ctor_kind: Option<CtorKind>,
-) {
-    let mut fields = fields
-        .iter()
-        .filter_map(|f| match f.kind {
-            clean::StructFieldItem(ref ty) => Some((f, ty)),
-            _ => None,
-        })
-        .peekable();
-    if let None | Some(CtorKind::Fn) = ctor_kind {
-        if fields.peek().is_some() {
-            let title = format!(
-                "{}{}",
-                if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
-                document_non_exhaustive_header(it),
-            );
-            write_section_heading(w, &title, "fields", Some("fields"), document_non_exhaustive(it));
-            for (index, (field, ty)) in fields.enumerate() {
-                let field_name =
-                    field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
-                let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField));
-                write_str(
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        let mut fields = fields
+            .iter()
+            .filter_map(|f| match f.kind {
+                clean::StructFieldItem(ref ty) => Some((f, ty)),
+                _ => None,
+            })
+            .peekable();
+        if let None | Some(CtorKind::Fn) = ctor_kind {
+            if fields.peek().is_some() {
+                let title = format!(
+                    "{}{}",
+                    if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
+                    document_non_exhaustive_header(it),
+                );
+                write!(
                     w,
-                    format_args!(
+                    "{}",
+                    write_section_heading(
+                        &title,
+                        "fields",
+                        Some("fields"),
+                        document_non_exhaustive(it)
+                    )
+                )?;
+                for (index, (field, ty)) in fields.enumerate() {
+                    let field_name = field
+                        .name
+                        .map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
+                    let id =
+                        cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField));
+                    write!(
+                        w,
                         "<span id=\"{id}\" class=\"{item_type} section-header\">\
                             <a href=\"#{id}\" class=\"anchor field\">ยง</a>\
                             <code>{field_name}: {ty}</code>\
-                        </span>",
+                        </span>\
+                        {doc}",
                         item_type = ItemType::StructField,
-                        ty = ty.print(cx)
-                    ),
-                );
-                write_str(w, format_args!("{}", document(cx, field, Some(it), HeadingOffset::H3)));
+                        ty = ty.print(cx),
+                        doc = document(cx, field, Some(it), HeadingOffset::H3),
+                    )?;
+                }
             }
         }
-    }
+        Ok(())
+    })
 }
 
 fn item_static(
-    w: &mut impl fmt::Write,
     cx: &Context<'_>,
     it: &clean::Item,
     s: &clean::Static,
     safety: Option<hir::Safety>,
-) {
-    wrap_item(w, |buffer| {
-        render_attributes_in_code(buffer, it, cx);
-        write!(
-            buffer,
-            "{vis}{safe}static {mutability}{name}: {typ}",
-            vis = visibility_print_with_space(it, cx),
-            safe = safety.map(|safe| safe.prefix_str()).unwrap_or(""),
-            mutability = s.mutability.print_with_space(),
-            name = it.name.unwrap(),
-            typ = s.type_.print(cx)
-        )
-        .unwrap();
-    });
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        wrap_item(w, |w| {
+            render_attributes_in_code(w, it, cx);
+            write!(
+                w,
+                "{vis}{safe}static {mutability}{name}: {typ}",
+                vis = visibility_print_with_space(it, cx),
+                safe = safety.map(|safe| safe.prefix_str()).unwrap_or(""),
+                mutability = s.mutability.print_with_space(),
+                name = it.name.unwrap(),
+                typ = s.type_.print(cx)
+            )
+        })?;
 
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
+        write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+    })
 }
 
-fn item_foreign_type(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) {
-    wrap_item(w, |buffer| {
-        buffer.write_str("extern {\n").unwrap();
-        render_attributes_in_code(buffer, it, cx);
+fn item_foreign_type(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
+    fmt::from_fn(|w| {
+        wrap_item(w, |w| {
+            w.write_str("extern {\n")?;
+            render_attributes_in_code(w, it, cx);
+            write!(w, "    {}type {};\n}}", visibility_print_with_space(it, cx), it.name.unwrap(),)
+        })?;
+
         write!(
-            buffer,
-            "    {}type {};\n}}",
-            visibility_print_with_space(it, cx),
-            it.name.unwrap(),
+            w,
+            "{}{}",
+            document(cx, it, None, HeadingOffset::H2),
+            render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
         )
-        .unwrap();
-    });
-
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap();
-    write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
-        .unwrap();
+    })
 }
 
-fn item_keyword(w: &mut String, cx: &Context<'_>, it: &clean::Item) {
-    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
+fn item_keyword(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
+    document(cx, it, None, HeadingOffset::H2)
 }
 
 /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
@@ -2111,18 +2185,14 @@ pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
     s
 }
 
-pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display + '_ {
+pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display {
     fmt::from_fn(move |f| match ty {
         ItemType::Module => write!(f, "{}index.html", ensure_trailing_slash(name)),
         _ => write!(f, "{ty}.{name}.html"),
     })
 }
 
-fn bounds<'a, 'tcx>(
-    bounds: &'a [clean::GenericBound],
-    trait_alias: bool,
-    cx: &'a Context<'tcx>,
-) -> impl Display + 'a + Captures<'tcx> {
+fn bounds(bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> impl Display {
     (!bounds.is_empty())
         .then_some(fmt::from_fn(move |f| {
             let has_lots_of_bounds = bounds.len() > 2;
@@ -2140,14 +2210,15 @@ fn bounds<'a, 'tcx>(
         .maybe_display()
 }
 
-fn wrap_item<W, F>(w: &mut W, f: F)
+fn wrap_item<W, F, T>(w: &mut W, f: F) -> T
 where
     W: fmt::Write,
-    F: FnOnce(&mut W),
+    F: FnOnce(&mut W) -> T,
 {
     write!(w, r#"<pre class="rust item-decl"><code>"#).unwrap();
-    f(w);
+    let res = f(w);
     write!(w, "</code></pre>").unwrap();
+    res
 }
 
 #[derive(PartialEq, Eq)]
@@ -2175,10 +2246,9 @@ fn render_implementor(
     cx: &Context<'_>,
     implementor: &Impl,
     trait_: &clean::Item,
-    w: &mut String,
     implementor_dups: &FxHashMap<Symbol, (DefId, bool)>,
     aliases: &[String],
-) {
+) -> impl fmt::Display {
     // If there's already another implementor that has the same abridged name, use the
     // full path, for example in `std::iter::ExactSizeIterator`
     let use_absolute = match implementor.inner_impl().for_ {
@@ -2191,7 +2261,6 @@ fn render_implementor(
         _ => false,
     };
     render_impl(
-        w,
         cx,
         implementor,
         trait_,
@@ -2205,26 +2274,29 @@ fn render_implementor(
             show_non_assoc_items: false,
             toggle_open_by_default: false,
         },
-    );
+    )
 }
 
-fn render_union<'a, 'cx: 'a>(
-    it: &'a clean::Item,
-    g: Option<&'a clean::Generics>,
-    fields: &'a [clean::Item],
-    cx: &'a Context<'cx>,
-) -> impl Display + 'a + Captures<'cx> {
+fn render_union(
+    it: &clean::Item,
+    g: Option<&clean::Generics>,
+    fields: &[clean::Item],
+    cx: &Context<'_>,
+) -> impl Display {
     fmt::from_fn(move |mut f| {
         write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?;
 
-        let where_displayed = g
-            .map(|g| {
-                let mut buf = g.print(cx).to_string();
-                let where_displayed = print_where_clause_and_check(&mut buf, g, cx);
-                f.write_str(&buf).unwrap();
-                where_displayed
-            })
-            .unwrap_or(false);
+        let where_displayed = if let Some(generics) = g {
+            write!(f, "{}", generics.print(cx))?;
+            if let Some(where_clause) = print_where_clause(generics, cx, 0, Ending::Newline) {
+                write!(f, "{where_clause}")?;
+                true
+            } else {
+                false
+            }
+        } else {
+            false
+        };
 
         // If there wasn't a `where` clause, we add a whitespace.
         if !where_displayed {
@@ -2263,7 +2335,6 @@ fn render_union<'a, 'cx: 'a>(
 }
 
 fn render_struct(
-    w: &mut String,
     it: &clean::Item,
     g: Option<&clean::Generics>,
     ty: Option<CtorKind>,
@@ -2271,33 +2342,35 @@ fn render_struct(
     tab: &str,
     structhead: bool,
     cx: &Context<'_>,
-) {
-    write_str(
-        w,
-        format_args!(
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        write!(
+            w,
             "{}{}{}",
             visibility_print_with_space(it, cx),
             if structhead { "struct " } else { "" },
             it.name.unwrap()
-        ),
-    );
-    if let Some(g) = g {
-        write_str(w, format_args!("{}", g.print(cx)));
-    }
-    render_struct_fields(
-        w,
-        g,
-        ty,
-        fields,
-        tab,
-        structhead,
-        it.has_stripped_entries().unwrap_or(false),
-        cx,
-    )
+        )?;
+        if let Some(g) = g {
+            write!(w, "{}", g.print(cx))?;
+        }
+        write!(
+            w,
+            "{}",
+            render_struct_fields(
+                g,
+                ty,
+                fields,
+                tab,
+                structhead,
+                it.has_stripped_entries().unwrap_or(false),
+                cx,
+            )
+        )
+    })
 }
 
 fn render_struct_fields(
-    mut w: &mut String,
     g: Option<&clean::Generics>,
     ty: Option<CtorKind>,
     fields: &[clean::Item],
@@ -2305,112 +2378,123 @@ fn render_struct_fields(
     structhead: bool,
     has_stripped_entries: bool,
     cx: &Context<'_>,
-) {
-    match ty {
-        None => {
-            let where_displayed =
-                g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false);
+) -> impl fmt::Display {
+    fmt::from_fn(move |w| {
+        match ty {
+            None => {
+                let where_displayed = if let Some(generics) = g
+                    && let Some(where_clause) = print_where_clause(generics, cx, 0, Ending::Newline)
+                {
+                    write!(w, "{where_clause}")?;
+                    true
+                } else {
+                    false
+                };
 
-            // If there wasn't a `where` clause, we add a whitespace.
-            if !where_displayed {
-                w.push_str(" {");
-            } else {
-                w.push_str("{");
-            }
-            let count_fields =
-                fields.iter().filter(|f| matches!(f.kind, clean::StructFieldItem(..))).count();
-            let has_visible_fields = count_fields > 0;
-            let toggle = should_hide_fields(count_fields);
-            if toggle {
-                toggle_open(&mut w, format_args!("{count_fields} fields"));
-            }
-            for field in fields {
-                if let clean::StructFieldItem(ref ty) = field.kind {
-                    write_str(
-                        w,
-                        format_args!(
+                // If there wasn't a `where` clause, we add a whitespace.
+                if !where_displayed {
+                    w.write_str(" {")?;
+                } else {
+                    w.write_str("{")?;
+                }
+                let count_fields =
+                    fields.iter().filter(|f| matches!(f.kind, clean::StructFieldItem(..))).count();
+                let has_visible_fields = count_fields > 0;
+                let toggle = should_hide_fields(count_fields);
+                if toggle {
+                    toggle_open(&mut *w, format_args!("{count_fields} fields"));
+                }
+                for field in fields {
+                    if let clean::StructFieldItem(ref ty) = field.kind {
+                        write!(
+                            w,
                             "\n{tab}    {vis}{name}: {ty},",
                             vis = visibility_print_with_space(field, cx),
                             name = field.name.unwrap(),
                             ty = ty.print(cx)
-                        ),
-                    );
+                        )?;
+                    }
                 }
-            }
 
-            if has_visible_fields {
-                if has_stripped_entries {
-                    write_str(
-                        w,
-                        format_args!(
+                if has_visible_fields {
+                    if has_stripped_entries {
+                        write!(
+                            w,
                             "\n{tab}    <span class=\"comment\">/* private fields */</span>"
-                        ),
-                    );
+                        )?;
+                    }
+                    write!(w, "\n{tab}")?;
+                } else if has_stripped_entries {
+                    write!(w, " <span class=\"comment\">/* private fields */</span> ")?;
                 }
-                write_str(w, format_args!("\n{tab}"));
-            } else if has_stripped_entries {
-                write_str(w, format_args!(" <span class=\"comment\">/* private fields */</span> "));
-            }
-            if toggle {
-                toggle_close(&mut w);
+                if toggle {
+                    toggle_close(&mut *w);
+                }
+                w.write_str("}")?;
             }
-            w.push_str("}");
-        }
-        Some(CtorKind::Fn) => {
-            w.push_str("(");
-            if !fields.is_empty()
-                && fields.iter().all(|field| {
-                    matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
-                })
-            {
-                write_str(w, format_args!("<span class=\"comment\">/* private fields */</span>"));
-            } else {
-                for (i, field) in fields.iter().enumerate() {
-                    if i > 0 {
-                        w.push_str(", ");
-                    }
-                    match field.kind {
-                        clean::StrippedItem(box clean::StructFieldItem(..)) => {
-                            write_str(w, format_args!("_"));
+            Some(CtorKind::Fn) => {
+                w.write_str("(")?;
+                if !fields.is_empty()
+                    && fields.iter().all(|field| {
+                        matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
+                    })
+                {
+                    write!(w, "<span class=\"comment\">/* private fields */</span>")?;
+                } else {
+                    for (i, field) in fields.iter().enumerate() {
+                        if i > 0 {
+                            w.write_str(", ")?;
                         }
-                        clean::StructFieldItem(ref ty) => {
-                            write_str(
-                                w,
-                                format_args!(
+                        match field.kind {
+                            clean::StrippedItem(box clean::StructFieldItem(..)) => {
+                                write!(w, "_")?;
+                            }
+                            clean::StructFieldItem(ref ty) => {
+                                write!(
+                                    w,
                                     "{}{}",
                                     visibility_print_with_space(field, cx),
                                     ty.print(cx)
-                                ),
-                            );
+                                )?;
+                            }
+                            _ => unreachable!(),
                         }
-                        _ => unreachable!(),
                     }
                 }
+                w.write_str(")")?;
+                if let Some(g) = g {
+                    write!(
+                        w,
+                        "{}",
+                        print_where_clause(g, cx, 0, Ending::NoNewline).maybe_display()
+                    )?;
+                }
+                // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
+                if structhead {
+                    w.write_str(";")?;
+                }
             }
-            w.push_str(")");
-            if let Some(g) = g {
-                write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline)));
-            }
-            // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
-            if structhead {
-                w.push_str(";");
-            }
-        }
-        Some(CtorKind::Const) => {
-            // Needed for PhantomData.
-            if let Some(g) = g {
-                write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline)));
+            Some(CtorKind::Const) => {
+                // Needed for PhantomData.
+                if let Some(g) = g {
+                    write!(
+                        w,
+                        "{}",
+                        print_where_clause(g, cx, 0, Ending::NoNewline).maybe_display()
+                    )?;
+                }
+                w.write_str(";")?;
             }
-            w.push_str(";");
         }
-    }
+        Ok(())
+    })
 }
 
 fn document_non_exhaustive_header(item: &clean::Item) -> &str {
     if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
 }
 
-fn document_non_exhaustive(item: &clean::Item) -> impl Display + '_ {
+fn document_non_exhaustive(item: &clean::Item) -> impl Display {
     fmt::from_fn(|f| {
         if item.is_non_exhaustive() {
             write!(
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index 0f01db5f6bc..a1ee5c8c548 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -2,7 +2,6 @@ use std::fmt;
 
 use rinja::Template;
 use rustc_abi::{Primitive, TagEncoding, Variants};
-use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::LayoutError;
@@ -26,10 +25,7 @@ struct TypeLayoutSize {
     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> {
+pub(crate) fn document_type_layout(cx: &Context<'_>, ty_def_id: DefId) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         if !cx.shared.show_type_layout {
             return Ok(());
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index a4dec013fc0..b2bbf4614bf 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -153,7 +153,7 @@ fn write_rendered_cross_crate_info(
     include_sources: bool,
 ) -> Result<(), Error> {
     let m = &opt.should_merge;
-    if opt.emit.is_empty() || opt.emit.contains(&EmitType::InvocationSpecific) {
+    if opt.should_emit_crate() {
         if include_sources {
             write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, crates, m)?;
         }
@@ -636,26 +636,22 @@ impl TypeAliasPart {
                         } else {
                             AssocItemLink::Anchor(None)
                         };
-                        let text = {
-                            let mut buf = String::new();
-                            super::render_impl(
-                                &mut buf,
-                                cx,
-                                impl_,
-                                type_alias_item,
-                                assoc_link,
-                                RenderMode::Normal,
-                                None,
-                                &[],
-                                ImplRenderingParameters {
-                                    show_def_docs: true,
-                                    show_default_items: true,
-                                    show_non_assoc_items: true,
-                                    toggle_open_by_default: true,
-                                },
-                            );
-                            buf
-                        };
+                        let text = super::render_impl(
+                            cx,
+                            impl_,
+                            type_alias_item,
+                            assoc_link,
+                            RenderMode::Normal,
+                            None,
+                            &[],
+                            ImplRenderingParameters {
+                                show_def_docs: true,
+                                show_default_items: true,
+                                show_non_assoc_items: true,
+                                toggle_open_by_default: true,
+                            },
+                        )
+                        .to_string();
                         let type_alias_fqp = (*type_alias_fqp).iter().join("::");
                         if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) {
                             ret.last_mut()
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 78c86a27632..cbbd4b01d83 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -333,7 +333,7 @@ pub(crate) fn print_src(
     source_context: &SourceContext<'_>,
 ) {
     let mut lines = s.lines().count();
-    let line_info = if let SourceContext::Embedded(ref info) = source_context {
+    let line_info = if let SourceContext::Embedded(info) = source_context {
         highlight::LineInfo::new_scraped(lines as u32, info.offset as u32)
     } else {
         highlight::LineInfo::new(lines as u32)
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index acea7828e86..1554c045a32 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -123,7 +123,7 @@ declare namespace rustdoc {
      * Same as QueryElement, but bindings and typeFilter support strings
      */
     interface ParserQueryElement {
-        name: string,
+        name: string|null,
         id: number|null,
         fullPath: Array<string>,
         pathWithoutLast: Array<string>,
@@ -131,11 +131,17 @@ declare namespace rustdoc {
         normalizedPathLast: string,
         generics: Array<ParserQueryElement>,
         bindings: Map<string, Array<ParserQueryElement>>,
-        bindingName: {name: string, generics: ParserQueryElement[]}|null,
-        typeFilter: string|null,
+        bindingName: {name: string|null, generics: ParserQueryElement[]}|null,
+        typeFilter: number|string|null,
     }
 
     /**
+     * Same as ParserQueryElement, but all fields are optional.
+     */
+    type ParserQueryElementFields = {
+        [K in keyof ParserQueryElement]?: ParserQueryElement[T]
+    }
+    /**
      * Intermediate parser state. Discarded when parsing is done.
      */
     interface ParserState {
@@ -176,10 +182,11 @@ declare namespace rustdoc {
         name: string,
         normalizedName: string,
         word: string,
+        paramNames: string[],
         parent: ({ty: number, name: string, path: string, exactPath: string}|null|undefined),
         path: string,
         ty: number,
-        type?: FunctionSearchType
+        type: FunctionSearchType | null,
     }
 
     /**
@@ -390,7 +397,7 @@ declare namespace rustdoc {
      */
     type RawSearchIndexCrate = {
     doc: string,
-    a: Object,
+    a: { [key: string]: number[] },
     n: Array<string>,
     t: string,
     D: string,
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index ccbd6811b07..c275127997a 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -638,7 +638,6 @@ function getNextElem(query, parserState, elems, isInGenerics) {
                 getFilteredNextElem(query, parserState, generics, isInGenerics);
                 generics[generics.length - 1].bindingName = makePrimitiveElement("output");
             } else {
-                // @ts-expect-error
                 generics.push(makePrimitiveElement(null, {
                     bindingName: makePrimitiveElement("output"),
                     typeFilter: null,
@@ -791,7 +790,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
         generics: generics.filter(gen => {
             // Syntactically, bindings are parsed as generics,
             // but the query engine treats them differently.
-            if (gen.bindingName !== null) {
+            if (gen.bindingName !== null && gen.bindingName.name !== null) {
                 if (gen.name !== null) {
                     gen.bindingName.generics.unshift(gen);
                 }
@@ -811,8 +810,8 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
 
 /**
  *
- * @param {string} name
- * @param {Object=} extra
+ * @param {string|null} name
+ * @param {rustdoc.ParserQueryElementFields=} extra
  * @returns {rustdoc.ParserQueryElement}
  */
 function makePrimitiveElement(name, extra) {
@@ -1478,73 +1477,61 @@ class DocSearch {
          * Special type name IDs for searching by array.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfArray = this.buildTypeMapIndex("array");
         /**
          * Special type name IDs for searching by slice.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfSlice = this.buildTypeMapIndex("slice");
         /**
          * Special type name IDs for searching by both array and slice (`[]` syntax).
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfArrayOrSlice = this.buildTypeMapIndex("[]");
         /**
          * Special type name IDs for searching by tuple.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfTuple = this.buildTypeMapIndex("tuple");
         /**
          * Special type name IDs for searching by unit.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfUnit = this.buildTypeMapIndex("unit");
         /**
          * Special type name IDs for searching by both tuple and unit (`()` syntax).
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfTupleOrUnit = this.buildTypeMapIndex("()");
         /**
          * Special type name IDs for searching `fn`.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfFn = this.buildTypeMapIndex("fn");
         /**
          * Special type name IDs for searching `fnmut`.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfFnMut = this.buildTypeMapIndex("fnmut");
         /**
          * Special type name IDs for searching `fnonce`.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfFnOnce = this.buildTypeMapIndex("fnonce");
         /**
          * Special type name IDs for searching higher order functions (`->` syntax).
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfHof = this.buildTypeMapIndex("->");
         /**
          * Special type name IDs the output assoc type.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true);
         /**
          * Special type name IDs for searching by reference.
          * @type {number}
          */
-        // @ts-expect-error
         this.typeNameIdOfReference = this.buildTypeMapIndex("reference");
 
         /**
@@ -1586,7 +1573,6 @@ class DocSearch {
         /**
          *  @type {Array<rustdoc.Row>}
          */
-        // @ts-expect-error
         this.searchIndex = this.buildIndex(rawSearchIndex);
     }
 
@@ -1598,10 +1584,16 @@ class DocSearch {
      * done more quickly. Two types with the same name but different item kinds
      * get the same ID.
      *
-     * @param {string} name
+     * @template T extends string
+     * @overload
+     * @param {T} name
      * @param {boolean=} isAssocType - True if this is an assoc type
+     * @returns {T extends "" ? null : number}
+     *
+     * @param {string} name
+     * @param {boolean=} isAssocType
+     * @returns {number | null}
      *
-     * @returns {number?}
      */
     buildTypeMapIndex(name, isAssocType) {
         if (name === "" || name === null) {
@@ -1909,6 +1901,7 @@ class DocSearch {
      * Convert raw search index into in-memory search index.
      *
      * @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
+     * @returns {rustdoc.Row[]}
      */
     buildIndex(rawSearchIndex) {
         /**
@@ -2008,6 +2001,7 @@ class DocSearch {
             return cb;
         };
 
+        /** @type {rustdoc.Row[]} */
         const searchIndex = [];
         let currentIndex = 0;
         let id = 0;
@@ -2108,8 +2102,6 @@ class DocSearch {
             // an array of [(Number) item type,
             //              (String) name]
             const rawPaths = crateCorpus.p;
-            // an array of [(String) alias name
-            //             [Number] index to items]
             const aliases = crateCorpus.a;
             // an array of [(Number) item index,
             //              (String) comma-separated list of function generic param names]
@@ -2232,6 +2224,7 @@ class DocSearch {
                 // object defined above.
                 const itemParentIdx = itemParentIdxDecoder.next();
                 normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, "");
+                /** @type {rustdoc.Row} */
                 const row = {
                     crate,
                     ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
@@ -2274,16 +2267,14 @@ class DocSearch {
                         continue;
                     }
 
-                    // @ts-expect-error
+                    /** @type{number[]} */
                     let currentNameAliases;
                     if (currentCrateAliases.has(alias_name)) {
                         currentNameAliases = currentCrateAliases.get(alias_name);
                     } else {
                         currentNameAliases = [];
-                        // @ts-expect-error
                         currentCrateAliases.set(alias_name, currentNameAliases);
                     }
-                    // @ts-expect-error
                     for (const local_alias of aliases[alias_name]) {
                         currentNameAliases.push(local_alias + currentIndex);
                     }
@@ -2326,15 +2317,13 @@ class DocSearch {
          * @param {rustdoc.ParserQueryElement} elem
          */
         function convertTypeFilterOnElem(elem) {
-            if (elem.typeFilter !== null) {
+            if (typeof elem.typeFilter === "string") {
                 let typeFilter = elem.typeFilter;
                 if (typeFilter === "const") {
                     typeFilter = "constant";
                 }
-                // @ts-expect-error
                 elem.typeFilter = itemTypeFromName(typeFilter);
             } else {
-                // @ts-expect-error
                 elem.typeFilter = NO_TYPE_FILTER;
             }
             for (const elem2 of elem.generics) {
@@ -2407,9 +2396,9 @@ class DocSearch {
                     continue;
                 }
                 if (!foundStopChar) {
-                    let extra = "";
+                    /** @type String[] */
+                    let extra = [];
                     if (isLastElemGeneric(query.elems, parserState)) {
-                        // @ts-expect-error
                         extra = [" after ", ">"];
                     } else if (prevIs(parserState, "\"")) {
                         throw ["Cannot have more than one element if you use quotes"];
@@ -2547,7 +2536,7 @@ class DocSearch {
          * See `buildTypeMapIndex` for more information.
          *
          * @param {rustdoc.QueryElement} elem
-         * @param {boolean} isAssocType
+         * @param {boolean=} isAssocType
          */
         const convertNameToId = (elem, isAssocType) => {
             const loweredName = elem.pathLast.toLowerCase();
@@ -2627,7 +2616,6 @@ class DocSearch {
                 ];
             }
             for (const elem2 of elem.generics) {
-                // @ts-expect-error
                 convertNameToId(elem2);
             }
             elem.bindings = new Map(Array.from(elem.bindings.entries())
@@ -2750,7 +2738,11 @@ class DocSearch {
             return [displayPath, href, `${exactPath}::${name}`];
         };
 
-        // @ts-expect-error
+        /**
+         *
+         * @param {string} path
+         * @returns {string}
+         */
         function pathSplitter(path) {
             const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
             if (tmp.endsWith("<span>")) {
@@ -2763,9 +2755,9 @@ class DocSearch {
          * Add extra data to result objects, and filter items that have been
          * marked for removal.
          *
-         * @param {[rustdoc.ResultObject]} results
+         * @param {rustdoc.ResultObject[]} results
          * @param {"sig"|"elems"|"returned"|null} typeInfo
-         * @returns {[rustdoc.ResultObject]}
+         * @returns {rustdoc.ResultObject[]}
          */
         const transformResults = (results, typeInfo) => {
             const duplicates = new Set();
@@ -2840,7 +2832,7 @@ class DocSearch {
             }
             let fnInputs = null;
             let fnOutput = null;
-            // @ts-expect-error
+            /** @type {Map<number, number> | null} */
             let mgens = null;
             if (typeInfo !== "elems" && typeInfo !== "returned") {
                 fnInputs = unifyFunctionTypes(
@@ -3053,7 +3045,6 @@ class DocSearch {
                             writeFn(nested, result);
                         }
                         return;
-                    // @ts-expect-error
                     } else if (mgens) {
                         for (const [queryId, fnId] of mgens) {
                             if (fnId === fnType.id) {
@@ -3069,7 +3060,7 @@ class DocSearch {
                         name: fnParamNames[-1 - fnType.id],
                         highlighted: !!fnType.highlighted,
                     }, result);
-                    // @ts-expect-error
+                    /** @type{string[]} */
                     const where = [];
                     onEachBtwn(
                         fnType.generics,
@@ -3079,7 +3070,6 @@ class DocSearch {
                         () => pushText({ name: " + ", highlighted: false }, where),
                     );
                     if (where.length > 0) {
-                        // @ts-expect-error
                         whereClause.set(fnParamNames[-1 - fnType.id], where);
                     }
                 } else {
@@ -3181,7 +3171,7 @@ class DocSearch {
          * @param {rustdoc.Results} results
          * @param {"sig"|"elems"|"returned"|null} typeInfo
          * @param {string} preferredCrate
-         * @returns {Promise<[rustdoc.ResultObject]>}
+         * @returns {Promise<rustdoc.ResultObject[]>}
          */
         const sortResults = async(results, typeInfo, preferredCrate) => {
             const userQuery = parsedQuery.userQuery;
@@ -3337,7 +3327,6 @@ class DocSearch {
                 return 0;
             });
 
-            // @ts-expect-error
             return transformResults(result_list, typeInfo);
         };