Skip to content

rustdoc: Fixes for everyone! #21018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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