Skip to content

Commit e58df0d

Browse files
committed
Auto merge of #49304 - sinkuu:impl_trait_rustdoc, r=QuietMisdreavus
Rustdoc support for universal_impl_trait Hides type parameters synthesized by `impl Trait`-in-argument-position, and enables links to trait names. <img alt="before" src="https://user-images.githubusercontent.com/7091080/37831646-a61413c6-2ee9-11e8-8ec2-a6137956d922.png" width="450"/> ↓ <img alt="after" src="https://user-images.githubusercontent.com/7091080/37831657-b2ff0ae6-2ee9-11e8-8797-fdad904782bf.png" width="450"/> Fixes #49309
2 parents 59ec9bf + 4800afa commit e58df0d

File tree

4 files changed

+127
-28
lines changed

4 files changed

+127
-28
lines changed

Diff for: src/librustdoc/clean/mod.rs

+67-12
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,7 @@ pub struct TyParam {
12351235
pub did: DefId,
12361236
pub bounds: Vec<TyParamBound>,
12371237
pub default: Option<Type>,
1238+
pub synthetic: Option<hir::SyntheticTyParamKind>,
12381239
}
12391240

12401241
impl Clean<TyParam> for hir::TyParam {
@@ -1244,6 +1245,7 @@ impl Clean<TyParam> for hir::TyParam {
12441245
did: cx.tcx.hir.local_def_id(self.id),
12451246
bounds: self.bounds.clean(cx),
12461247
default: self.default.clean(cx),
1248+
synthetic: self.synthetic,
12471249
}
12481250
}
12491251
}
@@ -1259,7 +1261,8 @@ impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
12591261
Some(cx.tcx.type_of(self.def_id).clean(cx))
12601262
} else {
12611263
None
1262-
}
1264+
},
1265+
synthetic: None,
12631266
}
12641267
}
12651268
}
@@ -1627,6 +1630,16 @@ pub enum GenericParam {
16271630
Type(TyParam),
16281631
}
16291632

1633+
impl GenericParam {
1634+
pub fn is_synthetic_type_param(&self) -> bool {
1635+
if let GenericParam::Type(ref t) = *self {
1636+
t.synthetic.is_some()
1637+
} else {
1638+
false
1639+
}
1640+
}
1641+
}
1642+
16301643
impl Clean<GenericParam> for hir::GenericParam {
16311644
fn clean(&self, cx: &DocContext) -> GenericParam {
16321645
match *self {
@@ -1759,11 +1772,12 @@ pub struct Method {
17591772

17601773
impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
17611774
fn clean(&self, cx: &DocContext) -> Method {
1775+
let generics = self.1.clean(cx);
17621776
Method {
1763-
generics: self.1.clean(cx),
1777+
decl: enter_impl_trait(cx, &generics.params, || (&*self.0.decl, self.2).clean(cx)),
1778+
generics,
17641779
unsafety: self.0.unsafety,
17651780
constness: self.0.constness,
1766-
decl: (&*self.0.decl, self.2).clean(cx),
17671781
abi: self.0.abi
17681782
}
17691783
}
@@ -1788,6 +1802,8 @@ pub struct Function {
17881802

17891803
impl Clean<Item> for doctree::Function {
17901804
fn clean(&self, cx: &DocContext) -> Item {
1805+
let generics = self.generics.clean(cx);
1806+
let decl = enter_impl_trait(cx, &generics.params, || (&self.decl, self.body).clean(cx));
17911807
Item {
17921808
name: Some(self.name.clean(cx)),
17931809
attrs: self.attrs.clean(cx),
@@ -1797,8 +1813,8 @@ impl Clean<Item> for doctree::Function {
17971813
deprecation: self.depr.clean(cx),
17981814
def_id: cx.tcx.hir.local_def_id(self.id),
17991815
inner: FunctionItem(Function {
1800-
decl: (&self.decl, self.body).clean(cx),
1801-
generics: self.generics.clean(cx),
1816+
decl,
1817+
generics,
18021818
unsafety: self.unsafety,
18031819
constness: self.constness,
18041820
abi: self.abi,
@@ -1883,7 +1899,8 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
18831899
vec![].into_iter()
18841900
} else {
18851901
cx.tcx.fn_arg_names(did).into_iter()
1886-
}.peekable();
1902+
};
1903+
18871904
FnDecl {
18881905
output: Return(sig.skip_binder().output().clean(cx)),
18891906
attrs: Attributes::default(),
@@ -2025,10 +2042,13 @@ impl Clean<Item> for hir::TraitItem {
20252042
MethodItem((sig, &self.generics, body).clean(cx))
20262043
}
20272044
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
2045+
let generics = self.generics.clean(cx);
20282046
TyMethodItem(TyMethod {
20292047
unsafety: sig.unsafety.clone(),
2030-
decl: (&*sig.decl, &names[..]).clean(cx),
2031-
generics: self.generics.clean(cx),
2048+
decl: enter_impl_trait(cx, &generics.params, || {
2049+
(&*sig.decl, &names[..]).clean(cx)
2050+
}),
2051+
generics,
20322052
abi: sig.abi
20332053
})
20342054
}
@@ -2532,6 +2552,12 @@ impl Clean<Type> for hir::Ty {
25322552
return new_ty;
25332553
}
25342554

2555+
if let Def::TyParam(did) = path.def {
2556+
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
2557+
return ImplTrait(bounds);
2558+
}
2559+
}
2560+
25352561
let mut alias = None;
25362562
if let Def::TyAlias(def_id) = path.def {
25372563
// Substitute private type aliases
@@ -3244,10 +3270,13 @@ pub struct BareFunctionDecl {
32443270

32453271
impl Clean<BareFunctionDecl> for hir::BareFnTy {
32463272
fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
3273+
let generic_params = self.generic_params.clean(cx);
32473274
BareFunctionDecl {
32483275
unsafety: self.unsafety,
3249-
generic_params: self.generic_params.clean(cx),
3250-
decl: (&*self.decl, &self.arg_names[..]).clean(cx),
3276+
decl: enter_impl_trait(cx, &generic_params, || {
3277+
(&*self.decl, &self.arg_names[..]).clean(cx)
3278+
}),
3279+
generic_params,
32513280
abi: self.abi,
32523281
}
32533282
}
@@ -3548,9 +3577,12 @@ impl Clean<Item> for hir::ForeignItem {
35483577
fn clean(&self, cx: &DocContext) -> Item {
35493578
let inner = match self.node {
35503579
hir::ForeignItemFn(ref decl, ref names, ref generics) => {
3580+
let generics = generics.clean(cx);
35513581
ForeignFunctionItem(Function {
3552-
decl: (&**decl, &names[..]).clean(cx),
3553-
generics: generics.clean(cx),
3582+
decl: enter_impl_trait(cx, &generics.params, || {
3583+
(&**decl, &names[..]).clean(cx)
3584+
}),
3585+
generics,
35543586
unsafety: hir::Unsafety::Unsafe,
35553587
abi: Abi::Rust,
35563588
constness: hir::Constness::NotConst,
@@ -3852,6 +3884,29 @@ pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option<String>) -> Vec<
38523884
once(crate_name).chain(relative).collect()
38533885
}
38543886

3887+
pub fn enter_impl_trait<F, R>(cx: &DocContext, gps: &[GenericParam], f: F) -> R
3888+
where
3889+
F: FnOnce() -> R,
3890+
{
3891+
let bounds = gps.iter()
3892+
.filter_map(|p| {
3893+
if let GenericParam::Type(ref tp) = *p {
3894+
if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
3895+
return Some((tp.did, tp.bounds.clone()));
3896+
}
3897+
}
3898+
3899+
None
3900+
})
3901+
.collect::<FxHashMap<DefId, Vec<TyParamBound>>>();
3902+
3903+
let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), bounds);
3904+
let r = f();
3905+
assert!(cx.impl_trait_bounds.borrow().is_empty());
3906+
*cx.impl_trait_bounds.borrow_mut() = old_bounds;
3907+
r
3908+
}
3909+
38553910
// Start of code copied from rust-clippy
38563911

38573912
pub fn get_trait_def_id(tcx: &TyCtxt, path: &[&str], use_local: bool) -> Option<DefId> {

Diff for: src/librustdoc/core.rs

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
7272
pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
7373
/// Table node id of lifetime parameter definition -> substituted lifetime
7474
pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
75+
/// Table DefId of `impl Trait` in argument position -> bounds
76+
pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::TyParamBound>>>,
7577
pub send_trait: Option<DefId>,
7678
pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
7779
pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
@@ -261,6 +263,7 @@ pub fn run_core(search_paths: SearchPaths,
261263
renderinfo: Default::default(),
262264
ty_substs: Default::default(),
263265
lt_substs: Default::default(),
266+
impl_trait_bounds: Default::default(),
264267
mod_ids: Default::default(),
265268
send_trait: send_trait,
266269
fake_def_ids: RefCell::new(FxHashMap()),

Diff for: src/librustdoc/html/format.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,17 @@ impl fmt::Display for clean::GenericParam {
148148

149149
impl fmt::Display for clean::Generics {
150150
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151-
if self.params.is_empty() { return Ok(()) }
151+
let real_params = self.params
152+
.iter()
153+
.filter(|p| !p.is_synthetic_type_param())
154+
.collect::<Vec<_>>();
155+
if real_params.is_empty() {
156+
return Ok(());
157+
}
152158
if f.alternate() {
153-
write!(f, "<{:#}>", CommaSep(&self.params))
159+
write!(f, "<{:#}>", CommaSep(&real_params))
154160
} else {
155-
write!(f, "&lt;{}&gt;", CommaSep(&self.params))
161+
write!(f, "&lt;{}&gt;", CommaSep(&real_params))
156162
}
157163
}
158164
}
@@ -575,7 +581,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
575581
}
576582
many => {
577583
primitive_link(f, PrimitiveType::Tuple, "(")?;
578-
fmt::Display::fmt(&CommaSep(&many), f)?;
584+
fmt::Display::fmt(&CommaSep(many), f)?;
579585
primitive_link(f, PrimitiveType::Tuple, ")")
580586
}
581587
}
@@ -661,18 +667,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
661667
}
662668
}
663669
clean::ImplTrait(ref bounds) => {
664-
write!(f, "impl ")?;
665-
for (i, bound) in bounds.iter().enumerate() {
666-
if i != 0 {
667-
write!(f, " + ")?;
668-
}
669-
if f.alternate() {
670-
write!(f, "{:#}", *bound)?;
671-
} else {
672-
write!(f, "{}", *bound)?;
673-
}
674-
}
675-
Ok(())
670+
write!(f, "impl {}", TyParamBounds(bounds))
676671
}
677672
clean::QPath { ref name, ref self_type, ref trait_ } => {
678673
let should_show_cast = match *trait_ {

Diff for: src/test/rustdoc/universal-impl-trait.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(universal_impl_trait)]
12+
#![crate_name = "foo"]
13+
14+
// @has foo/fn.foo.html
15+
// @has - //pre 'foo('
16+
// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Clone\.html"'
17+
// @matches - '_z: .+impl.+trait\.Copy\.html.+, impl.+trait\.Clone\.html'
18+
pub fn foo(_x: impl Clone, _y: i32, _z: (impl Copy, impl Clone)) {
19+
}
20+
21+
pub trait Trait {
22+
// @has foo/trait.Trait.html
23+
// @has - 'method</a>('
24+
// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
25+
fn method(&self, _x: impl std::fmt::Debug) {
26+
}
27+
}
28+
29+
pub struct S<T>(T);
30+
31+
impl<T> S<T> {
32+
// @has foo/struct.S.html
33+
// @has - 'bar</a>('
34+
// @matches - '_bar: impl <a class="trait" href="[^"]+/trait\.Copy\.html"'
35+
pub fn bar(_bar: impl Copy) {
36+
}
37+
38+
// @has - 'baz</a>('
39+
// @matches - '_baz:.+struct\.S\.html.+impl .+trait\.Clone\.html'
40+
pub fn baz(_baz: S<impl Clone>) {
41+
}
42+
}
43+
44+
// @has - 'method</a>('
45+
// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
46+
impl<T> Trait for S<T> {}

0 commit comments

Comments
 (0)