Skip to content

Commit 14c6553

Browse files
committed
Auto merge of rust-lang#121160 - fmease:rustdoc-fix-n-refactor-html-rendering, r=<try>
rustdoc: fix and refactor HTML rendering a bit * refactoring: get rid of a bunch of manual `f.alternative()` branches * not sure why this doesn't done yet, is this perf-sensitive? * fix an ICE in debug builds of rustdoc * rustdoc used to crash on empty outlives-bounds: `where 'a:` * properly escape const generic defaults
2 parents cbddf31 + 2f6a913 commit 14c6553

File tree

2 files changed

+78
-112
lines changed

2 files changed

+78
-112
lines changed

src/librustdoc/html/format.rs

+66-112
Original file line numberDiff line numberDiff line change
@@ -207,35 +207,27 @@ impl clean::GenericParamDef {
207207
f.write_str(self.name.as_str())?;
208208

209209
if !bounds.is_empty() {
210-
if f.alternate() {
211-
write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
212-
} else {
213-
write!(f, ": {}", print_generic_bounds(bounds, cx))?;
214-
}
210+
f.write_str(": ")?;
211+
fmt::Display::fmt(&print_generic_bounds(bounds, cx), f)?;
215212
}
216213

217214
if let Some(ref ty) = default {
218-
if f.alternate() {
219-
write!(f, " = {:#}", ty.print(cx))?;
220-
} else {
221-
write!(f, " = {}", ty.print(cx))?;
222-
}
215+
f.write_str(" = ")?;
216+
fmt::Display::fmt(&ty.print(cx), f)?;
223217
}
224218

225219
Ok(())
226220
}
227221
clean::GenericParamDefKind::Const { ty, default, .. } => {
228-
if f.alternate() {
229-
write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
230-
} else {
231-
write!(f, "const {}: {}", self.name, ty.print(cx))?;
232-
}
222+
write!(f, "const {}: ", self.name)?;
223+
fmt::Display::fmt(&ty.print(cx), f)?;
233224

234225
if let Some(default) = default {
226+
f.write_str(" = ")?;
235227
if f.alternate() {
236-
write!(f, " = {default:#}")?;
228+
write!(f, "{default}")?;
237229
} else {
238-
write!(f, " = {default}")?;
230+
write!(f, "{}", Escape(default))?;
239231
}
240232
}
241233

@@ -281,61 +273,55 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
281273
ending: Ending,
282274
) -> impl fmt::Display + 'a + Captures<'tcx> {
283275
display_fn(move |f| {
284-
let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
285-
!matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
286-
}).map(|pred| {
287-
display_fn(move |f| {
288-
if f.alternate() {
289-
f.write_str(" ")?;
290-
} else {
291-
f.write_str("\n")?;
292-
}
293-
294-
match pred {
295-
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
296-
let ty_cx = ty.print(cx);
297-
let generic_bounds = print_generic_bounds(bounds, cx);
276+
let mut where_predicates = gens
277+
.where_predicates
278+
.iter()
279+
.map(|pred| {
280+
display_fn(move |f| {
281+
if f.alternate() {
282+
f.write_str(" ")?;
283+
} else {
284+
f.write_str("\n")?;
285+
}
298286

299-
if bound_params.is_empty() {
300-
if f.alternate() {
301-
write!(f, "{ty_cx:#}: {generic_bounds:#}")
302-
} else {
303-
write!(f, "{ty_cx}: {generic_bounds}")
304-
}
305-
} else {
306-
if f.alternate() {
307-
write!(
308-
f,
309-
"for<{:#}> {ty_cx:#}: {generic_bounds:#}",
310-
comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true)
311-
)
312-
} else {
313-
write!(
287+
match pred {
288+
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
289+
if !bound_params.is_empty() {
290+
f.write_str(if f.alternate() { "for<" } else { "for&lt;" })?;
291+
fmt::Display::fmt(
292+
&comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true),
314293
f,
315-
"for&lt;{}&gt; {ty_cx}: {generic_bounds}",
316-
comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true)
317-
)
294+
)?;
295+
f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
318296
}
297+
fmt::Display::fmt(&ty.print(cx), f)?;
298+
f.write_str(":")?;
299+
if !bounds.is_empty() {
300+
f.write_str(" ")?;
301+
fmt::Display::fmt(&print_generic_bounds(bounds, cx), f)?;
302+
}
303+
Ok(())
319304
}
320-
}
321-
clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
322-
let mut bounds_display = String::new();
323-
for bound in bounds.iter().map(|b| b.print(cx)) {
324-
write!(bounds_display, "{bound} + ")?;
305+
clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
306+
// We don't need to check `alternate` since we can be certain that neither
307+
// the lifetime nor the bounds contain any characters which need escaping.
308+
write!(f, "{}:", lifetime.print())?;
309+
if !bounds.is_empty() {
310+
write!(f, " {}", print_generic_bounds(bounds, cx))?;
311+
}
312+
Ok(())
325313
}
326-
bounds_display.truncate(bounds_display.len() - " + ".len());
327-
write!(f, "{}: {bounds_display}", lifetime.print())
328-
}
329-
clean::WherePredicate::EqPredicate { lhs, rhs } => {
330-
if f.alternate() {
331-
write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
332-
} else {
333-
write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
314+
clean::WherePredicate::EqPredicate { lhs, rhs } => {
315+
if f.alternate() {
316+
write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
317+
} else {
318+
write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
319+
}
334320
}
335321
}
336-
}
322+
})
337323
})
338-
}).peekable();
324+
.peekable();
339325

340326
if where_predicates.peek().is_none() {
341327
return Ok(());
@@ -429,11 +415,7 @@ impl clean::PolyTrait {
429415
)?;
430416
}
431417
}
432-
if f.alternate() {
433-
write!(f, "{:#}", self.trait_.print(cx))
434-
} else {
435-
write!(f, "{}", self.trait_.print(cx))
436-
}
418+
fmt::Display::fmt(&self.trait_.print(cx), f)
437419
})
438420
}
439421
}
@@ -446,18 +428,14 @@ impl clean::GenericBound {
446428
display_fn(move |f| match self {
447429
clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
448430
clean::GenericBound::TraitBound(ty, modifier) => {
449-
let modifier_str = match modifier {
431+
f.write_str(match modifier {
450432
hir::TraitBoundModifier::None => "",
451433
hir::TraitBoundModifier::Maybe => "?",
452434
hir::TraitBoundModifier::Negative => "!",
453435
// `const` and `~const` trait bounds are experimental; don't render them.
454436
hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "",
455-
};
456-
if f.alternate() {
457-
write!(f, "{modifier_str}{ty:#}", ty = ty.print(cx))
458-
} else {
459-
write!(f, "{modifier_str}{ty}", ty = ty.print(cx))
460-
}
437+
})?;
438+
fmt::Display::fmt(&ty.print(cx), f)
461439
}
462440
})
463441
}
@@ -515,11 +493,7 @@ impl clean::GenericArgs {
515493
f.write_str(", ")?;
516494
}
517495
comma = true;
518-
if f.alternate() {
519-
write!(f, "{:#}", ty.print(cx))?;
520-
} else {
521-
write!(f, "{}", ty.print(cx))?;
522-
}
496+
fmt::Display::fmt(&ty.print(cx), f)?;
523497
}
524498
f.write_str(")")?;
525499
if let Some(ref ty) = *output {
@@ -1216,11 +1190,8 @@ fn fmt_type<'cx>(
12161190
Ok(())
12171191
}
12181192
clean::ImplTrait(ref bounds) => {
1219-
if f.alternate() {
1220-
write!(f, "impl {:#}", print_generic_bounds(bounds, cx))
1221-
} else {
1222-
write!(f, "impl {}", print_generic_bounds(bounds, cx))
1223-
}
1193+
f.write_str("impl ")?;
1194+
fmt::Display::fmt(&print_generic_bounds(bounds, cx), f)
12241195
}
12251196
clean::QPath(box clean::QPathData {
12261197
ref assoc,
@@ -1323,11 +1294,9 @@ impl clean::Impl {
13231294
cx: &'a Context<'tcx>,
13241295
) -> impl fmt::Display + 'a + Captures<'tcx> {
13251296
display_fn(move |f| {
1326-
if f.alternate() {
1327-
write!(f, "impl{:#} ", self.generics.print(cx))?;
1328-
} else {
1329-
write!(f, "impl{} ", self.generics.print(cx))?;
1330-
}
1297+
f.write_str("impl")?;
1298+
fmt::Display::fmt(&self.generics.print(cx), f)?;
1299+
f.write_str(" ")?;
13311300

13321301
if let Some(ref ty) = self.trait_ {
13331302
match self.polarity {
@@ -1400,12 +1369,7 @@ impl clean::Arguments {
14001369
display_fn(move |f| {
14011370
for (i, input) in self.values.iter().enumerate() {
14021371
write!(f, "{}: ", input.name)?;
1403-
1404-
if f.alternate() {
1405-
write!(f, "{:#}", input.type_.print(cx))?;
1406-
} else {
1407-
write!(f, "{}", input.type_.print(cx))?;
1408-
}
1372+
fmt::Display::fmt(&input.type_.print(cx), f)?;
14091373
if i + 1 < self.values.len() {
14101374
write!(f, ", ")?;
14111375
}
@@ -1782,26 +1746,16 @@ impl clean::TypeBinding {
17821746
) -> impl fmt::Display + 'a + Captures<'tcx> {
17831747
display_fn(move |f| {
17841748
f.write_str(self.assoc.name.as_str())?;
1785-
if f.alternate() {
1786-
write!(f, "{:#}", self.assoc.args.print(cx))?;
1787-
} else {
1788-
write!(f, "{}", self.assoc.args.print(cx))?;
1789-
}
1749+
fmt::Display::fmt(&self.assoc.args.print(cx), f)?;
17901750
match self.kind {
17911751
clean::TypeBindingKind::Equality { ref term } => {
1792-
if f.alternate() {
1793-
write!(f, " = {:#}", term.print(cx))?;
1794-
} else {
1795-
write!(f, " = {}", term.print(cx))?;
1796-
}
1752+
f.write_str(" = ")?;
1753+
fmt::Display::fmt(&term.print(cx), f)?;
17971754
}
17981755
clean::TypeBindingKind::Constraint { ref bounds } => {
17991756
if !bounds.is_empty() {
1800-
if f.alternate() {
1801-
write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
1802-
} else {
1803-
write!(f, ": {}", print_generic_bounds(bounds, cx))?;
1804-
}
1757+
f.write_str(": ")?;
1758+
fmt::Display::fmt(&print_generic_bounds(bounds, cx), f)?;
18051759
}
18061760
}
18071761
}

tests/rustdoc/bounds-in-multiple-parts.rs tests/rustdoc/bounds.rs

+12
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,15 @@ pub trait T2 {
1818
fn f<T: Eq>()
1919
where Self: Eq, Self: Eq2, T: Eq2;
2020
}
21+
22+
// Checking that we support empty bounds (we used to crash on empty outlives-bounds).
23+
// Note that we don't want to hide them since they have a semantic effect.
24+
// For outlives-bounds, they force the lifetime param to be early-bound instead of late-bound.
25+
// For trait bounds, it can affect well-formedness (see `ClauseKind::WellFormed`).
26+
// @has 'foo/fn.empty.html'
27+
// @has - '//pre[@class="rust item-decl"]' "empty<'a, T>()where T:, 'a:,"
28+
pub fn empty<'a, T>()
29+
where
30+
T:,
31+
'a:,
32+
{}

0 commit comments

Comments
 (0)