rustdoc: generate implementors for all auto traits

Previously we would only generate a list of synthetic implementations
for two well known traits – Send and Sync. With this patch all the auto
traits known to rustc are considered. This includes such traits like
Unpin and user’s own traits.

Sadly the implementation still iterates through the list of crate items
and checks them against the traits, which for non-std crates containing
their own auto-traits will still not include types defined in std/core.

It is an improvement nontheless.
This commit is contained in:
Simonas Kazlauskas 2019-04-26 01:16:57 +03:00
parent 4fb77a0398
commit 4c8d00a3ec
8 changed files with 24 additions and 83 deletions

View File

@ -27,9 +27,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
let param_env = self.cx.tcx.param_env(param_env_def_id);
debug!("get_auto_trait_impls({:?})", ty);
let auto_traits = self.cx.send_trait.into_iter().chain(
Some(self.cx.tcx.require_lang_item(lang_items::SyncTraitLangItem))
);
let auto_traits = self.cx.auto_traits.iter().cloned();
auto_traits.filter_map(|trait_def_id| {
let trait_ref = ty::TraitRef {
def_id: trait_def_id,

View File

@ -17,8 +17,8 @@ use rustc::middle::resolve_lifetime as rl;
use rustc::middle::lang_items;
use rustc::middle::stability;
use rustc::mir::interpret::{GlobalId, ConstValue};
use rustc::hir::{self, HirVec};
use rustc::hir::def::{self, Res, DefKind, CtorKind};
use rustc::hir;
use rustc::hir::def::{CtorKind, DefKind, Res};
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::ty::subst::{InternalSubsts, SubstsRef, UnpackedKind};
use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
@ -4418,72 +4418,6 @@ where
r
}
// Start of code copied from rust-clippy
pub fn path_to_def_local(tcx: TyCtxt<'_>, path: &[Symbol]) -> Option<DefId> {
let krate = tcx.hir().krate();
let mut items = krate.module.item_ids.clone();
let mut path_it = path.iter().peekable();
loop {
let segment = path_it.next()?;
for item_id in mem::replace(&mut items, HirVec::new()).iter() {
let item = tcx.hir().expect_item(item_id.id);
if item.ident.name == *segment {
if path_it.peek().is_none() {
return Some(tcx.hir().local_def_id_from_hir_id(item_id.id))
}
items = match &item.node {
&hir::ItemKind::Mod(ref m) => m.item_ids.clone(),
_ => panic!("Unexpected item {:?} in path {:?} path")
};
break;
}
}
}
}
pub fn path_to_def(tcx: TyCtxt<'_>, path: &[Symbol]) -> Option<DefId> {
let crates = tcx.crates();
let krate = crates
.iter()
.find(|&&krate| tcx.crate_name(krate) == path[0]);
if let Some(krate) = krate {
let krate = DefId {
krate: *krate,
index: CRATE_DEF_INDEX,
};
let mut items = tcx.item_children(krate);
let mut path_it = path.iter().skip(1).peekable();
loop {
let segment = path_it.next()?;
for item in mem::replace(&mut items, &[]).iter() {
if item.ident.name == *segment {
if path_it.peek().is_none() {
return match item.res {
def::Res::Def(DefKind::Trait, did) => Some(did),
_ => None,
}
}
items = tcx.item_children(item.res.def_id());
break;
}
}
}
} else {
None
}
}
// End of code copied from rust-clippy
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
enum RegionTarget<'tcx> {
Region(Region<'tcx>),

View File

@ -67,13 +67,13 @@ pub struct DocContext<'tcx> {
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>>>,
pub send_trait: Option<DefId>,
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)`.
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
pub generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
pub all_traits: Vec<DefId>,
pub auto_traits: Vec<DefId>,
}
impl<'tcx> DocContext<'tcx> {
@ -367,15 +367,10 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
.collect()
};
let send_trait = if crate_name == Some("core".to_string()) {
clean::path_to_def_local(tcx, &[sym::marker, sym::Send])
} else {
clean::path_to_def(tcx, &[sym::core, sym::marker, sym::Send])
};
let mut renderinfo = RenderInfo::default();
renderinfo.access_levels = access_levels;
let all_traits = tcx.all_traits(LOCAL_CRATE).to_vec();
let ctxt = DocContext {
tcx,
resolver,
@ -388,11 +383,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
lt_substs: Default::default(),
ct_substs: Default::default(),
impl_trait_bounds: Default::default(),
send_trait: send_trait,
fake_def_ids: Default::default(),
all_fake_def_ids: Default::default(),
generated_synthetics: Default::default(),
all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
auto_traits: all_traits.iter().cloned().filter(|trait_def_id| {
tcx.trait_is_auto(*trait_def_id)
}).collect(),
all_traits,
};
debug!("crate: {:?}", tcx.hir().krate());

View File

@ -8,3 +8,6 @@ pub struct Foo;
// @!has - 'Auto Trait Implementations'
impl !Send for Foo {}
impl !Sync for Foo {}
impl !std::marker::Unpin for Foo {}
impl !std::panic::RefUnwindSafe for Foo {}
impl !std::panic::UnwindSafe for Foo {}

View File

@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
// @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
// @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0
// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 2
// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 5
pub struct Switch<B: Signal> {
pub inner: <B as Signal2>::Item2,
}

View File

@ -2,7 +2,7 @@
// @has - '//code' 'impl<T> Send for Foo<T> where T: Send'
// @has - '//code' 'impl<T> Sync for Foo<T> 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"]' 5
pub struct Foo<T> {
field: T,
}

View File

@ -0,0 +1,9 @@
#![feature(optin_builtin_traits)]
pub auto trait Banana {}
// @has crate_local/struct.Peach.html
// @has - '//code' 'impl Banana for Peach'
// @has - '//code' 'impl Send for Peach'
// @has - '//code' 'impl Sync for Peach'
pub struct Peach;

View File

@ -6,7 +6,7 @@
// 'impl<T> Send for Foo<T>'
//
// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1
// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 1
// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 4
pub struct Foo<T> {
field: T,
}