Skip to content

Commit 521d784

Browse files
committed
Auto merge of #61613 - sinkuu:impl_trait_inline, r=ollie27
Support `impl Trait` in inlined documentation `impl Trait` in argument position was not properly rendered when inlined from other crates. ([a live example on docs.rs](https://docs.rs/libp2p/0.8.1/libp2p/floodsub/struct.Floodsub.html#method.unsubscribe)) ![old](https://user-images.githubusercontent.com/7091080/59089838-14ba9900-8946-11e9-830b-53b317bdecb4.png) ↓ ![new](https://user-images.githubusercontent.com/7091080/59089844-16845c80-8946-11e9-9fe3-8998af9d73ce.png)
2 parents b1522e6 + 1fe6160 commit 521d784

File tree

6 files changed

+264
-67
lines changed

6 files changed

+264
-67
lines changed

src/librustdoc/clean/inline.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,9 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
217217
};
218218

219219
let predicates = cx.tcx.predicates_of(did);
220-
let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
221-
let decl = (did, sig).clean(cx);
220+
let (generics, decl) = clean::enter_impl_trait(cx, || {
221+
((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx))
222+
});
222223
let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx);
223224
clean::Function {
224225
decl,
@@ -372,7 +373,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>,
372373
None
373374
}
374375
}).collect::<Vec<_>>(),
375-
(tcx.generics_of(did), &predicates).clean(cx),
376+
clean::enter_impl_trait(cx, || {
377+
(tcx.generics_of(did), &predicates).clean(cx)
378+
}),
376379
)
377380
};
378381
let polarity = tcx.impl_polarity(did);

src/librustdoc/clean/mod.rs

+135-17
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use std::cell::RefCell;
4545
use std::sync::Arc;
4646
use std::u32;
4747

48-
use crate::core::{self, DocContext};
48+
use crate::core::{self, DocContext, ImplTraitParam};
4949
use crate::doctree;
5050
use crate::html::render::{cache, ExternalLocation};
5151
use crate::html::item_type::ItemType;
@@ -1540,7 +1540,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
15401540
ty::GenericParamDefKind::Lifetime => {
15411541
(self.name.to_string(), GenericParamDefKind::Lifetime)
15421542
}
1543-
ty::GenericParamDefKind::Type { has_default, .. } => {
1543+
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
15441544
cx.renderinfo.borrow_mut().external_param_names
15451545
.insert(self.def_id, self.name.clean(cx));
15461546
let default = if has_default {
@@ -1552,7 +1552,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
15521552
did: self.def_id,
15531553
bounds: vec![], // These are filled in from the where-clauses.
15541554
default,
1555-
synthetic: None,
1555+
synthetic,
15561556
})
15571557
}
15581558
ty::GenericParamDefKind::Const { .. } => {
@@ -1641,7 +1641,7 @@ impl Clean<Generics> for hir::Generics {
16411641
match param.kind {
16421642
GenericParamDefKind::Lifetime => unreachable!(),
16431643
GenericParamDefKind::Type { did, ref bounds, .. } => {
1644-
cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone());
1644+
cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone());
16451645
}
16461646
GenericParamDefKind::Const { .. } => unreachable!(),
16471647
}
@@ -1693,26 +1693,123 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
16931693
&'a &'tcx ty::GenericPredicates<'tcx>) {
16941694
fn clean(&self, cx: &DocContext<'_>) -> Generics {
16951695
use self::WherePredicate as WP;
1696+
use std::collections::BTreeMap;
16961697

16971698
let (gens, preds) = *self;
16981699

1700+
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
1701+
// since `Clean for ty::Predicate` would consume them.
1702+
let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
1703+
16991704
// Bounds in the type_params and lifetimes fields are repeated in the
17001705
// predicates field (see rustc_typeck::collect::ty_generics), so remove
17011706
// them.
1702-
let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind {
1703-
ty::GenericParamDefKind::Lifetime => None,
1704-
ty::GenericParamDefKind::Type { .. } => {
1705-
if param.name.as_symbol() == kw::SelfUpper {
1706-
assert_eq!(param.index, 0);
1707-
return None;
1707+
let stripped_typarams = gens.params.iter()
1708+
.filter_map(|param| match param.kind {
1709+
ty::GenericParamDefKind::Lifetime => None,
1710+
ty::GenericParamDefKind::Type { synthetic, .. } => {
1711+
if param.name.as_symbol() == kw::SelfUpper {
1712+
assert_eq!(param.index, 0);
1713+
return None;
1714+
}
1715+
if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
1716+
impl_trait.insert(param.index.into(), vec![]);
1717+
return None;
1718+
}
1719+
Some(param.clean(cx))
1720+
}
1721+
ty::GenericParamDefKind::Const { .. } => None,
1722+
}).collect::<Vec<GenericParamDef>>();
1723+
1724+
// param index -> [(DefId of trait, associated type name, type)]
1725+
let mut impl_trait_proj =
1726+
FxHashMap::<u32, Vec<(DefId, String, Ty<'tcx>)>>::default();
1727+
1728+
let where_predicates = preds.predicates.iter()
1729+
.flat_map(|(p, _)| {
1730+
let mut projection = None;
1731+
let param_idx = (|| {
1732+
if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
1733+
if let ty::Param(param) = trait_ref.self_ty().sty {
1734+
return Some(param.index);
1735+
}
1736+
} else if let Some(outlives) = p.to_opt_type_outlives() {
1737+
if let ty::Param(param) = outlives.skip_binder().0.sty {
1738+
return Some(param.index);
1739+
}
1740+
} else if let ty::Predicate::Projection(p) = p {
1741+
if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().sty {
1742+
projection = Some(p);
1743+
return Some(param.index);
1744+
}
1745+
}
1746+
1747+
None
1748+
})();
1749+
1750+
if let Some(param_idx) = param_idx {
1751+
if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
1752+
let p = p.clean(cx)?;
1753+
1754+
b.extend(
1755+
p.get_bounds()
1756+
.into_iter()
1757+
.flatten()
1758+
.cloned()
1759+
.filter(|b| !b.is_sized_bound(cx))
1760+
);
1761+
1762+
let proj = projection
1763+
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
1764+
if let Some(((_, trait_did, name), rhs)) =
1765+
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
1766+
{
1767+
impl_trait_proj
1768+
.entry(param_idx)
1769+
.or_default()
1770+
.push((trait_did, name.to_string(), rhs));
1771+
}
1772+
1773+
return None;
1774+
}
1775+
}
1776+
1777+
Some(p)
1778+
})
1779+
.collect::<Vec<_>>();
1780+
1781+
for (param, mut bounds) in impl_trait {
1782+
// Move trait bounds to the front.
1783+
bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b {
1784+
false
1785+
} else {
1786+
true
1787+
});
1788+
1789+
if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
1790+
if let Some(proj) = impl_trait_proj.remove(&idx) {
1791+
for (trait_did, name, rhs) in proj {
1792+
simplify::merge_bounds(
1793+
cx,
1794+
&mut bounds,
1795+
trait_did,
1796+
&name,
1797+
&rhs.clean(cx),
1798+
);
1799+
}
17081800
}
1709-
Some(param.clean(cx))
1801+
} else {
1802+
unreachable!();
17101803
}
1711-
ty::GenericParamDefKind::Const { .. } => None,
1712-
}).collect::<Vec<GenericParamDef>>();
17131804

1714-
let mut where_predicates = preds.predicates.iter()
1715-
.flat_map(|(p, _)| p.clean(cx))
1805+
cx.impl_trait_bounds.borrow_mut().insert(param, bounds);
1806+
}
1807+
1808+
// Now that `cx.impl_trait_bounds` is populated, we can process
1809+
// remaining predicates which could contain `impl Trait`.
1810+
let mut where_predicates = where_predicates
1811+
.into_iter()
1812+
.flat_map(|p| p.clean(cx))
17161813
.collect::<Vec<_>>();
17171814

17181815
// Type parameters and have a Sized bound by default unless removed with
@@ -2613,6 +2710,21 @@ impl Type {
26132710
_ => false,
26142711
}
26152712
}
2713+
2714+
pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
2715+
let (self_, trait_, name) = match self {
2716+
QPath { ref self_type, ref trait_, ref name } => {
2717+
(self_type, trait_, name)
2718+
}
2719+
_ => return None,
2720+
};
2721+
let trait_did = match **trait_ {
2722+
ResolvedPath { did, .. } => did,
2723+
_ => return None,
2724+
};
2725+
Some((&self_, trait_did, name))
2726+
}
2727+
26162728
}
26172729

26182730
impl GetDefId for Type {
@@ -2791,7 +2903,7 @@ impl Clean<Type> for hir::Ty {
27912903
if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() {
27922904
return new_ty;
27932905
}
2794-
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
2906+
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) {
27952907
return ImplTrait(bounds);
27962908
}
27972909
}
@@ -3082,7 +3194,13 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
30823194

30833195
ty::Projection(ref data) => data.clean(cx),
30843196

3085-
ty::Param(ref p) => Generic(p.name.to_string()),
3197+
ty::Param(ref p) => {
3198+
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) {
3199+
ImplTrait(bounds)
3200+
} else {
3201+
Generic(p.name.to_string())
3202+
}
3203+
}
30863204

30873205
ty::Opaque(def_id, substs) => {
30883206
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,

src/librustdoc/clean/simplify.rs

+51-45
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/librustdoc/core.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ pub struct DocContext<'tcx> {
6161
pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
6262
/// Table `DefId` of const parameter -> substituted const
6363
pub ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
64-
/// Table DefId of `impl Trait` in argument position -> bounds
65-
pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::GenericBound>>>,
64+
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
65+
pub impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
6666
pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
6767
pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
6868
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
@@ -459,3 +459,23 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
459459
})
460460
})
461461
}
462+
463+
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
464+
/// for `impl Trait` in argument position.
465+
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
466+
pub enum ImplTraitParam {
467+
DefId(DefId),
468+
ParamIndex(u32),
469+
}
470+
471+
impl From<DefId> for ImplTraitParam {
472+
fn from(did: DefId) -> Self {
473+
ImplTraitParam::DefId(did)
474+
}
475+
}
476+
477+
impl From<u32> for ImplTraitParam {
478+
fn from(idx: u32) -> Self {
479+
ImplTraitParam::ParamIndex(idx)
480+
}
481+
}

0 commit comments

Comments
 (0)