diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index ea25ac5c682..f466183bec8 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -105,16 +105,19 @@ pub fn get_auto_trait_impls( let generics = self.cx.tcx.generics_of(def_id); let ty = self.cx.tcx.type_of(def_id); - let mut traits = FxHashMap(); + let mut traits = Vec::new(); if self.cx.crate_name != Some("core".to_string()) { if let ty::TyAdt(_adt, _) = ty.sty { + 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 traits.get(&trait_def_id).is_some() || - !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) { + 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 } - let t_name = self.cx.tcx.item_name(trait_def_id).to_string(); self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| { self.cx.tcx.infer_ctxt().enter(|infcx| { let generics = infcx.tcx.generics_of(impl_def_id); @@ -124,7 +127,7 @@ pub fn get_auto_trait_impls( ::rustc::ty::TypeVariants::TyParam(_) => true, _ => false, } { - return; + return } let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id); @@ -147,38 +150,63 @@ pub fn get_auto_trait_impls( param_env, trait_ref.to_predicate(), )); - if may_apply { - if traits.get(&trait_def_id).is_none() { - 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(impl_def_id) - .into_iter() - .map(|meth| meth.ident.to_string()) - .collect(); - traits.insert(trait_def_id, Item { - source: Span::empty(), - 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: (generics, - &tcx.predicates_of(impl_def_id)).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::>().clean(self.cx), - polarity: None, - synthetic: true, - }), - }); - } + 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(impl_def_id) + .into_iter() + .map(|meth| meth.ident.to_string()) + .collect(); + + 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), + }; + + let ty = hir::Ty { + id: ast::DUMMY_NODE_ID, + node: hir::Ty_::TyPath(hir::QPath::Resolved(None, P(new_path))), + span: DUMMY_SP, + hir_id: hir::DUMMY_HIR_ID, + }; + + traits.push(Item { + source: Span::empty(), + 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: (generics, + &tcx.predicates_of(impl_def_id)).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::>().clean(self.cx), + polarity: None, + synthetic: true, + }), + }); debug!("{:?} => {}", trait_ref, may_apply); } }); @@ -209,7 +237,7 @@ pub fn get_auto_trait_impls( def_ctor, tcx.require_lang_item(lang_items::SyncTraitLangItem), ).into_iter()) - .chain(traits.into_iter().map(|(_, v)| v)) + .chain(traits.into_iter()) .collect(); debug!( diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs new file mode 100644 index 00000000000..68277835d2b --- /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 or the MIT license +// , 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 'impl ToString for Bar' +pub struct Bar; + +// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl ToString for Foo' +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 @@ fn a_method(&self) -> usize { // @!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 @@ fn 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, } diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs index 8ff84d11a50..200747bf6cd 100644 --- a/src/test/rustdoc/synthetic_auto/basic.rs +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -12,7 +12,7 @@ // @has - '//code' 'impl Send for Foo where T: Send' // @has - '//code' 'impl Sync for Foo where T: Sync' // @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 2 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 11 pub struct Foo { field: T, } diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index ef6797ecf3c..461b922e28e 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -16,7 +16,7 @@ // 'impl Send for Foo' // // @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 10 pub struct Foo { field: T, }