about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/clean/auto_trait.rs171
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/html/format.rs6
-rw-r--r--src/librustdoc/html/render.rs95
-rw-r--r--src/test/rustdoc/generic-impl.rs25
-rw-r--r--src/test/rustdoc/manual_impl.rs1
-rw-r--r--src/test/rustdoc/sidebar-items.rs8
9 files changed, 246 insertions, 69 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 0cdab134815..c30d6817b46 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -8,10 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::traits::auto_trait as auto;
-use rustc::ty::TypeFoldable;
 use rustc::hir;
+use rustc::traits::{self, auto_trait as auto};
+use rustc::ty::{self, ToPredicate, TypeFoldable};
+use rustc::ty::subst::Subst;
+use rustc::infer::InferOk;
 use std::fmt::Debug;
+use syntax_pos::DUMMY_SP;
+
+use core::DocAccessLevels;
 
 use super::*;
 
@@ -75,6 +80,141 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
         self.get_auto_trait_impls(did, &def_ctor, Some(name))
     }
 
+    fn get_real_ty<F>(&self,
+                      def_id: DefId,
+                      def_ctor: &F,
+                      real_name: &Option<Ident>,
+                      generics: &ty::Generics,
+    ) -> hir::Ty
+    where F: Fn(DefId) -> Def {
+        let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
+        let mut segments = path.segments.into_vec();
+        let last = segments.pop().unwrap();
+
+        segments.push(hir::PathSegment::new(
+            real_name.unwrap_or(last.ident),
+            self.generics_to_path_params(generics.clone()),
+            false,
+        ));
+
+        let new_path = hir::Path {
+            span: path.span,
+            def: path.def,
+            segments: HirVec::from_vec(segments),
+        };
+
+        hir::Ty {
+            id: ast::DUMMY_NODE_ID,
+            node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
+            span: DUMMY_SP,
+            hir_id: hir::DUMMY_HIR_ID,
+        }
+    }
+
+    pub fn get_blanket_impls<F>(
+        &self,
+        def_id: DefId,
+        def_ctor: &F,
+        name: Option<String>,
+        generics: &ty::Generics,
+    ) -> Vec<Item>
+    where F: Fn(DefId) -> Def {
+        let ty = self.cx.tcx.type_of(def_id);
+        let mut traits = Vec::new();
+        if self.cx.access_levels.borrow().is_doc_reachable(def_id) {
+            let real_name = name.clone().map(|name| Ident::from_str(&name));
+            let param_env = self.cx.tcx.param_env(def_id);
+            for &trait_def_id in self.cx.all_traits.iter() {
+                if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
+                   self.cx.generated_synthetics
+                          .borrow_mut()
+                          .get(&(def_id, trait_def_id))
+                          .is_some() {
+                    continue
+                }
+                self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
+                    self.cx.tcx.infer_ctxt().enter(|infcx| {
+                        let t_generics = infcx.tcx.generics_of(impl_def_id);
+                        let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap();
+
+                        match infcx.tcx.type_of(impl_def_id).sty {
+                            ::rustc::ty::TypeVariants::TyParam(_) => {},
+                            _ => return,
+                        }
+
+                        let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
+                        let ty = ty.subst(infcx.tcx, substs);
+                        let param_env = param_env.subst(infcx.tcx, substs);
+
+                        let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+                        let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
+
+                        // Require the type the impl is implemented on to match
+                        // our type, and ignore the impl if there was a mismatch.
+                        let cause = traits::ObligationCause::dummy();
+                        let eq_result = infcx.at(&cause, param_env)
+                                             .eq(trait_ref.self_ty(), ty);
+                        if let Ok(InferOk { value: (), obligations }) = eq_result {
+                            // FIXME(eddyb) ignoring `obligations` might cause false positives.
+                            drop(obligations);
+
+                            let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
+                                cause.clone(),
+                                param_env,
+                                trait_ref.to_predicate(),
+                            ));
+                            if !may_apply {
+                                return
+                            }
+                            self.cx.generated_synthetics.borrow_mut()
+                                                        .insert((def_id, trait_def_id));
+                            let trait_ = hir::TraitRef {
+                                path: get_path_for_type(infcx.tcx,
+                                                        trait_def_id,
+                                                        hir::def::Def::Trait),
+                                ref_id: ast::DUMMY_NODE_ID,
+                            };
+                            let provided_trait_methods =
+                                infcx.tcx.provided_trait_methods(trait_def_id)
+                                         .into_iter()
+                                         .map(|meth| meth.ident.to_string())
+                                         .collect();
+
+                            let ty = self.get_real_ty(def_id, def_ctor, &real_name, generics);
+                            let predicates = infcx.tcx.predicates_of(impl_def_id);
+
+                            traits.push(Item {
+                                source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
+                                name: None,
+                                attrs: Default::default(),
+                                visibility: None,
+                                def_id: self.next_def_id(impl_def_id.krate),
+                                stability: None,
+                                deprecation: None,
+                                inner: ImplItem(Impl {
+                                    unsafety: hir::Unsafety::Normal,
+                                    generics: (t_generics, &predicates).clean(self.cx),
+                                    provided_trait_methods,
+                                    trait_: Some(trait_.clean(self.cx)),
+                                    for_: ty.clean(self.cx),
+                                    items: infcx.tcx.associated_items(impl_def_id)
+                                                    .collect::<Vec<_>>()
+                                                    .clean(self.cx),
+                                    polarity: None,
+                                    synthetic: false,
+                                    blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
+                                                                .clean(self.cx)),
+                                }),
+                            });
+                            debug!("{:?} => {}", trait_ref, may_apply);
+                        }
+                    });
+                });
+            }
+        }
+        traits
+    }
+
     pub fn get_auto_trait_impls<F>(
         &self,
         def_id: DefId,
@@ -122,6 +262,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                 def_ctor,
                 tcx.require_lang_item(lang_items::SyncTraitLangItem),
             ).into_iter())
+            .chain(self.get_blanket_impls(def_id, def_ctor, name, &generics).into_iter())
             .collect();
 
         debug!(
@@ -196,31 +337,8 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                 }
                 _ => unreachable!(),
             };
-
-            let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
-            let mut segments = path.segments.into_vec();
-            let last = segments.pop().unwrap();
-
             let real_name = name.map(|name| Ident::from_str(&name));
-
-            segments.push(hir::PathSegment::new(
-                real_name.unwrap_or(last.ident),
-                self.generics_to_path_params(generics.clone()),
-                false,
-            ));
-
-            let new_path = hir::Path {
-                span: path.span,
-                def: path.def,
-                segments: HirVec::from_vec(segments),
-            };
-
-            let ty = hir::Ty {
-                id: ast::DUMMY_NODE_ID,
-                node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
-                span: DUMMY_SP,
-                hir_id: hir::DUMMY_HIR_ID,
-            };
+            let ty = self.get_real_ty(def_id, def_ctor, &real_name, &generics);
 
             return Some(Item {
                 source: Span::empty(),
@@ -239,6 +357,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                     items: Vec::new(),
                     polarity,
                     synthetic: true,
+                    blanket_impl: None,
                 }),
             });
         }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 0117e4fde84..9245ef3cf50 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -275,7 +275,6 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
     if auto_traits {
         let auto_impls = get_auto_traits_with_def_id(cx, did);
         let mut renderinfo = cx.renderinfo.borrow_mut();
-
         let new_impls: Vec<clean::Item> = auto_impls.into_iter()
             .filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
 
@@ -415,6 +414,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
             items: trait_items,
             polarity: Some(polarity.clean(cx)),
             synthetic: false,
+            blanket_impl: None,
         }),
         source: tcx.def_span(did).clean(cx),
         name: None,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c601f138d0a..c050e30fea0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1549,7 +1549,6 @@ impl GenericBound {
     }
 
     fn get_trait_type(&self) -> Option<Type> {
-
         if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
             return Some(trait_.clone());
         }
@@ -3880,6 +3879,7 @@ pub struct Impl {
     pub items: Vec<Item>,
     pub polarity: Option<ImplPolarity>,
     pub synthetic: bool,
+    pub blanket_impl: Option<Type>,
 }
 
 pub fn get_auto_traits_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec<Item> {
@@ -3947,6 +3947,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
                 items,
                 polarity: Some(self.polarity.clean(cx)),
                 synthetic: false,
+                blanket_impl: None,
             })
         });
         ret
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 4b8dbaf4211..77375442d4c 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -11,7 +11,7 @@
 use rustc_lint;
 use rustc_driver::{self, driver, target_features, abort_on_err};
 use rustc::session::{self, config};
-use rustc::hir::def_id::{DefId, CrateNum};
+use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
 use rustc::hir::def::Def;
 use rustc::middle::cstore::CrateStore;
 use rustc::middle::privacy::AccessLevels;
@@ -84,6 +84,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
     /// Maps (type_id, trait_id) -> auto trait impl
     pub generated_synthetics: RefCell<FxHashSet<(DefId, DefId)>>,
     pub current_item_name: RefCell<Option<Name>>,
+    pub all_traits: Vec<DefId>,
 }
 
 impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
@@ -386,6 +387,7 @@ pub fn run_core(search_paths: SearchPaths,
                 all_fake_def_ids: RefCell::new(FxHashSet()),
                 generated_synthetics: RefCell::new(FxHashSet()),
                 current_item_name: RefCell::new(None),
+                all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
             };
             debug!("crate: {:?}", tcx.hir.krate());
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 2377354b85f..9c7354a7c63 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -769,7 +769,11 @@ fn fmt_impl(i: &clean::Impl,
         write!(f, " for ")?;
     }
 
-    fmt_type(&i.for_, f, use_absolute)?;
+    if let Some(ref ty) = i.blanket_impl {
+        fmt_type(ty, f, use_absolute)?;
+    } else {
+        fmt_type(&i.for_, f, use_absolute)?;
+    }
 
     fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
     Ok(())
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 81fef9bf83e..79c127a1c40 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -177,7 +177,7 @@ pub enum ExternalLocation {
 }
 
 /// Metadata about implementations for a type or trait.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct Impl {
     pub impl_item: clean::Item,
 }
@@ -2900,18 +2900,18 @@ fn item_trait(
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
 
     let cache = cache();
-    let impl_header = "
-        <h2 id='implementors' class='small-section-header'>
-          Implementors<a href='#implementors' class='anchor'></a>
-        </h2>
-        <ul class='item-list' id='implementors-list'>
+    let impl_header = "\
+        <h2 id='implementors' class='small-section-header'>\
+          Implementors<a href='#implementors' class='anchor'></a>\
+        </h2>\
+        <ul class='item-list' id='implementors-list'>\
     ";
 
-    let synthetic_impl_header = "
-        <h2 id='synthetic-implementors' class='small-section-header'>
-          Auto implementors<a href='#synthetic-implementors' class='anchor'></a>
-        </h2>
-        <ul class='item-list' id='synthetic-implementors-list'>
+    let synthetic_impl_header = "\
+        <h2 id='synthetic-implementors' class='small-section-header'>\
+          Auto implementors<a href='#synthetic-implementors' class='anchor'></a>\
+        </h2>\
+        <ul class='item-list' id='synthetic-implementors-list'>\
     ";
 
     let mut synthetic_types = Vec::new();
@@ -2942,9 +2942,9 @@ fn item_trait(
                                          .map_or(true, |d| cache.paths.contains_key(&d)));
 
 
-        let (synthetic, concrete) = local.iter()
-            .partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
-
+        let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
+            .filter(|i| i.inner_impl().blanket_impl.is_none())
+            .partition(|i| i.inner_impl().synthetic);
 
         if !foreign.is_empty() {
             write!(w, "
@@ -3590,18 +3590,19 @@ fn render_assoc_items(w: &mut fmt::Formatter,
     if !non_trait.is_empty() {
         let render_mode = match what {
             AssocItemRender::All => {
-                write!(w, "
-                    <h2 id='methods' class='small-section-header'>
-                      Methods<a href='#methods' class='anchor'></a>
-                    </h2>
+                write!(w, "\
+                    <h2 id='methods' class='small-section-header'>\
+                      Methods<a href='#methods' class='anchor'></a>\
+                    </h2>\
                 ")?;
                 RenderMode::Normal
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
-                write!(w, "
-                    <h2 id='deref-methods' class='small-section-header'>
-                      Methods from {}&lt;Target = {}&gt;<a href='#deref-methods' class='anchor'></a>
-                    </h2>
+                write!(w, "\
+                    <h2 id='deref-methods' class='small-section-header'>\
+                      Methods from {}&lt;Target = {}&gt;\
+                      <a href='#deref-methods' class='anchor'></a>\
+                    </h2>\
                 ", trait_, type_)?;
                 RenderMode::ForDeref { mut_: deref_mut_ }
             }
@@ -3625,9 +3626,12 @@ fn render_assoc_items(w: &mut fmt::Formatter,
             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?;
         }
 
-        let (synthetic, concrete) = traits
+        let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = traits
             .iter()
-            .partition::<Vec<_>, _>(|t| t.inner_impl().synthetic);
+            .partition(|t| t.inner_impl().synthetic);
+        let (blanket_impl, concrete) = concrete
+            .into_iter()
+            .partition(|t| t.inner_impl().blanket_impl.is_some());
 
         struct RendererStruct<'a, 'b, 'c>(&'a Context, Vec<&'b &'b Impl>, &'c clean::Item);
 
@@ -3639,23 +3643,36 @@ fn render_assoc_items(w: &mut fmt::Formatter,
 
         let impls = format!("{}", RendererStruct(cx, concrete, containing_item));
         if !impls.is_empty() {
-            write!(w, "
-                <h2 id='implementations' class='small-section-header'>
-                  Trait Implementations<a href='#implementations' class='anchor'></a>
-                </h2>
+            write!(w, "\
+                <h2 id='implementations' class='small-section-header'>\
+                  Trait Implementations<a href='#implementations' class='anchor'></a>\
+                </h2>\
                 <div id='implementations-list'>{}</div>", impls)?;
         }
 
         if !synthetic.is_empty() {
-            write!(w, "
-                <h2 id='synthetic-implementations' class='small-section-header'>
-                  Auto Trait Implementations<a href='#synthetic-implementations' class='anchor'></a>
-                </h2>
-                <div id='synthetic-implementations-list'>
+            write!(w, "\
+                <h2 id='synthetic-implementations' class='small-section-header'>\
+                  Auto Trait Implementations\
+                  <a href='#synthetic-implementations' class='anchor'></a>\
+                </h2>\
+                <div id='synthetic-implementations-list'>\
             ")?;
             render_impls(cx, w, &synthetic, containing_item)?;
             write!(w, "</div>")?;
         }
+
+        if !blanket_impl.is_empty() {
+            write!(w, "\
+                <h2 id='blanket-implementations' class='small-section-header'>\
+                  Blanket Implementations\
+                  <a href='#blanket-implementations' class='anchor'></a>\
+                </h2>\
+                <div id='blanket-implementations-list'>\
+            ")?;
+            render_impls(cx, w, &blanket_impl, containing_item)?;
+            write!(w, "</div>")?;
+        }
     }
     Ok(())
 }
@@ -4201,12 +4218,16 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
                            .collect::<String>()
             };
 
-            let (synthetic, concrete) = v
+            let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = v
                 .iter()
                 .partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
+            let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
+                .into_iter()
+                .partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
 
             let concrete_format = format_impls(concrete);
             let synthetic_format = format_impls(synthetic);
+            let blanket_format = format_impls(blanket_impl);
 
             if !concrete_format.is_empty() {
                 out.push_str("<a class=\"sidebar-title\" href=\"#implementations\">\
@@ -4219,6 +4240,12 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
                               Auto Trait Implementations</a>");
                 out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", synthetic_format));
             }
+
+            if !blanket_format.is_empty() {
+                out.push_str("<a class=\"sidebar-title\" href=\"#blanket-implementations\">\
+                              Blanket Implementations</a>");
+                out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", blanket_format));
+            }
         }
     }
 
diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs
new file mode 100644
index 00000000000..e2665fd8f37
--- /dev/null
+++ b/src/test/rustdoc/generic-impl.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![crate_name = "foo"]
+
+use std::fmt;
+
+// @!has foo/struct.Bar.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+pub struct Bar;
+
+// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+pub struct Foo;
+
+impl fmt::Display for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Foo")
+    }
+}
diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs
index befd3161ac4..54a8a764833 100644
--- a/src/test/rustdoc/manual_impl.rs
+++ b/src/test/rustdoc/manual_impl.rs
@@ -56,7 +56,6 @@ impl T for S1 {
 // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
 // @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
 // @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @!has - '//*[@class="docblock"]' 'Read more'
 pub struct S2(usize);
 
 /// Docs associated with the S2 trait implementation.
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
index 9be40441e9d..3ecd6b63510 100644
--- a/src/test/rustdoc/sidebar-items.rs
+++ b/src/test/rustdoc/sidebar-items.rs
@@ -31,11 +31,11 @@ pub trait Foo {
 // @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields'
 // @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f"]' 'f'
 // @has - '//*[@class="sidebar-links"]/a[@href="#structfield.u"]' 'u'
-// @!has - '//*[@class="sidebar-links"]/a' 'w'
+// @!has - '//*[@class="sidebar-links"]/a' 'waza'
 pub struct Bar {
     pub f: u32,
     pub u: u32,
-    w: u32,
+    waza: u32,
 }
 
 // @has foo/enum.En.html
@@ -51,9 +51,9 @@ pub enum En {
 // @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields'
 // @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f1"]' 'f1'
 // @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f2"]' 'f2'
-// @!has - '//*[@class="sidebar-links"]/a' 'w'
+// @!has - '//*[@class="sidebar-links"]/a' 'waza'
 pub union MyUnion {
     pub f1: u32,
     pub f2: f32,
-    w: u32,
+    waza: u32,
 }