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 + AddAssign, + Self: Sub + SubAssign, + Self: Mul + MulAssign, + Self: Div + DivAssign, + Self: Rem + RemAssign, + Self: Mul<::Bits, Output = Self> + MulAssign<::Bits>, + Self: Div<::Bits, Output = Self> + DivAssign<::Bits>, + Self: Rem<::Bits, Output = Self> + RemAssign<::Bits>, + Self: Rem<::NonZeroBits, Output = Self>, + Self: RemAssign<::NonZeroBits>, + Self: Not, + Self: BitAnd + BitAndAssign, + Self: BitOr + BitOrAssign, + Self: BitXor + BitXorAssign, + Self: Shl + ShlAssign, + Self: Shr + ShrAssign, + Self: Sum + Product, + Self: PartialOrd + PartialOrd + PartialOrd, + Self: PartialOrd + PartialOrd + PartialOrd, + Self: PartialOrd + PartialOrd + PartialOrd, + Self: PartialOrd + PartialOrd + PartialOrd, + Self: PartialOrd + PartialOrd, +{ + type Bits: From; + type NonZeroBits: TryFrom; +}