Skip to content

Commit

Permalink
Auto merge of rust-lang#121160 - fmease:rustdoc-fix-n-refactor-html-r…
Browse files Browse the repository at this point in the history
…endering, 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
  • Loading branch information
bors committed Feb 15, 2024
2 parents cbddf31 + 2f6a913 commit 14c6553
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 112 deletions.
178 changes: 66 additions & 112 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))?;
}
}

Expand Down Expand Up @@ -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&lt;" })?;
fmt::Display::fmt(
&comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true),
f,
"for&lt;{}&gt; {ty_cx}: {generic_bounds}",
comma_sep(bound_params.iter().map(|lt| lt.print(cx)), true)
)
)?;
f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
}
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(());
Expand Down Expand Up @@ -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)
})
}
}
Expand All @@ -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)
}
})
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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, ", ")?;
}
Expand Down Expand Up @@ -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)?;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,15 @@ pub trait T2 {
fn f<T: Eq>()
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:,
{}

0 comments on commit 14c6553

Please sign in to comment.