Skip to content

Commit

Permalink
auto merge of #21018 : tomjakubowski/rust/rustdoc-where-xcrate, r=ale…
Browse files Browse the repository at this point in the history
…xcrichton

Various fixes for `rustdoc`, including showing where clauses
finally on re-exported items.
  • Loading branch information
bors committed Jan 14, 2015
2 parents c366e43 + 616db5a commit 170c439
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 113 deletions.
241 changes: 185 additions & 56 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
}
}

impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
fn clean(&self, cx: &DocContext) -> U {
self.0.clean(cx)
}
}

impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
fn clean(&self, cx: &DocContext) -> Vec<U> {
self.iter().map(|x| x.clean(cx)).collect()
Expand Down Expand Up @@ -498,22 +504,28 @@ impl Clean<TyParamBound> for ast::TyParamBound {
}
}

impl<'tcx> Clean<Vec<TyParamBound>> for ty::ExistentialBounds<'tcx> {
fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
let mut vec = vec![];
self.region_bound.clean(cx).map(|b| vec.push(RegionBound(b)));
impl<'tcx> Clean<(Vec<TyParamBound>, Vec<TypeBinding>)> for ty::ExistentialBounds<'tcx> {
fn clean(&self, cx: &DocContext) -> (Vec<TyParamBound>, Vec<TypeBinding>) {
let mut tp_bounds = vec![];
self.region_bound.clean(cx).map(|b| tp_bounds.push(RegionBound(b)));
for bb in self.builtin_bounds.iter() {
vec.push(bb.clean(cx));
tp_bounds.push(bb.clean(cx));
}

// FIXME(#20299) -- should do something with projection bounds
let mut bindings = vec![];
for &ty::Binder(ref pb) in self.projection_bounds.iter() {
bindings.push(TypeBinding {
name: pb.projection_ty.item_name.clean(cx),
ty: pb.ty.clean(cx)
});
}

vec
(tp_bounds, bindings)
}
}

fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
substs: &subst::Substs) -> PathParameters {
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
use rustc::middle::ty::sty;
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
.iter()
Expand All @@ -531,7 +543,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
return PathParameters::AngleBracketed {
lifetimes: lifetimes,
types: types.clean(cx),
bindings: vec![]
bindings: bindings
}
}
};
Expand All @@ -548,7 +560,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
PathParameters::AngleBracketed {
lifetimes: lifetimes,
types: types.clean(cx),
bindings: vec![] // FIXME(#20646)
bindings: bindings
}
}
}
Expand All @@ -557,12 +569,12 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
// from Fn<(A, B,), C> to Fn(A, B) -> C
fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
substs: &subst::Substs) -> Path {
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
Path {
global: false,
segments: vec![PathSegment {
name: name.to_string(),
params: external_path_params(cx, trait_did, substs)
params: external_path_params(cx, trait_did, bindings, substs)
}],
}
}
Expand All @@ -577,16 +589,16 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
let (did, path) = match *self {
ty::BoundSend =>
(tcx.lang_items.send_trait().unwrap(),
external_path(cx, "Send", None, &empty)),
external_path(cx, "Send", None, vec![], &empty)),
ty::BoundSized =>
(tcx.lang_items.sized_trait().unwrap(),
external_path(cx, "Sized", None, &empty)),
external_path(cx, "Sized", None, vec![], &empty)),
ty::BoundCopy =>
(tcx.lang_items.copy_trait().unwrap(),
external_path(cx, "Copy", None, &empty)),
external_path(cx, "Copy", None, vec![], &empty)),
ty::BoundSync =>
(tcx.lang_items.sync_trait().unwrap(),
external_path(cx, "Sync", None, &empty)),
external_path(cx, "Sync", None, vec![], &empty)),
};
let fqn = csearch::get_item_path(tcx, did);
let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
Expand All @@ -603,12 +615,6 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
}
}

impl<'tcx> Clean<TyParamBound> for ty::PolyTraitRef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParamBound {
self.0.clean(cx)
}
}

impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParamBound {
let tcx = match cx.tcx_opt() {
Expand All @@ -619,7 +625,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
let fqn = fqn.into_iter().map(|i| i.to_string())
.collect::<Vec<String>>();
let path = external_path(cx, fqn.last().unwrap().as_slice(),
Some(self.def_id), self.substs);
Some(self.def_id), vec![], self.substs);
cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
(fqn, TypeTrait));

Expand Down Expand Up @@ -730,8 +736,7 @@ impl Clean<Option<Lifetime>> for ty::Region {
pub enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
// FIXME (#20041)
EqPredicate
EqPredicate { lhs: Type, rhs: Type }
}

impl Clean<WherePredicate> for ast::WherePredicate {
Expand All @@ -752,12 +757,89 @@ impl Clean<WherePredicate> for ast::WherePredicate {
}

ast::WherePredicate::EqPredicate(_) => {
WherePredicate::EqPredicate
unimplemented!() // FIXME(#20041)
}
}
}
}

impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
use rustc::middle::ty::Predicate;

match *self {
Predicate::Trait(ref pred) => pred.clean(cx),
Predicate::Equate(ref pred) => pred.clean(cx),
Predicate::RegionOutlives(ref pred) => pred.clean(cx),
Predicate::TypeOutlives(ref pred) => pred.clean(cx),
Predicate::Projection(ref pred) => pred.clean(cx)
}
}
}

impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
WherePredicate::BoundPredicate {
ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
bounds: vec![self.trait_ref.clean(cx)]
}
}
}

impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::EquatePredicate(ref lhs, ref rhs) = *self;
WherePredicate::EqPredicate {
lhs: lhs.clean(cx),
rhs: rhs.clean(cx)
}
}
}

impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref a, ref b) = *self;
WherePredicate::RegionPredicate {
lifetime: a.clean(cx).unwrap(),
bounds: vec![b.clean(cx).unwrap()]
}
}
}

impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref ty, ref lt) = *self;

WherePredicate::BoundPredicate {
ty: ty.clean(cx),
bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
}
}
}

impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
WherePredicate::EqPredicate {
lhs: self.projection_ty.clean(cx),
rhs: self.ty.clean(cx)
}
}
}

impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
fn clean(&self, cx: &DocContext) -> Type {
let trait_ = match self.trait_ref.clean(cx) {
TyParamBound::TraitBound(t, _) => t.trait_,
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
};
Type::QPath {
name: self.item_name.clean(cx),
self_type: box self.trait_ref.self_ty().clean(cx),
trait_: box trait_
}
}
}

// maybe use a Generic enum and use ~[Generic]?
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub struct Generics {
Expand All @@ -778,11 +860,80 @@ impl Clean<Generics> for ast::Generics {

impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
fn clean(&self, cx: &DocContext) -> Generics {
let (me, space) = *self;
use std::collections::HashSet;
use syntax::ast::TraitBoundModifier as TBM;
use self::WherePredicate as WP;

fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool {
if let Some(tcx) = cx.tcx_opt() {
let sized_did = match tcx.lang_items.sized_trait() {
Some(did) => did,
None => return false
};
for bound in bounds.iter() {
if let TyParamBound::TraitBound(PolyTrait {
trait_: Type::ResolvedPath { did, .. }, ..
}, TBM::None) = *bound {
if did == sized_did {
return true
}
}
}
}
false
}

let (gens, space) = *self;
// Bounds in the type_params and lifetimes fields are repeated in the predicates
// field (see rustc_typeck::collect::ty_generics), so remove them.
let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
let mut stp = tp.clone();
stp.bounds = ty::ParamBounds::empty();
stp.clean(cx)
}).collect::<Vec<_>>();
let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
let mut srp = rp.clone();
srp.bounds = Vec::new();
srp.clean(cx)
}).collect::<Vec<_>>();

let where_predicates = gens.predicates.get_slice(space).to_vec().clean(cx);
// Type parameters have a Sized bound by default unless removed with ?Sized.
// Scan through the predicates and mark any type parameter with a Sized
// bound, removing the bounds as we find them.
let mut sized_params = HashSet::new();
let mut where_predicates = where_predicates.into_iter().filter_map(|pred| {
if let WP::BoundPredicate { ty: Type::Generic(ref g), ref bounds } = pred {
if has_sized_bound(&**bounds, cx) {
sized_params.insert(g.clone());
return None
}
}
Some(pred)
}).collect::<Vec<_>>();
// Finally, run through the type parameters again and insert a ?Sized unbound for
// any we didn't find to be Sized.
for tp in stripped_typarams.iter() {
if !sized_params.contains(&tp.name) {
let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
*tbm = TBM::Maybe
};
where_predicates.push(WP::BoundPredicate {
ty: Type::Generic(tp.name.clone()),
bounds: vec![sized_bound]
})
}
}

// It would be nice to collect all of the bounds on a type and recombine
// them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
// and instead see `where T: Foo + Bar + Sized + 'a`

Generics {
type_params: me.types.get_slice(space).to_vec().clean(cx),
lifetimes: me.regions.get_slice(space).to_vec().clean(cx),
where_predicates: vec![]
type_params: stripped_typarams,
lifetimes: stripped_lifetimes,
where_predicates: where_predicates
}
}
}
Expand Down Expand Up @@ -910,27 +1061,6 @@ impl Clean<Item> for doctree::Function {
}
}

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub struct ClosureDecl {
pub lifetimes: Vec<Lifetime>,
pub decl: FnDecl,
pub onceness: ast::Onceness,
pub unsafety: ast::Unsafety,
pub bounds: Vec<TyParamBound>,
}

impl Clean<ClosureDecl> for ast::ClosureTy {
fn clean(&self, cx: &DocContext) -> ClosureDecl {
ClosureDecl {
lifetimes: self.lifetimes.clean(cx),
decl: self.decl.clean(cx),
onceness: self.onceness,
unsafety: self.unsafety,
bounds: self.bounds.clean(cx)
}
}
}

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub struct FnDecl {
pub inputs: Arguments,
Expand Down Expand Up @@ -1207,8 +1337,6 @@ pub enum Type {
Generic(String),
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
Primitive(PrimitiveType),
Closure(Box<ClosureDecl>),
Proc(Box<ClosureDecl>),
/// extern "ABI" fn
BareFunction(Box<BareFunctionDecl>),
Tuple(Vec<Type>),
Expand Down Expand Up @@ -1436,7 +1564,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
_ => TypeEnum,
};
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
None, substs);
None, vec![], substs);
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
ResolvedPath {
path: path,
Expand All @@ -1448,12 +1576,13 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
let did = principal.def_id();
let fqn = csearch::get_item_path(cx.tcx(), did);
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
let (typarams, bindings) = bounds.clean(cx);
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
Some(did), principal.substs());
Some(did), bindings, principal.substs());
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
ResolvedPath {
path: path,
typarams: Some(bounds.clean(cx)),
typarams: Some(typarams),
did: did,
}
}
Expand Down
Loading

0 comments on commit 170c439

Please sign in to comment.