about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-03-28 05:29:57 +0000
committerbors <bors@rust-lang.org>2018-03-28 05:29:57 +0000
commite58df0d8c5221fa5743587740eb50e4db42c3d1e (patch)
treed7996f34294c11ec8b49e61725c0529119530c46
parent59ec9bfc66b86f04b50f00bb32839315f59252ec (diff)
parent4800afa5f5982b06d9cf27ae6003b058ca8855c8 (diff)
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
-rw-r--r--src/librustdoc/clean/mod.rs79
-rw-r--r--src/librustdoc/core.rs3
-rw-r--r--src/librustdoc/html/format.rs27
-rw-r--r--src/test/rustdoc/universal-impl-trait.rs46
4 files changed, 127 insertions, 28 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 73b3ae32cef..42c9d9e52f3 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1235,6 +1235,7 @@ pub struct TyParam {
     pub did: DefId,
     pub bounds: Vec<TyParamBound>,
     pub default: Option<Type>,
+    pub synthetic: Option<hir::SyntheticTyParamKind>,
 }
 
 impl Clean<TyParam> for hir::TyParam {
@@ -1244,6 +1245,7 @@ impl Clean<TyParam> for hir::TyParam {
             did: cx.tcx.hir.local_def_id(self.id),
             bounds: self.bounds.clean(cx),
             default: self.default.clean(cx),
+            synthetic: self.synthetic,
         }
     }
 }
@@ -1259,7 +1261,8 @@ impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
                 Some(cx.tcx.type_of(self.def_id).clean(cx))
             } else {
                 None
-            }
+            },
+            synthetic: None,
         }
     }
 }
@@ -1627,6 +1630,16 @@ pub enum GenericParam {
     Type(TyParam),
 }
 
+impl GenericParam {
+    pub fn is_synthetic_type_param(&self) -> bool {
+        if let GenericParam::Type(ref t) = *self {
+            t.synthetic.is_some()
+        } else {
+            false
+        }
+    }
+}
+
 impl Clean<GenericParam> for hir::GenericParam {
     fn clean(&self, cx: &DocContext) -> GenericParam {
         match *self {
@@ -1759,11 +1772,12 @@ pub struct Method {
 
 impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
     fn clean(&self, cx: &DocContext) -> Method {
+        let generics = self.1.clean(cx);
         Method {
-            generics: self.1.clean(cx),
+            decl: enter_impl_trait(cx, &generics.params, || (&*self.0.decl, self.2).clean(cx)),
+            generics,
             unsafety: self.0.unsafety,
             constness: self.0.constness,
-            decl: (&*self.0.decl, self.2).clean(cx),
             abi: self.0.abi
         }
     }
@@ -1788,6 +1802,8 @@ pub struct Function {
 
 impl Clean<Item> for doctree::Function {
     fn clean(&self, cx: &DocContext) -> Item {
+        let generics = self.generics.clean(cx);
+        let decl = enter_impl_trait(cx, &generics.params, || (&self.decl, self.body).clean(cx));
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -1797,8 +1813,8 @@ impl Clean<Item> for doctree::Function {
             deprecation: self.depr.clean(cx),
             def_id: cx.tcx.hir.local_def_id(self.id),
             inner: FunctionItem(Function {
-                decl: (&self.decl, self.body).clean(cx),
-                generics: self.generics.clean(cx),
+                decl,
+                generics,
                 unsafety: self.unsafety,
                 constness: self.constness,
                 abi: self.abi,
@@ -1883,7 +1899,8 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
             vec![].into_iter()
         } else {
             cx.tcx.fn_arg_names(did).into_iter()
-        }.peekable();
+        };
+
         FnDecl {
             output: Return(sig.skip_binder().output().clean(cx)),
             attrs: Attributes::default(),
@@ -2025,10 +2042,13 @@ impl Clean<Item> for hir::TraitItem {
                 MethodItem((sig, &self.generics, body).clean(cx))
             }
             hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
+                let generics = self.generics.clean(cx);
                 TyMethodItem(TyMethod {
                     unsafety: sig.unsafety.clone(),
-                    decl: (&*sig.decl, &names[..]).clean(cx),
-                    generics: self.generics.clean(cx),
+                    decl: enter_impl_trait(cx, &generics.params, || {
+                        (&*sig.decl, &names[..]).clean(cx)
+                    }),
+                    generics,
                     abi: sig.abi
                 })
             }
@@ -2532,6 +2552,12 @@ impl Clean<Type> for hir::Ty {
                     return new_ty;
                 }
 
+                if let Def::TyParam(did) = path.def {
+                    if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
+                        return ImplTrait(bounds);
+                    }
+                }
+
                 let mut alias = None;
                 if let Def::TyAlias(def_id) = path.def {
                     // Substitute private type aliases
@@ -3244,10 +3270,13 @@ pub struct BareFunctionDecl {
 
 impl Clean<BareFunctionDecl> for hir::BareFnTy {
     fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
+        let generic_params = self.generic_params.clean(cx);
         BareFunctionDecl {
             unsafety: self.unsafety,
-            generic_params: self.generic_params.clean(cx),
-            decl: (&*self.decl, &self.arg_names[..]).clean(cx),
+            decl: enter_impl_trait(cx, &generic_params, || {
+                (&*self.decl, &self.arg_names[..]).clean(cx)
+            }),
+            generic_params,
             abi: self.abi,
         }
     }
@@ -3548,9 +3577,12 @@ impl Clean<Item> for hir::ForeignItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
             hir::ForeignItemFn(ref decl, ref names, ref generics) => {
+                let generics = generics.clean(cx);
                 ForeignFunctionItem(Function {
-                    decl: (&**decl, &names[..]).clean(cx),
-                    generics: generics.clean(cx),
+                    decl: enter_impl_trait(cx, &generics.params, || {
+                        (&**decl, &names[..]).clean(cx)
+                    }),
+                    generics,
                     unsafety: hir::Unsafety::Unsafe,
                     abi: Abi::Rust,
                     constness: hir::Constness::NotConst,
@@ -3852,6 +3884,29 @@ pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option<String>) -> Vec<
     once(crate_name).chain(relative).collect()
 }
 
+pub fn enter_impl_trait<F, R>(cx: &DocContext, gps: &[GenericParam], f: F) -> R
+where
+    F: FnOnce() -> R,
+{
+    let bounds = gps.iter()
+        .filter_map(|p| {
+            if let GenericParam::Type(ref tp) = *p {
+                if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
+                    return Some((tp.did, tp.bounds.clone()));
+                }
+            }
+
+            None
+        })
+        .collect::<FxHashMap<DefId, Vec<TyParamBound>>>();
+
+    let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), bounds);
+    let r = f();
+    assert!(cx.impl_trait_bounds.borrow().is_empty());
+    *cx.impl_trait_bounds.borrow_mut() = old_bounds;
+    r
+}
+
 // Start of code copied from rust-clippy
 
 pub fn get_trait_def_id(tcx: &TyCtxt, path: &[&str], use_local: bool) -> Option<DefId> {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 1e0fafc8d9d..749d7ec126b 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -72,6 +72,8 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
     pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
     /// Table node id of lifetime parameter definition -> substituted lifetime
     pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
+    /// Table DefId of `impl Trait` in argument position -> bounds
+    pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::TyParamBound>>>,
     pub send_trait: Option<DefId>,
     pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
     pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
@@ -261,6 +263,7 @@ pub fn run_core(search_paths: SearchPaths,
             renderinfo: Default::default(),
             ty_substs: Default::default(),
             lt_substs: Default::default(),
+            impl_trait_bounds: Default::default(),
             mod_ids: Default::default(),
             send_trait: send_trait,
             fake_def_ids: RefCell::new(FxHashMap()),
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 2913ea6a78e..0a7e19fc643 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -148,11 +148,17 @@ impl fmt::Display for clean::GenericParam {
 
 impl fmt::Display for clean::Generics {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if self.params.is_empty() { return Ok(()) }
+        let real_params = self.params
+            .iter()
+            .filter(|p| !p.is_synthetic_type_param())
+            .collect::<Vec<_>>();
+        if real_params.is_empty() {
+            return Ok(());
+        }
         if f.alternate() {
-            write!(f, "<{:#}>", CommaSep(&self.params))
+            write!(f, "<{:#}>", CommaSep(&real_params))
         } else {
-            write!(f, "&lt;{}&gt;", CommaSep(&self.params))
+            write!(f, "&lt;{}&gt;", CommaSep(&real_params))
         }
     }
 }
@@ -575,7 +581,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
                 }
                 many => {
                     primitive_link(f, PrimitiveType::Tuple, "(")?;
-                    fmt::Display::fmt(&CommaSep(&many), f)?;
+                    fmt::Display::fmt(&CommaSep(many), f)?;
                     primitive_link(f, PrimitiveType::Tuple, ")")
                 }
             }
@@ -661,18 +667,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
             }
         }
         clean::ImplTrait(ref bounds) => {
-            write!(f, "impl ")?;
-            for (i, bound) in bounds.iter().enumerate() {
-                if i != 0 {
-                    write!(f, " + ")?;
-                }
-                if f.alternate() {
-                    write!(f, "{:#}", *bound)?;
-                } else {
-                    write!(f, "{}", *bound)?;
-                }
-            }
-            Ok(())
+            write!(f, "impl {}", TyParamBounds(bounds))
         }
         clean::QPath { ref name, ref self_type, ref trait_ } => {
             let should_show_cast = match *trait_ {
diff --git a/src/test/rustdoc/universal-impl-trait.rs b/src/test/rustdoc/universal-impl-trait.rs
new file mode 100644
index 00000000000..4cf99562c52
--- /dev/null
+++ b/src/test/rustdoc/universal-impl-trait.rs
@@ -0,0 +1,46 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(universal_impl_trait)]
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - //pre 'foo('
+// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Clone\.html"'
+// @matches - '_z: .+impl.+trait\.Copy\.html.+, impl.+trait\.Clone\.html'
+pub fn foo(_x: impl Clone, _y: i32, _z: (impl Copy, impl Clone)) {
+}
+
+pub trait Trait {
+    // @has foo/trait.Trait.html
+    // @has - 'method</a>('
+    // @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
+    fn method(&self, _x: impl std::fmt::Debug) {
+    }
+}
+
+pub struct S<T>(T);
+
+impl<T> S<T> {
+    // @has foo/struct.S.html
+    // @has - 'bar</a>('
+    // @matches - '_bar: impl <a class="trait" href="[^"]+/trait\.Copy\.html"'
+    pub fn bar(_bar: impl Copy) {
+    }
+
+    // @has - 'baz</a>('
+    // @matches - '_baz:.+struct\.S\.html.+impl .+trait\.Clone\.html'
+    pub fn baz(_baz: S<impl Clone>) {
+    }
+}
+
+// @has - 'method</a>('
+// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
+impl<T> Trait for S<T> {}