Skip to content

Commit 9c84324

Browse files
committed
Associated type bound for inlined impl Trait doc
1 parent 37d09a6 commit 9c84324

File tree

4 files changed

+131
-68
lines changed

4 files changed

+131
-68
lines changed

src/librustdoc/clean/mod.rs

Lines changed: 70 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
16941694

16951695
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
16961696
// since `Clean for ty::Predicate` would consume them.
1697-
let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<_>>::default();
1697+
let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<GenericBound>>::default();
16981698

16991699
// Bounds in the type_params and lifetimes fields are repeated in the
17001700
// predicates field (see rustc_typeck::collect::ty_generics), so remove
@@ -1716,41 +1716,73 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
17161716
ty::GenericParamDefKind::Const { .. } => None,
17171717
}).collect::<Vec<GenericParamDef>>();
17181718

1719+
// (param index, def id of trait) -> (name, type)
1720+
let mut impl_trait_proj = FxHashMap::<(u32, DefId), Vec<(String, Type)>>::default();
1721+
17191722
let mut where_predicates = preds.predicates.iter()
17201723
.flat_map(|(p, _)| {
1721-
let param_idx = if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
1722-
if let ty::Param(param) = trait_ref.self_ty().sty {
1723-
Some(param.index)
1724-
} else {
1725-
None
1726-
}
1727-
} else if let Some(outlives) = p.to_opt_type_outlives() {
1728-
if let ty::Param(param) = outlives.skip_binder().0.sty {
1729-
Some(param.index)
1730-
} else {
1731-
None
1724+
let param_idx = (|| {
1725+
if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
1726+
if let ty::Param(param) = trait_ref.self_ty().sty {
1727+
return Some(param.index);
1728+
}
1729+
} else if let Some(outlives) = p.to_opt_type_outlives() {
1730+
if let ty::Param(param) = outlives.skip_binder().0.sty {
1731+
return Some(param.index);
1732+
}
1733+
} else if let ty::Predicate::Projection(proj) = p {
1734+
if let ty::Param(param) = proj.skip_binder().projection_ty.self_ty().sty {
1735+
return Some(param.index);
1736+
}
17321737
}
1733-
} else {
1738+
17341739
None
1735-
};
1740+
})();
17361741

17371742
let p = p.clean(cx)?;
17381743

1739-
if let Some(b) = param_idx.and_then(|i| impl_trait.get_mut(&i.into())) {
1740-
b.extend(
1741-
p.get_bounds()
1742-
.into_iter()
1743-
.flatten()
1744-
.cloned()
1745-
.filter(|b| !b.is_sized_bound(cx))
1746-
);
1747-
return None;
1744+
if let Some(param_idx) = param_idx {
1745+
if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
1746+
b.extend(
1747+
p.get_bounds()
1748+
.into_iter()
1749+
.flatten()
1750+
.cloned()
1751+
.filter(|b| !b.is_sized_bound(cx))
1752+
);
1753+
1754+
let proj = match &p {
1755+
WherePredicate::EqPredicate { lhs, rhs } => Some((lhs, rhs))
1756+
.and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))),
1757+
_ => None,
1758+
};
1759+
if let Some(((_, trait_did, name), rhs)) = proj {
1760+
impl_trait_proj
1761+
.entry((param_idx, trait_did))
1762+
.or_default()
1763+
.push((name.to_string(), rhs.clone()));
1764+
}
1765+
1766+
return None;
1767+
}
17481768
}
17491769

17501770
Some(p)
17511771
})
17521772
.collect::<Vec<_>>();
17531773

1774+
for ((param_idx, trait_did), bounds) in impl_trait_proj {
1775+
for (name, rhs) in bounds {
1776+
simplify::merge_bounds(
1777+
cx,
1778+
impl_trait.get_mut(&param_idx.into()).unwrap(),
1779+
trait_did,
1780+
&name,
1781+
&rhs,
1782+
);
1783+
}
1784+
}
1785+
17541786
// Move `TraitPredicate`s to the front.
17551787
for (_, bounds) in impl_trait.iter_mut() {
17561788
bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b {
@@ -2662,6 +2694,21 @@ impl Type {
26622694
_ => false,
26632695
}
26642696
}
2697+
2698+
pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
2699+
let (self_, trait_, name) = match self {
2700+
QPath { ref self_type, ref trait_, ref name } => {
2701+
(self_type, trait_, name)
2702+
}
2703+
_ => return None,
2704+
};
2705+
let trait_did = match **trait_ {
2706+
ResolvedPath { did, .. } => did,
2707+
_ => return None,
2708+
};
2709+
Some((&self_, trait_did, name))
2710+
}
2711+
26652712
}
26662713

26672714
impl GetDefId for Type {

src/librustdoc/clean/simplify.rs

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -53,58 +53,21 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
5353
// Look for equality predicates on associated types that can be merged into
5454
// general bound predicates
5555
equalities.retain(|&(ref lhs, ref rhs)| {
56-
let (self_, trait_, name) = match *lhs {
57-
clean::QPath { ref self_type, ref trait_, ref name } => {
58-
(self_type, trait_, name)
59-
}
60-
_ => return true,
61-
};
62-
let generic = match **self_ {
63-
clean::Generic(ref s) => s,
64-
_ => return true,
56+
let (self_, trait_did, name) = if let Some(p) = lhs.projection() {
57+
p
58+
} else {
59+
return true;
6560
};
66-
let trait_did = match **trait_ {
67-
clean::ResolvedPath { did, .. } => did,
61+
let generic = match self_ {
62+
clean::Generic(s) => s,
6863
_ => return true,
6964
};
7065
let bounds = match params.get_mut(generic) {
7166
Some(bound) => bound,
7267
None => return true,
7368
};
74-
!bounds.iter_mut().any(|b| {
75-
let trait_ref = match *b {
76-
clean::GenericBound::TraitBound(ref mut tr, _) => tr,
77-
clean::GenericBound::Outlives(..) => return false,
78-
};
79-
let (did, path) = match trait_ref.trait_ {
80-
clean::ResolvedPath { did, ref mut path, ..} => (did, path),
81-
_ => return false,
82-
};
83-
// If this QPath's trait `trait_did` is the same as, or a supertrait
84-
// of, the bound's trait `did` then we can keep going, otherwise
85-
// this is just a plain old equality bound.
86-
if !trait_is_same_or_supertrait(cx, did, trait_did) {
87-
return false
88-
}
89-
let last = path.segments.last_mut().expect("segments were empty");
90-
match last.args {
91-
PP::AngleBracketed { ref mut bindings, .. } => {
92-
bindings.push(clean::TypeBinding {
93-
name: name.clone(),
94-
kind: clean::TypeBindingKind::Equality {
95-
ty: rhs.clone(),
96-
},
97-
});
98-
}
99-
PP::Parenthesized { ref mut output, .. } => {
100-
assert!(output.is_none());
101-
if *rhs != clean::Type::Tuple(Vec::new()) {
102-
*output = Some(rhs.clone());
103-
}
104-
}
105-
};
106-
true
107-
})
69+
70+
merge_bounds(cx, bounds, trait_did, name, rhs)
10871
});
10972

11073
// And finally, let's reassemble everything
@@ -127,6 +90,49 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
12790
clauses
12891
}
12992

93+
pub fn merge_bounds(
94+
cx: &clean::DocContext<'_>,
95+
bounds: &mut Vec<clean::GenericBound>,
96+
trait_did: DefId,
97+
name: &str,
98+
rhs: &clean::Type,
99+
) -> bool {
100+
!bounds.iter_mut().any(|b| {
101+
let trait_ref = match *b {
102+
clean::GenericBound::TraitBound(ref mut tr, _) => tr,
103+
clean::GenericBound::Outlives(..) => return false,
104+
};
105+
let (did, path) = match trait_ref.trait_ {
106+
clean::ResolvedPath { did, ref mut path, ..} => (did, path),
107+
_ => return false,
108+
};
109+
// If this QPath's trait `trait_did` is the same as, or a supertrait
110+
// of, the bound's trait `did` then we can keep going, otherwise
111+
// this is just a plain old equality bound.
112+
if !trait_is_same_or_supertrait(cx, did, trait_did) {
113+
return false
114+
}
115+
let last = path.segments.last_mut().expect("segments were empty");
116+
match last.args {
117+
PP::AngleBracketed { ref mut bindings, .. } => {
118+
bindings.push(clean::TypeBinding {
119+
name: name.to_string(),
120+
kind: clean::TypeBindingKind::Equality {
121+
ty: rhs.clone(),
122+
},
123+
});
124+
}
125+
PP::Parenthesized { ref mut output, .. } => {
126+
assert!(output.is_none());
127+
if *rhs != clean::Type::Tuple(Vec::new()) {
128+
*output = Some(rhs.clone());
129+
}
130+
}
131+
};
132+
true
133+
})
134+
}
135+
130136
pub fn ty_params(mut params: Vec<clean::GenericParamDef>) -> Vec<clean::GenericParamDef> {
131137
for param in &mut params {
132138
match param.kind {

src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use std::ops::Deref;
2+
13
pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
24

5+
pub fn func2<T>(_x: impl Deref<Target = Option<T>> + Iterator<Item = T>, _y: impl Iterator<Item = u8>) {}
6+
37
pub struct Foo;
48

59
impl Foo {

src/test/rustdoc/inline_cross/impl_trait.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ extern crate impl_trait_aux;
77
// @!has - '//pre[@class="rust fn"]' 'where'
88
pub use impl_trait_aux::func;
99

10+
// @has impl_trait/fn.func2.html
11+
// @has - '//pre[@class="rust fn"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
12+
// @has - '//pre[@class="rust fn"]' "_y: impl Iterator<Item = u8>)"
13+
// @!has - '//pre[@class="rust fn"]' 'where'
14+
pub use impl_trait_aux::func2;
15+
1016
// @has impl_trait/struct.Foo.html
1117
// @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a)"
1218
// @!has - '//code[@id="method.v"]' 'where'

0 commit comments

Comments
 (0)