Skip to content

Commit c6e2897

Browse files
authored
Rollup merge of rust-lang#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 78ca1bd + ea3e804 commit c6e2897

File tree

6 files changed

+250
-67
lines changed

6 files changed

+250
-67
lines changed

src/librustdoc/clean/inline.rs

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

212212
let predicates = cx.tcx.predicates_of(did);
213-
let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
214-
let decl = (did, sig).clean(cx);
213+
let (generics, decl) = clean::enter_impl_trait(cx, || {
214+
((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx))
215+
});
215216
let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx);
216217
clean::Function {
217218
decl,
@@ -347,7 +348,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec<clean::Item>) {
347348
None
348349
}
349350
}).collect::<Vec<_>>(),
350-
(tcx.generics_of(did), &predicates).clean(cx),
351+
clean::enter_impl_trait(cx, || {
352+
(tcx.generics_of(did), &predicates).clean(cx)
353+
}),
351354
)
352355
};
353356
let polarity = tcx.impl_polarity(did);

src/librustdoc/clean/mod.rs

+129-17
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use std::u32;
4747

4848
use parking_lot::ReentrantMutex;
4949

50-
use crate::core::{self, DocContext};
50+
use crate::core::{self, DocContext, ImplTraitParam};
5151
use crate::doctree;
5252
use crate::visit_ast;
5353
use crate::html::render::{cache, ExternalLocation};
@@ -1536,7 +1536,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
15361536
ty::GenericParamDefKind::Lifetime => {
15371537
(self.name.to_string(), GenericParamDefKind::Lifetime)
15381538
}
1539-
ty::GenericParamDefKind::Type { has_default, .. } => {
1539+
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
15401540
cx.renderinfo.borrow_mut().external_param_names
15411541
.insert(self.def_id, self.name.clean(cx));
15421542
let default = if has_default {
@@ -1548,7 +1548,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
15481548
did: self.def_id,
15491549
bounds: vec![], // These are filled in from the where-clauses.
15501550
default,
1551-
synthetic: None,
1551+
synthetic,
15521552
})
15531553
}
15541554
ty::GenericParamDefKind::Const { .. } => {
@@ -1637,7 +1637,7 @@ impl Clean<Generics> for hir::Generics {
16371637
match param.kind {
16381638
GenericParamDefKind::Lifetime => unreachable!(),
16391639
GenericParamDefKind::Type { did, ref bounds, .. } => {
1640-
cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone());
1640+
cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone());
16411641
}
16421642
GenericParamDefKind::Const { .. } => unreachable!(),
16431643
}
@@ -1692,25 +1692,116 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
16921692

16931693
let (gens, preds) = *self;
16941694

1695+
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
1696+
// since `Clean for ty::Predicate` would consume them.
1697+
let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<GenericBound>>::default();
1698+
16951699
// Bounds in the type_params and lifetimes fields are repeated in the
16961700
// predicates field (see rustc_typeck::collect::ty_generics), so remove
16971701
// them.
1698-
let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind {
1699-
ty::GenericParamDefKind::Lifetime => None,
1700-
ty::GenericParamDefKind::Type { .. } => {
1701-
if param.name.as_symbol() == kw::SelfUpper {
1702-
assert_eq!(param.index, 0);
1703-
return None;
1702+
let stripped_typarams = gens.params.iter()
1703+
.filter_map(|param| match param.kind {
1704+
ty::GenericParamDefKind::Lifetime => None,
1705+
ty::GenericParamDefKind::Type { synthetic, .. } => {
1706+
if param.name.as_symbol() == kw::SelfUpper {
1707+
assert_eq!(param.index, 0);
1708+
return None;
1709+
}
1710+
if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
1711+
impl_trait.insert(param.index.into(), vec![]);
1712+
return None;
1713+
}
1714+
Some(param.clean(cx))
17041715
}
1705-
Some(param.clean(cx))
1706-
}
1707-
ty::GenericParamDefKind::Const { .. } => None,
1708-
}).collect::<Vec<GenericParamDef>>();
1716+
ty::GenericParamDefKind::Const { .. } => None,
1717+
}).collect::<Vec<GenericParamDef>>();
1718+
1719+
// param index -> [(DefId of trait, associated type name, type)]
1720+
let mut impl_trait_proj =
1721+
FxHashMap::<u32, Vec<(DefId, String, Ty<'tcx>)>>::default();
17091722

17101723
let mut where_predicates = preds.predicates.iter()
1711-
.flat_map(|(p, _)| p.clean(cx))
1724+
.flat_map(|(p, _)| {
1725+
let mut projection = None;
1726+
let param_idx = (|| {
1727+
if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
1728+
if let ty::Param(param) = trait_ref.self_ty().sty {
1729+
return Some(param.index);
1730+
}
1731+
} else if let Some(outlives) = p.to_opt_type_outlives() {
1732+
if let ty::Param(param) = outlives.skip_binder().0.sty {
1733+
return Some(param.index);
1734+
}
1735+
} else if let ty::Predicate::Projection(p) = p {
1736+
if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().sty {
1737+
projection = Some(p);
1738+
return Some(param.index);
1739+
}
1740+
}
1741+
1742+
None
1743+
})();
1744+
1745+
let p = p.clean(cx)?;
1746+
1747+
if let Some(param_idx) = param_idx {
1748+
if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
1749+
b.extend(
1750+
p.get_bounds()
1751+
.into_iter()
1752+
.flatten()
1753+
.cloned()
1754+
.filter(|b| !b.is_sized_bound(cx))
1755+
);
1756+
1757+
let proj = projection
1758+
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
1759+
if let Some(((_, trait_did, name), rhs)) =
1760+
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
1761+
{
1762+
impl_trait_proj
1763+
.entry(param_idx)
1764+
.or_default()
1765+
.push((trait_did, name.to_string(), rhs));
1766+
}
1767+
1768+
return None;
1769+
}
1770+
}
1771+
1772+
Some(p)
1773+
})
17121774
.collect::<Vec<_>>();
17131775

1776+
// Move `TraitPredicate`s to the front.
1777+
for (_, bounds) in impl_trait.iter_mut() {
1778+
bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b {
1779+
false
1780+
} else {
1781+
true
1782+
});
1783+
}
1784+
1785+
for (param, mut bounds) in impl_trait {
1786+
if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
1787+
if let Some(proj) = impl_trait_proj.remove(&idx) {
1788+
for (trait_did, name, rhs) in proj {
1789+
simplify::merge_bounds(
1790+
cx,
1791+
&mut bounds,
1792+
trait_did,
1793+
&name,
1794+
&rhs.clean(cx),
1795+
);
1796+
}
1797+
}
1798+
} else {
1799+
unreachable!();
1800+
}
1801+
1802+
cx.impl_trait_bounds.borrow_mut().insert(param, bounds);
1803+
}
1804+
17141805
// Type parameters and have a Sized bound by default unless removed with
17151806
// ?Sized. Scan through the predicates and mark any type parameter with
17161807
// a Sized bound, removing the bounds as we find them.
@@ -2609,6 +2700,21 @@ impl Type {
26092700
_ => false,
26102701
}
26112702
}
2703+
2704+
pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
2705+
let (self_, trait_, name) = match self {
2706+
QPath { ref self_type, ref trait_, ref name } => {
2707+
(self_type, trait_, name)
2708+
}
2709+
_ => return None,
2710+
};
2711+
let trait_did = match **trait_ {
2712+
ResolvedPath { did, .. } => did,
2713+
_ => return None,
2714+
};
2715+
Some((&self_, trait_did, name))
2716+
}
2717+
26122718
}
26132719

26142720
impl GetDefId for Type {
@@ -2787,7 +2893,7 @@ impl Clean<Type> for hir::Ty {
27872893
if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() {
27882894
return new_ty;
27892895
}
2790-
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
2896+
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) {
27912897
return ImplTrait(bounds);
27922898
}
27932899
}
@@ -3078,7 +3184,13 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
30783184

30793185
ty::Projection(ref data) => data.clean(cx),
30803186

3081-
ty::Param(ref p) => Generic(p.name.to_string()),
3187+
ty::Param(ref p) => {
3188+
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) {
3189+
ImplTrait(bounds)
3190+
} else {
3191+
Generic(p.name.to_string())
3192+
}
3193+
}
30823194

30833195
ty::Opaque(def_id, substs) => {
30843196
// 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
@@ -65,8 +65,8 @@ pub struct DocContext<'tcx> {
6565
pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
6666
/// Table `DefId` of const parameter -> substituted const
6767
pub ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
68-
/// Table DefId of `impl Trait` in argument position -> bounds
69-
pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::GenericBound>>>,
68+
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
69+
pub impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
7070
pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
7171
pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
7272
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
@@ -472,3 +472,23 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
472472
})
473473
})
474474
}
475+
476+
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
477+
/// for `impl Trait` in argument position.
478+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
479+
pub enum ImplTraitParam {
480+
DefId(DefId),
481+
ParamIndex(u32),
482+
}
483+
484+
impl From<DefId> for ImplTraitParam {
485+
fn from(did: DefId) -> Self {
486+
ImplTraitParam::DefId(did)
487+
}
488+
}
489+
490+
impl From<u32> for ImplTraitParam {
491+
fn from(idx: u32) -> Self {
492+
ImplTraitParam::ParamIndex(idx)
493+
}
494+
}

0 commit comments

Comments
 (0)