Skip to content

Commit

Permalink
Auto merge of #52585 - GuillaumeGomez:generic-impls, r=QuietMisdreavus
Browse files Browse the repository at this point in the history
[rustdoc] Generic impls

Fixes #33772.

r? @QuietMisdreavus
  • Loading branch information
bors committed Jul 28, 2018
2 parents 4234adf + 06364bd commit dab7151
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 69 deletions.
171 changes: 145 additions & 26 deletions src/librustdoc/clean/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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!(
Expand Down Expand Up @@ -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(),
Expand All @@ -239,6 +357,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
items: Vec::new(),
polarity,
synthetic: true,
blanket_impl: None,
}),
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -3947,6 +3947,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
items,
polarity: Some(self.polarity.clean(cx)),
synthetic: false,
blanket_impl: None,
})
});
ret
Expand Down
4 changes: 3 additions & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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());

Expand Down
6 changes: 5 additions & 1 deletion src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
Expand Down
Loading

0 comments on commit dab7151

Please sign in to comment.