diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index d3dc4065dfc72..7e4f036d25ea7 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -166,13 +166,14 @@ pub(crate) fn comma_sep(
pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
bounds: &'a [clean::GenericBound],
cx: &'a Context<'tcx>,
+ separator: &'static str,
) -> impl fmt::Display + 'a + Captures<'tcx> {
display_fn(move |f| {
let mut bounds_dup = FxHashSet::default();
for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.clone())).enumerate() {
if i > 0 {
- f.write_str(" + ")?;
+ f.write_str(separator)?;
}
fmt::Display::fmt(&bound.print(cx), f)?;
}
@@ -206,9 +207,9 @@ impl clean::GenericParamDef {
if !bounds.is_empty() {
if f.alternate() {
- write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
+ write!(f, ": {:#}", print_generic_bounds(bounds, cx, " + "))?;
} else {
- write!(f, ": {}", print_generic_bounds(bounds, cx))?;
+ write!(f, ": {}", print_generic_bounds(bounds, cx, " + "))?;
}
}
@@ -295,7 +296,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
match pred {
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
let ty_cx = ty.print(cx);
- let generic_bounds = print_generic_bounds(bounds, cx);
+ let generic_bounds = print_generic_bounds(bounds, cx, " ++ ");
if bound_params.is_empty() {
if f.alternate() {
@@ -320,12 +321,8 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
}
}
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())
+ let generic_bounds = print_generic_bounds(bounds, cx, " ++ ");
+ write!(f, "{}: {generic_bounds}", lifetime.print())
}
// FIXME(fmease): Render bound params.
clean::WherePredicate::EqPredicate { lhs, rhs, bound_params: _ } => {
@@ -356,7 +353,36 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
for _ in 0..indent + 4 {
br_with_padding.push_str(" ");
}
- let where_preds = where_preds.to_string().replace("
", &br_with_padding);
+ let where_preds = where_preds.to_string().split("
").into_iter().enumerate().fold(
+ String::new(),
+ |mut acc, (pos, pred)| {
+ if pos > 0 {
+ acc.push_str(&br_with_padding);
+ }
+ if pred.split(" ++ ").count() > 4 {
+ // If we have more than 4 bounds, we put one by line instead.
+ let mut len = 0;
+ for (pos, part) in pred.split(" ++ ").enumerate() {
+ len += part.len();
+ if len > 80 {
+ acc.push_str(&br_with_padding);
+ len = part.len();
+ }
+ if pos > 0 {
+ acc.push_str(" + ");
+ }
+ acc.push_str(&part);
+ }
+ } else {
+ if pred.contains(" ++ ") {
+ acc.push_str(&pred.replace(" ++ ", " + "));
+ } else {
+ acc.push_str(&pred);
+ }
+ }
+ acc
+ },
+ );
if ending == Ending::Newline {
let mut clause = " ".repeat(indent.saturating_sub(1));
@@ -1081,9 +1107,9 @@ fn fmt_type<'cx>(
}
clean::ImplTrait(ref bounds) => {
if f.alternate() {
- write!(f, "impl {:#}", print_generic_bounds(bounds, cx))
+ write!(f, "impl {:#}", print_generic_bounds(bounds, cx, " + "))
} else {
- write!(f, "impl {}", print_generic_bounds(bounds, cx))
+ write!(f, "impl {}", print_generic_bounds(bounds, cx, " + "))
}
}
clean::QPath(box clean::QPathData {
@@ -1615,9 +1641,9 @@ impl clean::TypeBinding {
clean::TypeBindingKind::Constraint { ref bounds } => {
if !bounds.is_empty() {
if f.alternate() {
- write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
+ write!(f, ": {:#}", print_generic_bounds(bounds, cx, " + "))?;
} else {
- write!(f, ": {}", print_generic_bounds(bounds, cx))?;
+ write!(f, ": {}", print_generic_bounds(bounds, cx, " + "))?;
}
}
}
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index d644293d3ef12..1fd0131f753a2 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -789,7 +789,7 @@ fn assoc_type(
generics = generics.print(cx),
);
if !bounds.is_empty() {
- write!(w, ": {}", print_generic_bounds(bounds, cx))
+ write!(w, ": {}", print_generic_bounds(bounds, cx, " + "))
}
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
if let Some(default) = default {
diff --git a/tests/rustdoc/lot-of-bounds.bounds.html b/tests/rustdoc/lot-of-bounds.bounds.html
new file mode 100644
index 0000000000000..74a176f4c47a0
--- /dev/null
+++ b/tests/rustdoc/lot-of-bounds.bounds.html
@@ -0,0 +1,4 @@
+pub trait Fixedwhere
Self: Default
+ Hash
+ Ord
+ Debug
+ Display
+ LowerExp
+ UpperExp
+ Binary
+ Octal
+ LowerHex
+ UpperHex
+ Add<Output = Self>
+ AddAssign
+ Sub<Output = Self>
+ SubAssign
+ Mul<Output = Self>
+ MulAssign
+ Div<Output = Self>
+ DivAssign
+ Rem<Output = Self>
+ RemAssign
+ Mul<Self::Bits, Output = Self>
+ MulAssign<Self::Bits>
+ Div<Self::Bits, Output = Self>
+ DivAssign<Self::Bits>
+ Rem<Self::Bits, Output = Self>
+ RemAssign<Self::Bits>
+ Rem<Self::NonZeroBits, Output = Self>
+ RemAssign<Self::NonZeroBits>
+ Not<Output = Self>
+ BitAnd<Output = Self>
+ BitAndAssign
+ BitOr<Output = Self>
+ BitOrAssign
+ BitXor<Output = Self>
+ BitXorAssign
+ Shl<u32, Output = Self>
+ ShlAssign<u32>
+ Shr<u32, Output = Self>
+ ShrAssign<u32>
+ Sum
+ Product
+ PartialOrd<i8>
+ PartialOrd<i16>
+ PartialOrd<i32>
+ PartialOrd<i64>
+ PartialOrd<i128>
+ PartialOrd<isize>
+ PartialOrd<u8>
+ PartialOrd<u16>
+ PartialOrd<u32>
+ PartialOrd<u64>
+ PartialOrd<u128>
+ PartialOrd<usize>
+ PartialOrd<f32>
+ PartialOrd<f64>,{
+ type Bits: From<Self::NonZeroBits>;
+ type NonZeroBits: TryFrom<Self::Bits, Error = TryFromIntError>;
+}
\ No newline at end of file
diff --git a/tests/rustdoc/lot-of-bounds.rs b/tests/rustdoc/lot-of-bounds.rs
new file mode 100644
index 0000000000000..4a851d1bf8a6a
--- /dev/null
+++ b/tests/rustdoc/lot-of-bounds.rs
@@ -0,0 +1,44 @@
+// This is a regression test for .
+
+#![crate_name = "foo"]
+
+use std::convert::TryFrom;
+use std::iter::{Product, Sum};
+use std::num::TryFromIntError;
+use std::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign};
+use std::fmt::{Binary, Debug, Display, LowerExp, LowerHex, Octal, UpperExp, UpperHex};
+use std::hash::Hash;
+
+// @has 'foo/trait.Fixed.html'
+// @snapshot bounds - '//*[@class="item-decl"]//code'
+pub trait Fixed
+where
+ Self: Default + Hash + Ord,
+ Self: Debug + Display + LowerExp + UpperExp,
+ Self: Binary + Octal + LowerHex + UpperHex,
+ Self: Add