about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2024-02-15 20:41:20 +0100
committerLeón Orell Valerian Liehr <me@fmease.dev>2024-02-16 21:29:16 +0100
commit5fbb1b2f4dd858f21da7ba56f9e5011b43a0af4b (patch)
tree53af4956423d89065f3511fe040f1f490d4eb3b9
parent0a5b998c57a8681acc13206b5917340b053b3a30 (diff)
downloadrust-5fbb1b2f4dd858f21da7ba56f9e5011b43a0af4b.tar.gz
rust-5fbb1b2f4dd858f21da7ba56f9e5011b43a0af4b.zip
rustdoc: fix and refactor HTML rendering a bit
-rw-r--r--src/librustdoc/html/format.rs454
-rw-r--r--tests/rustdoc/bounds.rs (renamed from tests/rustdoc/bounds-in-multiple-parts.rs)12
-rw-r--r--tests/rustdoc/const-generics/generic_const_exprs.rs2
3 files changed, 186 insertions, 282 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 4ba1665bdc9..bb68c84f529 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1,6 +1,6 @@
 //! HTML formatting module
 //!
-//! This module contains a large number of `fmt::Display` implementations for
+//! This module contains a large number of `Display` implementations for
 //! various types in `rustdoc::clean`.
 //!
 //! These implementations all emit HTML. As an internal implementation detail,
@@ -9,7 +9,7 @@
 
 use std::borrow::Cow;
 use std::cell::Cell;
-use std::fmt::{self, Write};
+use std::fmt::{self, Display, Write};
 use std::iter::{self, once};
 
 use rustc_ast as ast;
@@ -150,16 +150,16 @@ impl Buffer {
     }
 }
 
-pub(crate) fn comma_sep<T: fmt::Display>(
+pub(crate) fn comma_sep<T: Display>(
     items: impl Iterator<Item = T>,
     space_after_comma: bool,
-) -> impl fmt::Display {
+) -> impl Display {
     display_fn(move |f| {
         for (i, item) in items.enumerate() {
             if i != 0 {
                 write!(f, ",{}", if space_after_comma { " " } else { "" })?;
             }
-            fmt::Display::fmt(&item, f)?;
+            item.fmt(f)?;
         }
         Ok(())
     })
@@ -168,7 +168,7 @@ pub(crate) fn comma_sep<T: fmt::Display>(
 pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
     bounds: &'a [clean::GenericBound],
     cx: &'a Context<'tcx>,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
         let mut bounds_dup = FxHashSet::default();
 
@@ -176,7 +176,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
             if i > 0 {
                 f.write_str(" + ")?;
             }
-            fmt::Display::fmt(&bound.print(cx), f)?;
+            bound.print(cx).fmt(f)?;
         }
         Ok(())
     })
@@ -186,7 +186,7 @@ impl clean::GenericParamDef {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match &self.kind {
             clean::GenericParamDefKind::Lifetime { outlives } => {
                 write!(f, "{}", self.name)?;
@@ -207,35 +207,27 @@ impl clean::GenericParamDef {
                 f.write_str(self.name.as_str())?;
 
                 if !bounds.is_empty() {
-                    if f.alternate() {
-                        write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
-                    } else {
-                        write!(f, ": {}", print_generic_bounds(bounds, cx))?;
-                    }
+                    f.write_str(": ")?;
+                    print_generic_bounds(bounds, cx).fmt(f)?;
                 }
 
                 if let Some(ref ty) = default {
-                    if f.alternate() {
-                        write!(f, " = {:#}", ty.print(cx))?;
-                    } else {
-                        write!(f, " = {}", ty.print(cx))?;
-                    }
+                    f.write_str(" = ")?;
+                    ty.print(cx).fmt(f)?;
                 }
 
                 Ok(())
             }
             clean::GenericParamDefKind::Const { ty, default, .. } => {
-                if f.alternate() {
-                    write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
-                } else {
-                    write!(f, "const {}: {}", self.name, ty.print(cx))?;
-                }
+                write!(f, "const {}: ", self.name)?;
+                ty.print(cx).fmt(f)?;
 
                 if let Some(default) = default {
+                    f.write_str(" = ")?;
                     if f.alternate() {
-                        write!(f, " = {default:#}")?;
+                        write!(f, "{default}")?;
                     } else {
-                        write!(f, " = {default}")?;
+                        write!(f, "{}", Escape(default))?;
                     }
                 }
 
@@ -249,7 +241,7 @@ impl clean::Generics {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
             if real_params.peek().is_none() {
@@ -279,63 +271,50 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
     cx: &'a Context<'tcx>,
     indent: usize,
     ending: Ending,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
-        let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
-            !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
-        }).map(|pred| {
-            display_fn(move |f| {
-                if f.alternate() {
-                    f.write_str(" ")?;
-                } else {
-                    f.write_str("\n")?;
-                }
-
-                match pred {
-                    clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
-                        let ty_cx = ty.print(cx);
-                        let generic_bounds = print_generic_bounds(bounds, cx);
+        let mut where_predicates = gens
+            .where_predicates
+            .iter()
+            .map(|pred| {
+                display_fn(move |f| {
+                    if f.alternate() {
+                        f.write_str(" ")?;
+                    } else {
+                        f.write_str("\n")?;
+                    }
 
-                        if bound_params.is_empty() {
-                            if f.alternate() {
-                                write!(f, "{ty_cx:#}: {generic_bounds:#}")
-                            } else {
-                                write!(f, "{ty_cx}: {generic_bounds}")
+                    match pred {
+                        clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
+                            print_higher_ranked_params_with_space(bound_params, cx).fmt(f)?;
+                            ty.print(cx).fmt(f)?;
+                            f.write_str(":")?;
+                            if !bounds.is_empty() {
+                                f.write_str(" ")?;
+                                print_generic_bounds(bounds, cx).fmt(f)?;
                             }
-                        } else {
+                            Ok(())
+                        }
+                        clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
+                            // We don't need to check `alternate` since we can be certain that neither
+                            // the lifetime nor the bounds contain any characters which need escaping.
+                            write!(f, "{}:", lifetime.print())?;
+                            if !bounds.is_empty() {
+                                write!(f, " {}", print_generic_bounds(bounds, cx))?;
+                            }
+                            Ok(())
+                        }
+                        clean::WherePredicate::EqPredicate { lhs, rhs } => {
                             if f.alternate() {
-                                write!(
-                                    f,
-                                    "for<{:#}> {ty_cx:#}: {generic_bounds:#}",
-                                    comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true)
-                                )
+                                write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
                             } else {
-                                write!(
-                                    f,
-                                    "for&lt;{}&gt; {ty_cx}: {generic_bounds}",
-                                    comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true)
-                                )
+                                write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
                             }
                         }
                     }
-                    clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
-                        let mut bounds_display = String::new();
-                        for bound in bounds.iter().map(|b| b.print(cx)) {
-                            write!(bounds_display, "{bound} + ")?;
-                        }
-                        bounds_display.truncate(bounds_display.len() - " + ".len());
-                        write!(f, "{}: {bounds_display}", lifetime.print())
-                    }
-                    clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                        if f.alternate() {
-                            write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
-                        } else {
-                            write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
-                        }
-                    }
-                }
+                })
             })
-        }).peekable();
+            .peekable();
 
         if where_predicates.peek().is_none() {
             return Ok(());
@@ -392,13 +371,13 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
 }
 
 impl clean::Lifetime {
-    pub(crate) fn print(&self) -> impl fmt::Display + '_ {
+    pub(crate) fn print(&self) -> impl Display + '_ {
         self.0.as_str()
     }
 }
 
 impl clean::Constant {
-    pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl fmt::Display + '_ {
+    pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ {
         let expr = self.expr(tcx);
         display_fn(
             move |f| {
@@ -409,31 +388,10 @@ impl clean::Constant {
 }
 
 impl clean::PolyTrait {
-    fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
-            if !self.generic_params.is_empty() {
-                if f.alternate() {
-                    write!(
-                        f,
-                        "for<{:#}> ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
-                    )?;
-                } else {
-                    write!(
-                        f,
-                        "for&lt;{}&gt; ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
-                    )?;
-                }
-            }
-            if f.alternate() {
-                write!(f, "{:#}", self.trait_.print(cx))
-            } else {
-                write!(f, "{}", self.trait_.print(cx))
-            }
+            print_higher_ranked_params_with_space(&self.generic_params, cx).fmt(f)?;
+            self.trait_.print(cx).fmt(f)
         })
     }
 }
@@ -442,32 +400,25 @@ impl clean::GenericBound {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
             clean::GenericBound::TraitBound(ty, modifier) => {
-                let modifier_str = match modifier {
+                f.write_str(match modifier {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
                     hir::TraitBoundModifier::Negative => "!",
                     // `const` and `~const` trait bounds are experimental; don't render them.
                     hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "",
-                };
-                if f.alternate() {
-                    write!(f, "{modifier_str}{ty:#}", ty = ty.print(cx))
-                } else {
-                    write!(f, "{modifier_str}{ty}", ty = ty.print(cx))
-                }
+                })?;
+                ty.print(cx).fmt(f)
             }
         })
     }
 }
 
 impl clean::GenericArgs {
-    fn print<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             match self {
                 clean::GenericArgs::AngleBracketed { args, bindings } => {
@@ -515,11 +466,7 @@ impl clean::GenericArgs {
                             f.write_str(", ")?;
                         }
                         comma = true;
-                        if f.alternate() {
-                            write!(f, "{:#}", ty.print(cx))?;
-                        } else {
-                            write!(f, "{}", ty.print(cx))?;
-                        }
+                        ty.print(cx).fmt(f)?;
                     }
                     f.write_str(")")?;
                     if let Some(ref ty) = *output {
@@ -973,31 +920,43 @@ fn primitive_link_fragment(
             None => {}
         }
     }
-    std::fmt::Display::fmt(&name, f)?;
+    Display::fmt(&name, f)?;
     if needs_termination {
         write!(f, "</a>")?;
     }
     Ok(())
 }
 
-/// Helper to render type parameters
 fn tybounds<'a, 'tcx: 'a>(
     bounds: &'a [clean::PolyTrait],
     lt: &'a Option<clean::Lifetime>,
     cx: &'a Context<'tcx>,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
         for (i, bound) in bounds.iter().enumerate() {
             if i > 0 {
                 write!(f, " + ")?;
             }
-
-            fmt::Display::fmt(&bound.print(cx), f)?;
+            bound.print(cx).fmt(f)?;
         }
-
         if let Some(lt) = lt {
-            write!(f, " + ")?;
-            fmt::Display::fmt(&lt.print(), f)?;
+            // We don't need to check `alternate` since we can be certain that
+            // the lifetime doesn't contain any characters which need escaping.
+            write!(f, " + {}", lt.print())?;
+        }
+        Ok(())
+    })
+}
+
+fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>(
+    params: &'a [clean::GenericParamDef],
+    cx: &'a Context<'tcx>,
+) -> impl Display + 'a + Captures<'tcx> {
+    display_fn(move |f| {
+        if !params.is_empty() {
+            f.write_str(if f.alternate() { "for<" } else { "for&lt;" })?;
+            comma_sep(params.iter().map(|lt| lt.print(cx)), true).fmt(f)?;
+            f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
         }
         Ok(())
     })
@@ -1007,7 +966,7 @@ pub(crate) fn anchor<'a, 'cx: 'a>(
     did: DefId,
     text: Symbol,
     cx: &'cx Context<'_>,
-) -> impl fmt::Display + 'a {
+) -> impl Display + 'a {
     let parts = href(did, cx);
     display_fn(move |f| {
         if let Ok((url, short_ty, fqp)) = parts {
@@ -1039,7 +998,7 @@ fn fmt_type<'cx>(
         }
         clean::DynTrait(ref bounds, ref lt) => {
             f.write_str("dyn ")?;
-            fmt::Display::fmt(&tybounds(bounds, lt, cx), f)
+            tybounds(bounds, lt, cx).fmt(f)
         }
         clean::Infer => write!(f, "_"),
         clean::Primitive(clean::PrimitiveType::Never) => {
@@ -1049,80 +1008,62 @@ fn fmt_type<'cx>(
             primitive_link(f, prim, format_args!("{}", prim.as_sym().as_str()), cx)
         }
         clean::BareFunction(ref decl) => {
+            print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?;
+            decl.unsafety.print_with_space().fmt(f)?;
+            print_abi_with_space(decl.abi).fmt(f)?;
             if f.alternate() {
-                write!(
-                    f,
-                    "{:#}{}{:#}fn{:#}",
-                    decl.print_hrtb_with_space(cx),
-                    decl.unsafety.print_with_space(),
-                    print_abi_with_space(decl.abi),
-                    decl.decl.print(cx),
-                )
+                f.write_str("fn")?;
             } else {
-                write!(
-                    f,
-                    "{}{}{}",
-                    decl.print_hrtb_with_space(cx),
-                    decl.unsafety.print_with_space(),
-                    print_abi_with_space(decl.abi)
-                )?;
                 primitive_link(f, PrimitiveType::Fn, format_args!("fn"), cx)?;
-                write!(f, "{}", decl.decl.print(cx))
             }
+            decl.decl.print(cx).fmt(f)
         }
-        clean::Tuple(ref typs) => {
-            match &typs[..] {
-                &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx),
-                [one] => {
-                    if let clean::Generic(name) = one {
-                        primitive_link(f, PrimitiveType::Tuple, format_args!("({name},)"), cx)
-                    } else {
-                        write!(f, "(")?;
-                        // Carry `f.alternate()` into this display w/o branching manually.
-                        fmt::Display::fmt(&one.print(cx), f)?;
-                        write!(f, ",)")
-                    }
+        clean::Tuple(ref typs) => match &typs[..] {
+            &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx),
+            [one] => {
+                if let clean::Generic(name) = one {
+                    primitive_link(f, PrimitiveType::Tuple, format_args!("({name},)"), cx)
+                } else {
+                    write!(f, "(")?;
+                    one.print(cx).fmt(f)?;
+                    write!(f, ",)")
                 }
-                many => {
-                    let generic_names: Vec<Symbol> = many
-                        .iter()
-                        .filter_map(|t| match t {
-                            clean::Generic(name) => Some(*name),
-                            _ => None,
-                        })
-                        .collect();
-                    let is_generic = generic_names.len() == many.len();
-                    if is_generic {
-                        primitive_link(
-                            f,
-                            PrimitiveType::Tuple,
-                            format_args!(
-                                "({})",
-                                generic_names.iter().map(|s| s.as_str()).join(", ")
-                            ),
-                            cx,
-                        )
-                    } else {
-                        write!(f, "(")?;
-                        for (i, item) in many.iter().enumerate() {
-                            if i != 0 {
-                                write!(f, ", ")?;
-                            }
-                            // Carry `f.alternate()` into this display w/o branching manually.
-                            fmt::Display::fmt(&item.print(cx), f)?;
+            }
+            many => {
+                let generic_names: Vec<Symbol> = many
+                    .iter()
+                    .filter_map(|t| match t {
+                        clean::Generic(name) => Some(*name),
+                        _ => None,
+                    })
+                    .collect();
+                let is_generic = generic_names.len() == many.len();
+                if is_generic {
+                    primitive_link(
+                        f,
+                        PrimitiveType::Tuple,
+                        format_args!("({})", generic_names.iter().map(|s| s.as_str()).join(", ")),
+                        cx,
+                    )
+                } else {
+                    write!(f, "(")?;
+                    for (i, item) in many.iter().enumerate() {
+                        if i != 0 {
+                            write!(f, ", ")?;
                         }
-                        write!(f, ")")
+                        item.print(cx).fmt(f)?;
                     }
+                    write!(f, ")")
                 }
             }
-        }
+        },
         clean::Slice(ref t) => match **t {
             clean::Generic(name) => {
                 primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx)
             }
             _ => {
                 write!(f, "[")?;
-                fmt::Display::fmt(&t.print(cx), f)?;
+                t.print(cx).fmt(f)?;
                 write!(f, "]")
             }
         },
@@ -1135,7 +1076,7 @@ fn fmt_type<'cx>(
             ),
             _ => {
                 write!(f, "[")?;
-                fmt::Display::fmt(&t.print(cx), f)?;
+                t.print(cx).fmt(f)?;
                 if f.alternate() {
                     write!(f, "; {n}")?;
                 } else {
@@ -1175,7 +1116,7 @@ fn fmt_type<'cx>(
                 }
             } else {
                 primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?;
-                fmt::Display::fmt(&t.print(cx), f)
+                t.print(cx).fmt(f)
             }
         }
         clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
@@ -1216,11 +1157,8 @@ fn fmt_type<'cx>(
             Ok(())
         }
         clean::ImplTrait(ref bounds) => {
-            if f.alternate() {
-                write!(f, "impl {:#}", print_generic_bounds(bounds, cx))
-            } else {
-                write!(f, "impl {}", print_generic_bounds(bounds, cx))
-            }
+            f.write_str("impl ")?;
+            print_generic_bounds(bounds, cx).fmt(f)
         }
         clean::QPath(box clean::QPathData {
             ref assoc,
@@ -1292,8 +1230,7 @@ fn fmt_type<'cx>(
                 write!(f, "{}", assoc.name)
             }?;
 
-            // Carry `f.alternate()` into this display w/o branching manually.
-            fmt::Display::fmt(&assoc.args.print(cx), f)
+            assoc.args.print(cx).fmt(f)
         }
     }
 }
@@ -1302,7 +1239,7 @@ impl clean::Type {
     pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+    ) -> impl Display + 'b + Captures<'tcx> {
         display_fn(move |f| fmt_type(self, f, false, cx))
     }
 }
@@ -1311,7 +1248,7 @@ impl clean::Path {
     pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+    ) -> impl Display + 'b + Captures<'tcx> {
         display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
     }
 }
@@ -1321,20 +1258,18 @@ impl clean::Impl {
         &'a self,
         use_absolute: bool,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
-            if f.alternate() {
-                write!(f, "impl{:#} ", self.generics.print(cx))?;
-            } else {
-                write!(f, "impl{} ", self.generics.print(cx))?;
-            }
+            f.write_str("impl")?;
+            self.generics.print(cx).fmt(f)?;
+            f.write_str(" ")?;
 
             if let Some(ref ty) = self.trait_ {
                 match self.polarity {
                     ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {}
                     ty::ImplPolarity::Negative => write!(f, "!")?,
                 }
-                fmt::Display::fmt(&ty.print(cx), f)?;
+                ty.print(cx).fmt(f)?;
                 write!(f, " for ")?;
             }
 
@@ -1359,14 +1294,9 @@ impl clean::Impl {
                 // Hardcoded anchor library/core/src/primitive_docs.rs
                 // Link should match `# Trait implementations`
 
-                let hrtb = bare_fn.print_hrtb_with_space(cx);
-                let unsafety = bare_fn.unsafety.print_with_space();
-                let abi = print_abi_with_space(bare_fn.abi);
-                if f.alternate() {
-                    write!(f, "{hrtb:#}{unsafety}{abi:#}",)?;
-                } else {
-                    write!(f, "{hrtb}{unsafety}{abi}",)?;
-                }
+                print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
+                bare_fn.unsafety.print_with_space().fmt(f)?;
+                print_abi_with_space(bare_fn.abi).fmt(f)?;
                 let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };
                 primitive_link_fragment(
                     f,
@@ -1386,8 +1316,7 @@ impl clean::Impl {
                 fmt_type(&self.for_, f, use_absolute, cx)?;
             }
 
-            fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, Ending::Newline), f)?;
-            Ok(())
+            print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f)
         })
     }
 }
@@ -1396,16 +1325,11 @@ impl clean::Arguments {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             for (i, input) in self.values.iter().enumerate() {
                 write!(f, "{}: ", input.name)?;
-
-                if f.alternate() {
-                    write!(f, "{:#}", input.type_.print(cx))?;
-                } else {
-                    write!(f, "{}", input.type_.print(cx))?;
-                }
+                input.type_.print(cx).fmt(f)?;
                 if i + 1 < self.values.len() {
                     write!(f, ", ")?;
                 }
@@ -1415,25 +1339,6 @@ impl clean::Arguments {
     }
 }
 
-impl clean::BareFunctionDecl {
-    fn print_hrtb_with_space<'a, 'tcx: 'a>(
-        &'a self,
-        cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
-        display_fn(move |f| {
-            if !self.generic_params.is_empty() {
-                write!(
-                    f,
-                    "for&lt;{}&gt; ",
-                    comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
-                )
-            } else {
-                Ok(())
-            }
-        })
-    }
-}
-
 // Implements Write but only counts the bytes "written".
 struct WriteCounter(usize);
 
@@ -1447,7 +1352,7 @@ impl std::fmt::Write for WriteCounter {
 // Implements Display by emitting the given number of spaces.
 struct Indent(usize);
 
-impl fmt::Display for Indent {
+impl Display for Indent {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         (0..self.0).for_each(|_| {
             f.write_char(' ').unwrap();
@@ -1460,7 +1365,7 @@ impl clean::FnDecl {
     pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'b + Captures<'tcx> {
+    ) -> impl Display + 'b + Captures<'tcx> {
         display_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
             if f.alternate() {
@@ -1494,7 +1399,7 @@ impl clean::FnDecl {
         header_len: usize,
         indent: usize,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             // First, generate the text form of the declaration, with no line wrapping, and count the bytes.
             let mut counter = WriteCounter(0);
@@ -1554,7 +1459,7 @@ impl clean::FnDecl {
                     }
                     clean::SelfExplicit(ref typ) => {
                         write!(f, "self: ")?;
-                        fmt::Display::fmt(&typ.print(cx), f)?;
+                        typ.print(cx).fmt(f)?;
                     }
                 }
             } else {
@@ -1562,7 +1467,7 @@ impl clean::FnDecl {
                     write!(f, "const ")?;
                 }
                 write!(f, "{}: ", input.name)?;
-                fmt::Display::fmt(&input.type_.print(cx), f)?;
+                input.type_.print(cx).fmt(f)?;
             }
         }
 
@@ -1578,14 +1483,13 @@ impl clean::FnDecl {
             Some(n) => write!(f, "\n{})", Indent(n))?,
         };
 
-        fmt::Display::fmt(&self.print_output(cx), f)?;
-        Ok(())
+        self.print_output(cx).fmt(f)
     }
 
     fn print_output<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match &self.output {
             clean::Tuple(tys) if tys.is_empty() => Ok(()),
             ty if f.alternate() => {
@@ -1600,7 +1504,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
     visibility: Option<ty::Visibility<DefId>>,
     item_did: ItemId,
     cx: &'a Context<'tcx>,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     use std::fmt::Write as _;
 
     let to_print: Cow<'static, str> = match visibility {
@@ -1648,7 +1552,7 @@ pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
     visibility: Option<ty::Visibility<DefId>>,
     tcx: TyCtxt<'tcx>,
     item_did: DefId,
-) -> impl fmt::Display + 'a + Captures<'tcx> {
+) -> impl Display + 'a + Captures<'tcx> {
     let to_print: Cow<'static, str> = match visibility {
         None => "".into(),
         Some(ty::Visibility::Public) => "pub ".into(),
@@ -1727,7 +1631,7 @@ impl clean::Import {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self.kind {
             clean::ImportKind::Simple(name) => {
                 if name == self.source.path.last() {
@@ -1751,7 +1655,7 @@ impl clean::ImportSource {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self.did {
             Some(did) => resolved_path(f, did, &self.path, true, false, cx),
             _ => {
@@ -1779,29 +1683,19 @@ impl clean::TypeBinding {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| {
             f.write_str(self.assoc.name.as_str())?;
-            if f.alternate() {
-                write!(f, "{:#}", self.assoc.args.print(cx))?;
-            } else {
-                write!(f, "{}", self.assoc.args.print(cx))?;
-            }
+            self.assoc.args.print(cx).fmt(f)?;
             match self.kind {
                 clean::TypeBindingKind::Equality { ref term } => {
-                    if f.alternate() {
-                        write!(f, " = {:#}", term.print(cx))?;
-                    } else {
-                        write!(f, " = {}", term.print(cx))?;
-                    }
+                    f.write_str(" = ")?;
+                    term.print(cx).fmt(f)?;
                 }
                 clean::TypeBindingKind::Constraint { ref bounds } => {
                     if !bounds.is_empty() {
-                        if f.alternate() {
-                            write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
-                        } else {
-                            write!(f, ": {}", print_generic_bounds(bounds, cx))?;
-                        }
+                        f.write_str(": ")?;
+                        print_generic_bounds(bounds, cx).fmt(f)?;
                     }
                 }
             }
@@ -1810,7 +1704,7 @@ impl clean::TypeBinding {
     }
 }
 
-pub(crate) fn print_abi_with_space(abi: Abi) -> impl fmt::Display {
+pub(crate) fn print_abi_with_space(abi: Abi) -> impl Display {
     display_fn(move |f| {
         let quot = if f.alternate() { "\"" } else { "&quot;" };
         match abi {
@@ -1828,34 +1722,32 @@ impl clean::GenericArg {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
-            clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(&lt.print(), f),
-            clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cx), f),
-            clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f),
-            clean::GenericArg::Infer => fmt::Display::fmt("_", f),
+            clean::GenericArg::Lifetime(lt) => lt.print().fmt(f),
+            clean::GenericArg::Type(ty) => ty.print(cx).fmt(f),
+            clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f),
+            clean::GenericArg::Infer => Display::fmt("_", f),
         })
     }
 }
 
-impl clean::types::Term {
+impl clean::Term {
     pub(crate) fn print<'a, 'tcx: 'a>(
         &'a self,
         cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
-            clean::types::Term::Type(ty) => fmt::Display::fmt(&ty.print(cx), f),
-            clean::types::Term::Constant(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f),
+            clean::Term::Type(ty) => ty.print(cx).fmt(f),
+            clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f),
         })
     }
 }
 
-pub(crate) fn display_fn(
-    f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
-) -> impl fmt::Display {
+pub(crate) fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Display {
     struct WithFormatter<F>(Cell<Option<F>>);
 
-    impl<F> fmt::Display for WithFormatter<F>
+    impl<F> Display for WithFormatter<F>
     where
         F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
     {
diff --git a/tests/rustdoc/bounds-in-multiple-parts.rs b/tests/rustdoc/bounds.rs
index 279e3c14888..da09e3f2a52 100644
--- a/tests/rustdoc/bounds-in-multiple-parts.rs
+++ b/tests/rustdoc/bounds.rs
@@ -18,3 +18,15 @@ pub trait T2 {
     fn f<T: Eq>()
         where Self: Eq, Self: Eq2, T: Eq2;
 }
+
+// Checking that we support empty bounds (we used to crash on empty outlives-bounds).
+// Note that we don't want to hide them since they have a semantic effect.
+// For outlives-bounds, they force the lifetime param to be early-bound instead of late-bound.
+// For trait bounds, it can affect well-formedness (see `ClauseKind::WellFormed`).
+// @has 'foo/fn.empty.html'
+// @has - '//pre[@class="rust item-decl"]' "empty<'a, T>()where T:, 'a:,"
+pub fn empty<'a, T>()
+    where
+        T:,
+        'a:,
+{}
diff --git a/tests/rustdoc/const-generics/generic_const_exprs.rs b/tests/rustdoc/const-generics/generic_const_exprs.rs
index e23b3006da6..2d2d31d7231 100644
--- a/tests/rustdoc/const-generics/generic_const_exprs.rs
+++ b/tests/rustdoc/const-generics/generic_const_exprs.rs
@@ -3,5 +3,5 @@
 #![allow(incomplete_features)]
 // make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
 // @has foo/struct.Ice.html '//pre[@class="rust item-decl"]' \
-//      'pub struct Ice<const N: usize>;'
+//      'pub struct Ice<const N: usize> where [(); { _ }]:;'
 pub struct Ice<const N: usize> where [(); N + 1]:;