diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6ef0a3f3da550..73837db7c3f74 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -29,8 +29,6 @@ use clean::{ self, GetDefId, ToSource, - get_auto_traits_with_def_id, - get_blanket_impls_with_def_id, }; use super::Clean; @@ -56,7 +54,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa let inner = match def { Def::Trait(did) => { record_extern_fqn(cx, did, clean::TypeKind::Trait); - ret.extend(build_impls(cx, did, false)); + ret.extend(build_impls(cx, did)); clean::TraitItem(build_external_trait(cx, did)) } Def::Fn(did) => { @@ -65,27 +63,27 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa } Def::Struct(did) => { record_extern_fqn(cx, did, clean::TypeKind::Struct); - ret.extend(build_impls(cx, did, true)); + ret.extend(build_impls(cx, did)); clean::StructItem(build_struct(cx, did)) } Def::Union(did) => { record_extern_fqn(cx, did, clean::TypeKind::Union); - ret.extend(build_impls(cx, did, true)); + ret.extend(build_impls(cx, did)); clean::UnionItem(build_union(cx, did)) } Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeKind::Typedef); - ret.extend(build_impls(cx, did, false)); + ret.extend(build_impls(cx, did)); clean::TypedefItem(build_type_alias(cx, did), false) } Def::Enum(did) => { record_extern_fqn(cx, did, clean::TypeKind::Enum); - ret.extend(build_impls(cx, did, true)); + ret.extend(build_impls(cx, did)); clean::EnumItem(build_enum(cx, did)) } Def::ForeignTy(did) => { record_extern_fqn(cx, did, clean::TypeKind::Foreign); - ret.extend(build_impls(cx, did, false)); + ret.extend(build_impls(cx, did)); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -275,7 +273,7 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { } } -pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec { +pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); @@ -283,18 +281,6 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec = auto_impls.into_iter() - .filter(|i| renderinfo.inlined.insert(i.def_id)).collect(); - - impls.extend(new_impls); - } - impls.extend(get_blanket_impls_with_def_id(cx, did)); - } - impls } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 238a2bd3ba571..7c66912694104 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -576,9 +576,9 @@ impl Clean for doctree::Module { let mut items: Vec = vec![]; items.extend(self.extern_crates.iter().map(|x| x.clean(cx))); items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); - items.extend(self.structs.iter().flat_map(|x| x.clean(cx))); - items.extend(self.unions.iter().flat_map(|x| x.clean(cx))); - items.extend(self.enums.iter().flat_map(|x| x.clean(cx))); + items.extend(self.structs.iter().map(|x| x.clean(cx))); + items.extend(self.unions.iter().map(|x| x.clean(cx))); + items.extend(self.enums.iter().map(|x| x.clean(cx))); items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); @@ -2813,14 +2813,10 @@ pub struct Union { pub fields_stripped: bool, } -impl Clean> for doctree::Struct { - fn clean(&self, cx: &DocContext) -> Vec { - let name = self.name.clean(cx); - let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); - ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone())); - - ret.push(Item { - name: Some(name), +impl Clean for doctree::Struct { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2833,20 +2829,14 @@ impl Clean> for doctree::Struct { fields: self.fields.clean(cx), fields_stripped: false, }), - }); - - ret + } } } -impl Clean> for doctree::Union { - fn clean(&self, cx: &DocContext) -> Vec { - let name = self.name.clean(cx); - let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); - ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone())); - - ret.push(Item { - name: Some(name), +impl Clean for doctree::Union { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2859,9 +2849,7 @@ impl Clean> for doctree::Union { fields: self.fields.clean(cx), fields_stripped: false, }), - }); - - ret + } } } @@ -2892,14 +2880,10 @@ pub struct Enum { pub variants_stripped: bool, } -impl Clean> for doctree::Enum { - fn clean(&self, cx: &DocContext) -> Vec { - let name = self.name.clean(cx); - let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); - ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone())); - - ret.push(Item { - name: Some(name), +impl Clean for doctree::Enum { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), @@ -2911,9 +2895,7 @@ impl Clean> for doctree::Enum { generics: self.generics.clean(cx), variants_stripped: false, }), - }); - - ret + } } } @@ -3442,11 +3424,7 @@ fn build_deref_target_impls(cx: &DocContext, let primitive = match *target { ResolvedPath { did, .. } if did.is_local() => continue, ResolvedPath { did, .. } => { - // We set the last parameter to false to avoid looking for auto-impls for traits - // and therefore avoid an ICE. - // The reason behind this is that auto-traits don't propagate through Deref so - // we're not supposed to synthesise impls for them. - ret.extend(inline::build_impls(cx, did, false)); + ret.extend(inline::build_impls(cx, did)); continue } _ => match target.primitive_type() { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 0ee1657f21516..56940483d7be2 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -12,14 +12,20 @@ use clean::*; use super::Pass; use core::DocContext; +use fold::DocFolder; pub const COLLECT_TRAIT_IMPLS: Pass = Pass::early("collect-trait-impls", collect_trait_impls, "retrieves trait impls for items in the crate"); -pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate { +pub fn collect_trait_impls(krate: Crate, cx: &DocContext) -> Crate { + let mut synth = SyntheticImplCollector::new(cx); + let mut krate = synth.fold_crate(krate); + if let Some(ref mut it) = krate.module { if let ModuleItem(Module { ref mut items, .. }) = it.inner { + items.extend(synth.impls); + for &cnum in cx.tcx.crates().iter() { for &did in cx.tcx.all_trait_implementations(cnum).iter() { inline::build_impl(cx, did, items); @@ -90,3 +96,35 @@ pub fn collect_trait_impls(mut krate: Crate, cx: &DocContext) -> Crate { krate } + +struct SyntheticImplCollector<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { + cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>, + impls: Vec, +} + +impl<'a, 'tcx, 'rcx, 'cstore> SyntheticImplCollector<'a, 'tcx, 'rcx, 'cstore> { + fn new(cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self { + SyntheticImplCollector { + cx, + impls: Vec::new(), + } + } +} + +impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rcx, 'cstore> { + fn fold_item(&mut self, i: Item) -> Option { + if i.is_struct() || i.is_enum() || i.is_union() { + if let (Some(node_id), Some(name)) = + (self.cx.tcx.hir.as_local_node_id(i.def_id), i.name.clone()) + { + self.impls.extend(get_auto_traits_with_node_id(self.cx, node_id, name.clone())); + self.impls.extend(get_blanket_impls_with_node_id(self.cx, node_id, name)); + } else { + self.impls.extend(get_auto_traits_with_def_id(self.cx, i.def_id)); + self.impls.extend(get_blanket_impls_with_def_id(self.cx, i.def_id)); + } + } + + self.fold_item_recur(i) + } +}