about summary refs log tree commit diff
diff options
context:
space:
mode:
authorShotaro Yamada <sinkuu@sinkuu.xyz>2019-06-21 12:23:05 +0900
committerShotaro Yamada <sinkuu@sinkuu.xyz>2019-08-19 17:49:54 +0900
commitb78367d8e8c3273b2cdeefc4ce55897e08e592b2 (patch)
tree0e2b01e87ebec1e1c9ade08a3c5c8e467cb9b741
parentcdff9189556bb7de2b9a8a72344c9d8ec6099fcd (diff)
downloadrust-b78367d8e8c3273b2cdeefc4ce55897e08e592b2.tar.gz
rust-b78367d8e8c3273b2cdeefc4ce55897e08e592b2.zip
Support `impl Trait` in inlined documentation
-rw-r--r--src/librustdoc/clean/inline.rs9
-rw-r--r--src/librustdoc/clean/mod.rs91
-rw-r--r--src/librustdoc/core.rs24
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs7
-rw-r--r--src/test/rustdoc/inline_cross/impl_trait.rs13
5 files changed, 122 insertions, 22 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 6f93c95edef..bcabefa51fa 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -217,8 +217,9 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
     };
 
     let predicates = cx.tcx.predicates_of(did);
-    let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
-    let decl = (did, sig).clean(cx);
+    let (generics, decl) = clean::enter_impl_trait(cx, || {
+        ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx))
+    });
     let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx);
     clean::Function {
         decl,
@@ -372,7 +373,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>,
                     None
                 }
             }).collect::<Vec<_>>(),
-            (tcx.generics_of(did), &predicates).clean(cx),
+            clean::enter_impl_trait(cx, || {
+                (tcx.generics_of(did), &predicates).clean(cx)
+            }),
         )
     };
     let polarity = tcx.impl_polarity(did);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9b4803ce41e..d3065f16793 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -45,7 +45,7 @@ use std::cell::RefCell;
 use std::sync::Arc;
 use std::u32;
 
-use crate::core::{self, DocContext};
+use crate::core::{self, DocContext, ImplTraitParam};
 use crate::doctree;
 use crate::html::render::{cache, ExternalLocation};
 use crate::html::item_type::ItemType;
@@ -1540,7 +1540,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
             ty::GenericParamDefKind::Lifetime => {
                 (self.name.to_string(), GenericParamDefKind::Lifetime)
             }
-            ty::GenericParamDefKind::Type { has_default, .. } => {
+            ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
                 cx.renderinfo.borrow_mut().external_param_names
                              .insert(self.def_id, self.name.clean(cx));
                 let default = if has_default {
@@ -1552,7 +1552,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
                     did: self.def_id,
                     bounds: vec![], // These are filled in from the where-clauses.
                     default,
-                    synthetic: None,
+                    synthetic,
                 })
             }
             ty::GenericParamDefKind::Const { .. } => {
@@ -1641,7 +1641,7 @@ impl Clean<Generics> for hir::Generics {
                 match param.kind {
                     GenericParamDefKind::Lifetime => unreachable!(),
                     GenericParamDefKind::Type { did, ref bounds, .. } => {
-                        cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone());
+                        cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone());
                     }
                     GenericParamDefKind::Const { .. } => unreachable!(),
                 }
@@ -1696,25 +1696,76 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
 
         let (gens, preds) = *self;
 
+        // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
+        // since `Clean for ty::Predicate` would consume them.
+        let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<_>>::default();
+
         // Bounds in the type_params and lifetimes fields are repeated in the
         // predicates field (see rustc_typeck::collect::ty_generics), so remove
         // them.
-        let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind {
-            ty::GenericParamDefKind::Lifetime => None,
-            ty::GenericParamDefKind::Type { .. } => {
-                if param.name.as_symbol() == kw::SelfUpper {
-                    assert_eq!(param.index, 0);
-                    return None;
+        let stripped_typarams = gens.params.iter()
+            .filter_map(|param| match param.kind {
+                ty::GenericParamDefKind::Lifetime => None,
+                ty::GenericParamDefKind::Type { synthetic, .. } => {
+                    if param.name.as_symbol() == kw::SelfUpper {
+                        assert_eq!(param.index, 0);
+                        return None;
+                    }
+                    if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
+                        impl_trait.insert(param.index.into(), vec![]);
+                        return None;
+                    }
+                    Some(param.clean(cx))
                 }
-                Some(param.clean(cx))
-            }
-            ty::GenericParamDefKind::Const { .. } => None,
-        }).collect::<Vec<GenericParamDef>>();
+                ty::GenericParamDefKind::Const { .. } => None,
+            }).collect::<Vec<GenericParamDef>>();
 
         let mut where_predicates = preds.predicates.iter()
-            .flat_map(|(p, _)| p.clean(cx))
+            .flat_map(|(p, _)| {
+                let param_idx = if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
+                    if let ty::Param(param) = trait_ref.self_ty().sty {
+                        Some(param.index)
+                    } else {
+                        None
+                    }
+                } else if let Some(outlives) = p.to_opt_type_outlives() {
+                    if let ty::Param(param) = outlives.skip_binder().0.sty {
+                        Some(param.index)
+                    } else {
+                        None
+                    }
+                } else {
+                    None
+                };
+
+                let p = p.clean(cx)?;
+
+                if let Some(b) = param_idx.and_then(|i| impl_trait.get_mut(&i.into())) {
+                    b.extend(
+                        p.get_bounds()
+                            .into_iter()
+                            .flatten()
+                            .cloned()
+                            .filter(|b| !b.is_sized_bound(cx))
+                    );
+                    return None;
+                }
+
+                Some(p)
+            })
             .collect::<Vec<_>>();
 
+        // Move `TraitPredicate`s to the front.
+        for (_, bounds) in impl_trait.iter_mut() {
+            bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b {
+                false
+            } else {
+                true
+            });
+        }
+
+        cx.impl_trait_bounds.borrow_mut().extend(impl_trait);
+
         // Type parameters and have a Sized bound by default unless removed with
         // ?Sized. Scan through the predicates and mark any type parameter with
         // a Sized bound, removing the bounds as we find them.
@@ -2791,7 +2842,7 @@ impl Clean<Type> for hir::Ty {
                     if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() {
                         return new_ty;
                     }
-                    if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
+                    if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) {
                         return ImplTrait(bounds);
                     }
                 }
@@ -3082,7 +3133,13 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
             ty::Projection(ref data) => data.clean(cx),
 
-            ty::Param(ref p) => Generic(p.name.to_string()),
+            ty::Param(ref p) => {
+                if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) {
+                    ImplTrait(bounds)
+                } else {
+                    Generic(p.name.to_string())
+                }
+            }
 
             ty::Opaque(def_id, substs) => {
                 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 87381f224d0..592a24fa4ae 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -61,8 +61,8 @@ pub struct DocContext<'tcx> {
     pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
     /// Table `DefId` of const parameter -> substituted const
     pub ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
-    /// Table DefId of `impl Trait` in argument position -> bounds
-    pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::GenericBound>>>,
+    /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
+    pub impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
     pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
     pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
     /// 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
         })
     })
 }
+
+/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
+/// for `impl Trait` in argument position.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ImplTraitParam {
+    DefId(DefId),
+    ParamIndex(u32),
+}
+
+impl From<DefId> for ImplTraitParam {
+    fn from(did: DefId) -> Self {
+        ImplTraitParam::DefId(did)
+    }
+}
+
+impl From<u32> for ImplTraitParam {
+    fn from(idx: u32) -> Self {
+        ImplTraitParam::ParamIndex(idx)
+    }
+}
diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs
new file mode 100644
index 00000000000..7807acbc4d6
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs
@@ -0,0 +1,7 @@
+pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
+
+pub struct Foo;
+
+impl Foo {
+    pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
+}
diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs
new file mode 100644
index 00000000000..091baa9773e
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/impl_trait.rs
@@ -0,0 +1,13 @@
+// aux-build:impl_trait_aux.rs
+
+extern crate impl_trait_aux;
+
+// @has impl_trait/fn.func.html
+// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a)"
+// @!has - '//pre[@class="rust fn"]' 'where'
+pub use impl_trait_aux::func;
+
+// @has impl_trait/struct.Foo.html
+// @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a)"
+// @!has - '//code[@id="method.v"]' 'where'
+pub use impl_trait_aux::Foo;