diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2017-11-22 16:16:55 -0500 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2018-02-18 16:29:24 -0500 |
| commit | 6728f21d85d347bcd5e7ca919b4e9f0c2677572b (patch) | |
| tree | 69ccb4351afdb8b46c28191a809182f6cfbe06ce /src/librustdoc/clean/inline.rs | |
| parent | 27a046e9338fb0455c33b13e8fe28da78212dedc (diff) | |
| download | rust-6728f21d85d347bcd5e7ca919b4e9f0c2677572b.tar.gz rust-6728f21d85d347bcd5e7ca919b4e9f0c2677572b.zip | |
Generate documentation for auto-trait impls
A new section is added to both both struct and trait doc pages.
On struct/enum pages, a new 'Auto Trait Implementations' section displays any
synthetic implementations for auto traits. Currently, this is only done
for Send and Sync.
On trait pages, a new 'Auto Implementors' section displays all types
which automatically implement the trait. Effectively, this is a list of
all public types in the standard library.
Synthesized impls for a particular auto trait ('synthetic impls') take
into account generic bounds. For example, a type 'struct Foo<T>(T)' will
have 'impl<T> Send for Foo<T> where T: Send' generated for it.
Manual implementations of auto traits are also taken into account. If we have
the following types:
'struct Foo<T>(T)'
'struct Wrapper<T>(Foo<T>)'
'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes
this sound somehow
Then Wrapper will have the following impl generated:
'impl<T> Send for Wrapper<T>'
reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send'
to hold
Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are
taken into account by synthetic impls
However, if a type can *never* implement a particular auto trait
(e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be
generated (in this case, 'impl<T> !Send for MyStruct<T>')
All of this means that a user should be able to copy-paste a synthetic
impl into their code, without any observable changes in behavior
(assuming the rest of the program remains unchanged).
Diffstat (limited to 'src/librustdoc/clean/inline.rs')
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9aba399b3b0..f32dbcb8a08 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -12,8 +12,8 @@ use std::collections::BTreeMap; use std::io; -use std::iter::once; use std::rc::Rc; +use std::iter::once; use syntax::ast; use rustc::hir; @@ -25,7 +25,7 @@ use rustc::util::nodemap::FxHashSet; use core::{DocContext, DocAccessLevels}; use doctree; -use clean::{self, GetDefId}; +use clean::{self, GetDefId, get_auto_traits_with_def_id}; use super::Clean; @@ -50,7 +50,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) let inner = match def { Def::Trait(did) => { record_extern_fqn(cx, did, clean::TypeKind::Trait); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, false)); clean::TraitItem(build_external_trait(cx, did)) } Def::Fn(did) => { @@ -59,27 +59,27 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) } Def::Struct(did) => { record_extern_fqn(cx, did, clean::TypeKind::Struct); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, true)); clean::StructItem(build_struct(cx, did)) } Def::Union(did) => { record_extern_fqn(cx, did, clean::TypeKind::Union); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, true)); clean::UnionItem(build_union(cx, did)) } Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeKind::Typedef); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, true)); 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)); + ret.extend(build_impls(cx, did, true)); clean::EnumItem(build_enum(cx, did)) } Def::TyForeign(did) => { record_extern_fqn(cx, did, clean::TypeKind::Foreign); - ret.extend(build_impls(cx, did)); + ret.extend(build_impls(cx, did, false)); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -120,11 +120,17 @@ pub fn load_attrs(cx: &DocContext, did: DefId) -> clean::Attributes { cx.tcx.get_attrs(did).clean(cx) } + /// Record an external fully qualified name in the external_paths cache. /// /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { + if did.is_local() { + debug!("record_extern_fqn(did={:?}, kind+{:?}): def_id is local, aborting", did, kind); + return; + } + let crate_name = cx.tcx.crate_name(did.krate).to_string(); let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { // extern blocks have an empty name @@ -144,6 +150,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { } pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { + let auto_trait = cx.tcx.trait_def(did).has_auto_impl; let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); let predicates = cx.tcx.predicates_of(did); let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); @@ -152,6 +159,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { let is_spotlight = load_attrs(cx, did).has_doc_flag("spotlight"); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { + auto: auto_trait, unsafety: cx.tcx.trait_def(did).unsafety, generics, items: trait_items, @@ -227,7 +235,7 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { } } -pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> { +pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean::Item> { let tcx = cx.tcx; let mut impls = Vec::new(); @@ -235,6 +243,16 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> { build_impl(cx, did, &mut impls); } + 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(); + + impls.extend(new_impls); + } + // If this is the first time we've inlined something from another crate, then // we inline *all* impls from all the crates into this crate. Note that there's // currently no way for us to filter this based on type, and we likely need @@ -249,6 +267,7 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> { cx.populated_all_crate_impls.set(true); + for &cnum in tcx.crates().iter() { for did in tcx.all_trait_implementations(cnum).iter() { build_impl(cx, *did, &mut impls); @@ -347,13 +366,14 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) { ret.push(clean::Item { inner: clean::ImplItem(clean::Impl { - unsafety: hir::Unsafety::Normal, // FIXME: this should be decoded + unsafety: hir::Unsafety::Normal, + generics: (tcx.generics_of(did), &predicates).clean(cx), provided_trait_methods: provided, trait_, for_, - generics: (tcx.generics_of(did), &predicates).clean(cx), items: trait_items, polarity: Some(polarity.clean(cx)), + synthetic: false }), source: tcx.def_span(did).clean(cx), name: None, |
