diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4ba1665bdc9f1..9729a4eb4465a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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(": ")?; + fmt::Display::fmt(&print_generic_bounds(bounds, cx), f)?; } if let Some(ref ty) = default { - if f.alternate() { - write!(f, " = {:#}", ty.print(cx))?; - } else { - write!(f, " = {}", ty.print(cx))?; - } + f.write_str(" = ")?; + fmt::Display::fmt(&ty.print(cx), 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)?; + fmt::Display::fmt(&ty.print(cx), 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))?; } } @@ -281,61 +273,55 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( ending: Ending, ) -> impl fmt::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}") - } - } else { - if f.alternate() { - write!( - f, - "for<{:#}> {ty_cx:#}: {generic_bounds:#}", - comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true) - ) - } else { - write!( + match pred { + clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { + if !bound_params.is_empty() { + f.write_str(if f.alternate() { "for<" } else { "for<" })?; + fmt::Display::fmt( + &comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true), f, - "for<{}> {ty_cx}: {generic_bounds}", - comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true) - ) + )?; + f.write_str(if f.alternate() { "> " } else { "> " })?; } + fmt::Display::fmt(&ty.print(cx), f)?; + f.write_str(":")?; + if !bounds.is_empty() { + f.write_str(" ")?; + fmt::Display::fmt(&print_generic_bounds(bounds, cx), f)?; + } + Ok(()) } - } - 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} + ")?; + 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(()) } - 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)) + 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(()); @@ -429,11 +415,7 @@ impl clean::PolyTrait { )?; } } - if f.alternate() { - write!(f, "{:#}", self.trait_.print(cx)) - } else { - write!(f, "{}", self.trait_.print(cx)) - } + fmt::Display::fmt(&self.trait_.print(cx), f) }) } } @@ -446,18 +428,14 @@ impl clean::GenericBound { 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)) - } + })?; + fmt::Display::fmt(&ty.print(cx), f) } }) } @@ -515,11 +493,7 @@ impl clean::GenericArgs { f.write_str(", ")?; } comma = true; - if f.alternate() { - write!(f, "{:#}", ty.print(cx))?; - } else { - write!(f, "{}", ty.print(cx))?; - } + fmt::Display::fmt(&ty.print(cx), f)?; } f.write_str(")")?; if let Some(ref ty) = *output { @@ -1216,11 +1190,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 ")?; + fmt::Display::fmt(&print_generic_bounds(bounds, cx), f) } clean::QPath(box clean::QPathData { ref assoc, @@ -1323,11 +1294,9 @@ impl clean::Impl { cx: &'a Context<'tcx>, ) -> impl fmt::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")?; + fmt::Display::fmt(&self.generics.print(cx), f)?; + f.write_str(" ")?; if let Some(ref ty) = self.trait_ { match self.polarity { @@ -1400,12 +1369,7 @@ impl clean::Arguments { 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))?; - } + fmt::Display::fmt(&input.type_.print(cx), f)?; if i + 1 < self.values.len() { write!(f, ", ")?; } @@ -1782,26 +1746,16 @@ impl clean::TypeBinding { ) -> impl fmt::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))?; - } + fmt::Display::fmt(&self.assoc.args.print(cx), 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(" = ")?; + fmt::Display::fmt(&term.print(cx), 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(": ")?; + fmt::Display::fmt(&print_generic_bounds(bounds, cx), f)?; } } } diff --git a/tests/rustdoc/bounds-in-multiple-parts.rs b/tests/rustdoc/bounds.rs similarity index 54% rename from tests/rustdoc/bounds-in-multiple-parts.rs rename to tests/rustdoc/bounds.rs index 279e3c148887e..da09e3f2a528f 100644 --- a/tests/rustdoc/bounds-in-multiple-parts.rs +++ b/tests/rustdoc/bounds.rs @@ -18,3 +18,15 @@ pub trait T2 { fn f() 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:, +{}