Skip to content

Commit 6835191

Browse files
committed
rustdoc: correctly clean cross-crate opaque types
1 parent 495c5dd commit 6835191

File tree

4 files changed

+101
-39
lines changed

4 files changed

+101
-39
lines changed

src/librustdoc/clean/mod.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -2299,23 +2299,26 @@ fn clean_middle_opaque_bounds<'tcx>(
22992299
let bindings: ThinVec<_> = bounds
23002300
.iter()
23012301
.filter_map(|bound| {
2302-
if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() {
2303-
if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
2304-
Some(TypeBinding {
2305-
assoc: projection_to_path_segment(
2306-
bound.kind().rebind(proj.projection_ty),
2307-
cx,
2308-
),
2309-
kind: TypeBindingKind::Equality {
2310-
term: clean_middle_term(bound.kind().rebind(proj.term), cx),
2311-
},
2312-
})
2313-
} else {
2314-
None
2315-
}
2316-
} else {
2317-
None
2302+
let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() else {
2303+
return None;
2304+
};
2305+
if !simplify::trait_is_same_or_supertrait2(
2306+
cx,
2307+
trait_ref.skip_binder(),
2308+
proj.projection_ty.trait_ref(cx.tcx),
2309+
) {
2310+
return None;
23182311
}
2312+
2313+
Some(TypeBinding {
2314+
assoc: projection_to_path_segment(
2315+
bound.kind().rebind(proj.projection_ty),
2316+
cx,
2317+
),
2318+
kind: TypeBindingKind::Equality {
2319+
term: clean_middle_term(bound.kind().rebind(proj.term), cx),
2320+
},
2321+
})
23192322
})
23202323
.collect();
23212324

src/librustdoc/clean/simplify.rs

+46-4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP
6868
clauses
6969
}
7070

71+
// NOTE(fmease): This basically does the same bound cleaning as `clean_middle_opaque_bounds`.
7172
pub(crate) fn merge_bounds(
7273
cx: &clean::DocContext<'_>,
7374
bounds: &mut Vec<clean::GenericBound>,
@@ -76,9 +77,8 @@ pub(crate) fn merge_bounds(
7677
rhs: &clean::Term,
7778
) -> bool {
7879
!bounds.iter_mut().any(|b| {
79-
let trait_ref = match *b {
80-
clean::GenericBound::TraitBound(ref mut tr, _) => tr,
81-
clean::GenericBound::Outlives(..) => return false,
80+
let clean::GenericBound::TraitBound(trait_ref, _) = b else {
81+
return false;
8282
};
8383
// If this QPath's trait `trait_did` is the same as, or a supertrait
8484
// of, the bound's trait `did` then we can keep going, otherwise
@@ -108,7 +108,21 @@ pub(crate) fn merge_bounds(
108108
})
109109
}
110110

111-
fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) -> bool {
111+
// FIXME(fmease): This doesn't take into account the generic args of traits.
112+
//
113+
// Get rid of this in favor of `trait_is_same_or_supertrait2`.
114+
//
115+
// This is soft-blocked on `merge_bounds` and `where_clauses`
116+
// operating on `rustc_middle` types directly instead of cleaned
117+
// types (part of refactoring #115379).
118+
// I suppose it's possible to not do that and to instead clean
119+
// `ty::TraitRef`s in `trait_is_same_or_supertrait` as we go
120+
// but that seems fragile and bad for perf.
121+
pub(crate) fn trait_is_same_or_supertrait(
122+
cx: &DocContext<'_>,
123+
child: DefId,
124+
trait_: DefId,
125+
) -> bool {
112126
if child == trait_ {
113127
return true;
114128
}
@@ -128,6 +142,34 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
128142
.any(|did| trait_is_same_or_supertrait(cx, did, trait_))
129143
}
130144

145+
// FIXME(fmease): Add docs clarifying why we need to check the generics args for equality.
146+
// FIXME(fmease): Drop the `2` from the name.
147+
pub(crate) fn trait_is_same_or_supertrait2<'tcx>(
148+
cx: &DocContext<'tcx>,
149+
child: ty::TraitRef<'tcx>,
150+
trait_: ty::TraitRef<'tcx>,
151+
) -> bool {
152+
if child == trait_ {
153+
return true;
154+
}
155+
let predicates = cx.tcx.super_predicates_of(child.def_id);
156+
debug_assert!(cx.tcx.generics_of(child.def_id).has_self);
157+
predicates
158+
.predicates
159+
.iter()
160+
.filter_map(|(pred, _)| {
161+
let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() else {
162+
return None;
163+
};
164+
if pred.trait_ref.self_ty() != cx.tcx.types.self_param {
165+
return None;
166+
}
167+
168+
Some(ty::EarlyBinder::bind(pred.trait_ref).instantiate(cx.tcx, child.args))
169+
})
170+
.any(|child| trait_is_same_or_supertrait2(cx, child, trait_))
171+
}
172+
131173
/// Move bounds that are (likely) directly attached to generic parameters from the where-clause to
132174
/// the respective parameter.
133175
///

tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs renamed to tests/rustdoc/inline_cross/auxiliary/impl_trait.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// edition:2018
2-
31
use std::ops::Deref;
42

53
pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
@@ -26,10 +24,22 @@ pub trait Auxiliary<'arena> {
2624
type Item<'input>;
2725
}
2826

29-
pub async fn async_fn() {}
30-
3127
pub struct Foo;
3228

3329
impl Foo {
3430
pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
3531
}
32+
33+
// Regression test for issue #113015, subitem (1) / bevyengine/bevy#8898.
34+
// Check that we pick up on the return type of cross-crate opaque `Fn`s and
35+
// `FnMut`s (`FnOnce` already used to work fine).
36+
pub fn rpit_fn() -> impl Fn() -> bool {
37+
|| false
38+
}
39+
40+
pub fn rpit_fn_mut() -> impl for<'a> FnMut(&'a str) -> &'a str {
41+
|source| source
42+
}
43+
44+
// FIXME(fmease): Add more tests that demonstrate the importance of checking the
45+
// generic args of supertrait bounds.
+22-15
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,46 @@
1-
// aux-build:impl_trait_aux.rs
1+
// aux-crate:impl_trait=impl_trait.rs
22
// edition:2018
3+
#![crate_name = "user"]
34

4-
extern crate impl_trait_aux;
5-
6-
// @has impl_trait/fn.func.html
5+
// @has user/fn.func.html
76
// @has - '//pre[@class="rust item-decl"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
87
// @!has - '//pre[@class="rust item-decl"]' 'where'
9-
pub use impl_trait_aux::func;
8+
pub use impl_trait::func;
109

11-
// @has impl_trait/fn.func2.html
10+
// @has user/fn.func2.html
1211
// @has - '//pre[@class="rust item-decl"]' "func2<T>("
1312
// @has - '//pre[@class="rust item-decl"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
1413
// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8> )"
1514
// @!has - '//pre[@class="rust item-decl"]' 'where'
16-
pub use impl_trait_aux::func2;
15+
pub use impl_trait::func2;
1716

18-
// @has impl_trait/fn.func3.html
17+
// @has user/fn.func3.html
1918
// @has - '//pre[@class="rust item-decl"]' "func3("
2019
// @has - '//pre[@class="rust item-decl"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)"
2120
// @!has - '//pre[@class="rust item-decl"]' 'where'
22-
pub use impl_trait_aux::func3;
21+
pub use impl_trait::func3;
2322

24-
// @has impl_trait/fn.func4.html
23+
// @has user/fn.func4.html
2524
// @has - '//pre[@class="rust item-decl"]' "func4<T>("
2625
// @has - '//pre[@class="rust item-decl"]' "T: Iterator<Item = impl Clone>,"
27-
pub use impl_trait_aux::func4;
26+
pub use impl_trait::func4;
2827

29-
// @has impl_trait/fn.func5.html
28+
// @has user/fn.func5.html
3029
// @has - '//pre[@class="rust item-decl"]' "func5("
3130
// @has - '//pre[@class="rust item-decl"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
3231
// @has - '//pre[@class="rust item-decl"]' "_a: impl for<'beta, 'alpha, '_gamma> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
3332
// @!has - '//pre[@class="rust item-decl"]' 'where'
34-
pub use impl_trait_aux::func5;
33+
pub use impl_trait::func5;
3534

36-
// @has impl_trait/struct.Foo.html
35+
// @has user/struct.Foo.html
3736
// @has - '//*[@id="method.method"]//h4[@class="code-header"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
3837
// @!has - '//*[@id="method.method"]//h4[@class="code-header"]' 'where'
39-
pub use impl_trait_aux::Foo;
38+
pub use impl_trait::Foo;
39+
40+
// @has user/fn.rpit_fn.html
41+
// @has - '//pre[@class="rust item-decl"]' "rpit_fn() -> impl Fn() -> bool"
42+
pub use impl_trait::rpit_fn;
43+
44+
// @has user/fn.rpit_fn_mut.html
45+
// @has - '//pre[@class="rust item-decl"]' "rpit_fn_mut() -> impl for<'a> FnMut(&'a str) -> &'a str"
46+
pub use impl_trait::rpit_fn_mut;

0 commit comments

Comments
 (0)