Skip to content

Commit 28d40f1

Browse files
committed
rustdoc: fix cross-crate impl-Sized
1 parent f68f37d commit 28d40f1

File tree

7 files changed

+121
-27
lines changed

7 files changed

+121
-27
lines changed

src/librustdoc/clean/mod.rs

+34-10
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,6 @@ fn clean_ty_generics<'tcx>(
835835
.into_iter()
836836
.flatten()
837837
.cloned()
838-
.filter(|b| !b.is_sized_bound(cx)),
839838
);
840839

841840
if let Some(proj) = projection
@@ -862,8 +861,27 @@ fn clean_ty_generics<'tcx>(
862861
.collect::<Vec<_>>();
863862

864863
for (param, mut bounds) in impl_trait {
864+
let mut has_sized = false;
865+
bounds.retain(|b| {
866+
if b.is_sized_bound(cx) {
867+
has_sized = true;
868+
false
869+
} else {
870+
true
871+
}
872+
});
873+
if !has_sized {
874+
bounds.push(GenericBound::maybe_sized(cx));
875+
}
876+
865877
// Move trait bounds to the front.
866-
bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
878+
bounds.sort_by_key(|b| !b.is_trait_bound());
879+
880+
// Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`).
881+
// Since all potential trait bounds are at the front we can just check the first bound.
882+
if bounds.first().map_or(true, |b| !b.is_trait_bound()) {
883+
bounds.insert(0, GenericBound::sized(cx));
884+
}
867885

868886
let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() };
869887
if let Some(proj) = impl_trait_proj.remove(&idx) {
@@ -2107,7 +2125,6 @@ fn clean_middle_opaque_bounds<'tcx>(
21072125
cx: &mut DocContext<'tcx>,
21082126
bounds: Vec<ty::Clause<'tcx>>,
21092127
) -> Type {
2110-
let mut regions = vec![];
21112128
let mut has_sized = false;
21122129
let mut bounds = bounds
21132130
.iter()
@@ -2116,10 +2133,7 @@ fn clean_middle_opaque_bounds<'tcx>(
21162133
let trait_ref = match bound_predicate.skip_binder() {
21172134
ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
21182135
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
2119-
if let Some(r) = clean_middle_region(reg) {
2120-
regions.push(GenericBound::Outlives(r));
2121-
}
2122-
return None;
2136+
return clean_middle_region(reg).map(GenericBound::Outlives);
21232137
}
21242138
_ => return None,
21252139
};
@@ -2155,10 +2169,20 @@ fn clean_middle_opaque_bounds<'tcx>(
21552169
Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
21562170
})
21572171
.collect::<Vec<_>>();
2158-
bounds.extend(regions);
2159-
if !has_sized && !bounds.is_empty() {
2160-
bounds.insert(0, GenericBound::maybe_sized(cx));
2172+
2173+
if !has_sized {
2174+
bounds.push(GenericBound::maybe_sized(cx));
21612175
}
2176+
2177+
// Move trait bounds to the front.
2178+
bounds.sort_by_key(|b| !b.is_trait_bound());
2179+
2180+
// Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`).
2181+
// Since all potential trait bounds are at the front we can just check the first bound.
2182+
if bounds.first().map_or(true, |b| !b.is_trait_bound()) {
2183+
bounds.insert(0, GenericBound::sized(cx));
2184+
}
2185+
21622186
ImplTrait(bounds)
21632187
}
21642188

src/librustdoc/clean/types.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1219,15 +1219,24 @@ pub(crate) enum GenericBound {
12191219
}
12201220

12211221
impl GenericBound {
1222+
pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1223+
Self::sized_with(cx, hir::TraitBoundModifier::None)
1224+
}
1225+
12221226
pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1227+
Self::sized_with(cx, hir::TraitBoundModifier::Maybe)
1228+
}
1229+
1230+
fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound {
12231231
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
12241232
let empty = ty::Binder::dummy(ty::GenericArgs::empty());
12251233
let path = external_path(cx, did, false, ThinVec::new(), empty);
12261234
inline::record_extern_fqn(cx, did, ItemType::Trait);
1227-
GenericBound::TraitBound(
1228-
PolyTrait { trait_: path, generic_params: Vec::new() },
1229-
hir::TraitBoundModifier::Maybe,
1230-
)
1235+
GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier)
1236+
}
1237+
1238+
pub(crate) fn is_trait_bound(&self) -> bool {
1239+
matches!(self, Self::TraitBound(..))
12311240
}
12321241

12331242
pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {

src/librustdoc/html/format.rs

+24-11
Original file line numberDiff line numberDiff line change
@@ -1094,22 +1094,35 @@ fn fmt_type<'cx>(
10941094
};
10951095
let m = mutability.print_with_space();
10961096
let amp = if f.alternate() { "&" } else { "&amp;" };
1097-
match **ty {
1097+
1098+
if let clean::Generic(name) = **ty {
1099+
return primitive_link(
1100+
f,
1101+
PrimitiveType::Reference,
1102+
&format!("{amp}{lt}{m}{name}"),
1103+
cx,
1104+
);
1105+
}
1106+
1107+
write!(f, "{amp}{lt}{m}")?;
1108+
1109+
let needs_parens = match **ty {
10981110
clean::DynTrait(ref bounds, ref trait_lt)
10991111
if bounds.len() > 1 || trait_lt.is_some() =>
11001112
{
1101-
write!(f, "{}{}{}(", amp, lt, m)?;
1102-
fmt_type(ty, f, use_absolute, cx)?;
1103-
write!(f, ")")
1104-
}
1105-
clean::Generic(name) => {
1106-
primitive_link(f, PrimitiveType::Reference, &format!("{amp}{lt}{m}{name}"), cx)
1107-
}
1108-
_ => {
1109-
write!(f, "{}{}{}", amp, lt, m)?;
1110-
fmt_type(ty, f, use_absolute, cx)
1113+
true
11111114
}
1115+
clean::ImplTrait(ref bounds) if bounds.len() > 1 => true,
1116+
_ => false,
1117+
};
1118+
if needs_parens {
1119+
f.write_str("(")?;
11121120
}
1121+
fmt_type(ty, f, use_absolute, cx)?;
1122+
if needs_parens {
1123+
f.write_str(")")?;
1124+
}
1125+
Ok(())
11131126
}
11141127
clean::ImplTrait(ref bounds) => {
11151128
if f.alternate() {

tests/rustdoc/extern-impl-trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ extern crate extern_impl_trait;
77
// @has 'foo/struct.X.html' '//h4[@class="code-header"]' "impl Foo<Associated = ()> + 'a"
88
pub use extern_impl_trait::X;
99

10-
// @has 'foo/struct.Y.html' '//h4[@class="code-header"]' "impl ?Sized + Foo<Associated = ()> + 'a"
10+
// @has 'foo/struct.Y.html' '//h4[@class="code-header"]' "impl Foo<Associated = ()> + ?Sized + 'a"
1111
pub use extern_impl_trait::Y;

tests/rustdoc/impl-everywhere.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ pub fn foo_foo() -> impl Foo + Foo2 {
2525
Bar
2626
}
2727

28-
// @has foo/fn.foo_foo_foo.html '//section[@id="main-content"]//pre' "x: &'x impl Foo + Foo2"
28+
// @has foo/fn.foo_foo_foo.html '//section[@id="main-content"]//pre' "x: &'x (impl Foo + Foo2)"
2929
pub fn foo_foo_foo<'x>(_x: &'x (impl Foo + Foo2)) {
3030
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use std::fmt::Debug;
2+
3+
pub fn sized(x: impl Sized) -> impl Sized {
4+
x
5+
}
6+
7+
pub fn sized_outlives<'a>(x: impl Sized + 'a) -> impl Sized + 'a {
8+
x
9+
}
10+
11+
pub fn maybe_sized(x: &impl ?Sized) -> &impl ?Sized {
12+
x
13+
}
14+
15+
pub fn debug_maybe_sized(x: &(impl Debug + ?Sized)) -> &(impl Debug + ?Sized) {
16+
x
17+
}
18+
19+
pub fn maybe_sized_outlives<'t>(x: &(impl ?Sized + 't)) -> &(impl ?Sized + 't) {
20+
x
21+
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![crate_name = "user"]
2+
3+
// aux-crate:impl_sized=impl-sized.rs
4+
// edition:2021
5+
6+
// @has user/fn.sized.html
7+
// @has - '//pre[@class="rust item-decl"]' "sized(x: impl Sized) -> impl Sized"
8+
pub use impl_sized::sized;
9+
10+
// @has user/fn.sized_outlives.html
11+
// @has - '//pre[@class="rust item-decl"]' \
12+
// "sized_outlives<'a>(x: impl Sized + 'a) -> impl Sized + 'a"
13+
pub use impl_sized::sized_outlives;
14+
15+
// @has user/fn.maybe_sized.html
16+
// @has - '//pre[@class="rust item-decl"]' "maybe_sized(x: &impl ?Sized) -> &impl ?Sized"
17+
pub use impl_sized::maybe_sized;
18+
19+
// @has user/fn.debug_maybe_sized.html
20+
// @has - '//pre[@class="rust item-decl"]' \
21+
// "debug_maybe_sized(x: &(impl Debug + ?Sized)) -> &(impl Debug + ?Sized)"
22+
pub use impl_sized::debug_maybe_sized;
23+
24+
// @has user/fn.maybe_sized_outlives.html
25+
// @has - '//pre[@class="rust item-decl"]' \
26+
// "maybe_sized_outlives<'t>(x: &(impl ?Sized + 't)) -> &(impl ?Sized + 't)"
27+
pub use impl_sized::maybe_sized_outlives;

0 commit comments

Comments
 (0)