diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index b710311c85872..0edaf6ec1f3ff 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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; @@ -276,115 +276,66 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( indent: usize, 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 padding_amount = indent + 4; - 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!( - f, - "for<{}> {ty_cx}: {generic_bounds}", - comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true) - ) - } - } - } - 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()) - } - // FIXME(fmease): Render bound params. - clean::WherePredicate::EqPredicate { lhs, rhs, bound_params: _ } => { - if f.alternate() { - write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx)) - } else { - write!(f, "{} == {}", lhs.print(cx), rhs.print(cx)) - } - } - } + display_fn(move |f| { + let where_preds: String = gens + .where_predicates + .iter() + .filter(|pred| { + !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty()) }) - }).peekable(); + .map(|pred| { + print_where_pred_helper(cx, pred, padding_amount) + }) + .join(","); - if where_predicates.peek().is_none() { + if where_preds.is_empty() { return Ok(()); } - let where_preds = comma_sep(where_predicates, false); - let clause = if f.alternate() { - if ending == Ending::Newline { - format!(" where{where_preds},") - } else { - format!(" where{where_preds}") - } + if ending == Ending::Newline { + write!(f, "where{where_preds},") } else { - let mut br_with_padding = String::with_capacity(6 * indent + 28); - br_with_padding.push('\n'); - - let where_indent = 3; - let padding_amount = if ending == Ending::Newline { - indent + 4 - } else if indent == 0 { - 4 - } else { - indent + where_indent + "where ".len() - }; - - for _ in 0..padding_amount { - br_with_padding.push(' '); - } - let where_preds = where_preds.to_string().replace('\n', &br_with_padding); + let indent_str = " ".repeat(indent); + write!(f, "\n{indent_str}where{where_preds}") + } + }) +} - if ending == Ending::Newline { - let mut clause = " ".repeat(indent.saturating_sub(1)); - write!(clause, "where{where_preds},")?; - clause - } else { - // insert a newline after a single space but before multiple spaces at the start - if indent == 0 { - format!("\nwhere{where_preds}") - } else { - // put the first one on the same line as the 'where' keyword - let where_preds = where_preds.replacen(&br_with_padding, " ", 1); +fn print_where_pred_helper<'a, 'tcx: 'a>( + cx: &'a Context<'tcx>, + pred: &'a clean::WherePredicate, + indent_len: usize, +) -> impl Display + Captures<'a> + Captures<'tcx> { + display_fn(move |f| { + f.write_str("\n")?; + f.write_str(&" ".repeat(indent_len))?; - let mut clause = br_with_padding; - // +1 is for `\n`. - clause.truncate(indent + 1 + where_indent); + match pred { + clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { + let ty_cx = ty.print(cx); + let generic_bounds = print_generic_bounds(bounds, cx); - write!(clause, "where{where_preds}")?; - clause + if bound_params.is_empty() { + write!(f, "{ty_cx}: {generic_bounds}") + } else { + write!( + f, + "for<{}> {ty_cx}: {generic_bounds}", + comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true) + ) } } - }; - write!(f, "{clause}") + clean::WherePredicate::RegionPredicate { lifetime, bounds } => { + let bounds_display = bounds.iter().map(|b| b.print(cx)).join(" + "); + write!(f, "{}: {bounds_display}", lifetime.print()) + } + // FIXME(fmease): Render bound params. + clean::WherePredicate::EqPredicate { lhs, rhs, bound_params: _ } => { + write!(f, "{} == {}", lhs.print(cx), rhs.print(cx)) + } + } }) } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 21c1eb631e07b..86df811874174 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -640,13 +640,16 @@ pre, .rustdoc.source .example-wrap { background: var(--table-alt-row-background-color); } +.where { + font-size: 0.875rem; +} + /* Shift "where ..." part of method or fn definition down a line */ .method .where, .fn .where, .where.fmt-newline { display: block; white-space: pre-wrap; - font-size: 0.875rem; } .item-info { diff --git a/tests/rustdoc/issue-112901-where-clause.assoc-S-impl-F.html b/tests/rustdoc/issue-112901-where-clause.assoc-S-impl-F.html new file mode 100644 index 0000000000000..b3a3d9e6c1427 --- /dev/null +++ b/tests/rustdoc/issue-112901-where-clause.assoc-S-impl-F.html @@ -0,0 +1,3 @@ +
§

type F<T> = T +where + T: Clone

\ No newline at end of file diff --git a/tests/rustdoc/issue-112901-where-clause.assoc-Tr-F.html b/tests/rustdoc/issue-112901-where-clause.assoc-Tr-F.html new file mode 100644 index 0000000000000..f28d6369e7a9e --- /dev/null +++ b/tests/rustdoc/issue-112901-where-clause.assoc-Tr-F.html @@ -0,0 +1,3 @@ +
source

type F<T> +where + T: Clone

\ No newline at end of file diff --git a/tests/rustdoc/issue-112901-where-clause.assoc-Tr-decl.html b/tests/rustdoc/issue-112901-where-clause.assoc-Tr-decl.html new file mode 100644 index 0000000000000..5389c50cf0e4c --- /dev/null +++ b/tests/rustdoc/issue-112901-where-clause.assoc-Tr-decl.html @@ -0,0 +1,5 @@ +
pub trait Tr {
+    type F<T>
+    where
+        T: Clone;
+}
\ No newline at end of file diff --git a/tests/rustdoc/issue-112901-where-clause.assoc-Tr-impl-F.html b/tests/rustdoc/issue-112901-where-clause.assoc-Tr-impl-F.html new file mode 100644 index 0000000000000..cbb07a3e884f5 --- /dev/null +++ b/tests/rustdoc/issue-112901-where-clause.assoc-Tr-impl-F.html @@ -0,0 +1,3 @@ +
§

type F<T> = T +where + T: Clone

\ No newline at end of file diff --git a/tests/rustdoc/issue-112901-where-clause.rs b/tests/rustdoc/issue-112901-where-clause.rs new file mode 100644 index 0000000000000..ee9af37917b78 --- /dev/null +++ b/tests/rustdoc/issue-112901-where-clause.rs @@ -0,0 +1,36 @@ +#![crate_name = "foo"] +#![feature(trivial_bounds)] + +pub mod structs { + // @has foo/structs/struct.A.html + // @snapshot structs-A - '//pre[@class="rust item-decl"]' + pub struct A(T) + where + T: Copy; + + // @has foo/structs/struct.S.html + // @snapshot structs-S - '//pre[@class="rust item-decl"]' + pub struct S + where + String: Clone; +} + +pub mod assoc { + // @has foo/assoc/struct.S.html + // @snapshot assoc-S-impl-F - '//section[@id="associatedtype.F"]' + pub struct S; + + // @has foo/assoc/trait.Tr.html + // @snapshot assoc-Tr-decl - '//pre[@class="rust item-decl"]' + // @snapshot assoc-Tr-F - '//section[@id="associatedtype.F"]' + // @snapshot assoc-Tr-impl-F - '//section[@id="associatedtype.F-1"]' + pub trait Tr { + type F + where + T: Clone; + } + + impl Tr for S { + type F = T where T: Clone; + } +} diff --git a/tests/rustdoc/issue-112901-where-clause.structs-A.html b/tests/rustdoc/issue-112901-where-clause.structs-A.html new file mode 100644 index 0000000000000..397e604a71ff3 --- /dev/null +++ b/tests/rustdoc/issue-112901-where-clause.structs-A.html @@ -0,0 +1,3 @@ +
pub struct A<T>(_)
+where
+    T: Copy;
\ No newline at end of file diff --git a/tests/rustdoc/issue-112901-where-clause.structs-S.html b/tests/rustdoc/issue-112901-where-clause.structs-S.html new file mode 100644 index 0000000000000..7b1a31d7dd471 --- /dev/null +++ b/tests/rustdoc/issue-112901-where-clause.structs-S.html @@ -0,0 +1,3 @@ +
pub struct S
+where
+    String: Clone;
\ No newline at end of file diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc/where.SWhere_Simd_item-decl.html index 3e72ba2b74fe2..a2e76a548e260 100644 --- a/tests/rustdoc/where.SWhere_Simd_item-decl.html +++ b/tests/rustdoc/where.SWhere_Simd_item-decl.html @@ -1,3 +1,3 @@
pub struct Simd<T>(_)
 where
-    T: MyTrait;
+ T: MyTrait; \ No newline at end of file diff --git a/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html b/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html index e8ab061e679dd..3af87a00c4271 100644 --- a/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html +++ b/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html @@ -1,13 +1,17 @@
pub trait TraitWhere {
     type Item<'a>
-       where Self: 'a;
+    where
+        Self: 'a;
 
     // Provided methods
     fn func(self)
-       where Self: Sized { ... }
+    where
+        Self: Sized { ... }
     fn lines(self) -> Lines<Self>
-       where Self: Sized { ... }
+    where
+        Self: Sized { ... }
     fn merge<T>(self, a: T)
-       where Self: Sized,
-             T: Sized { ... }
+    where
+        Self: Sized,
+        T: Sized { ... }
 }
\ No newline at end of file