auto merge of #21018 : tomjakubowski/rust/rustdoc-where-xcrate, r=alexcrichton

Various fixes for `rustdoc`, including showing where clauses
finally on re-exported items.
This commit is contained in:
bors 2015-01-14 00:41:55 +00:00
commit 170c4399e6
2 changed files with 187 additions and 113 deletions

View file

@ -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()
@ -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()
@ -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
}
}
};
@ -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
}
}
}
@ -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)
}],
}
}
@ -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();
@ -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() {
@ -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));
@ -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 {
@ -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 {
@ -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
}
}
}
@ -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,
@ -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>),
@ -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,
@ -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,
}
}

View file

@ -153,8 +153,8 @@ impl<'a> fmt::String for WhereClause<'a> {
try!(write!(f, "{}", lifetime));
}
}
&clean::WherePredicate::EqPredicate => {
unimplemented!()
&clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
try!(write!(f, "{} == {}", lhs, rhs));
}
}
}
@ -465,61 +465,6 @@ impl fmt::String for clean::Type {
}
clean::Infer => write!(f, "_"),
clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
clean::Closure(ref decl) => {
write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}",
style = UnsafetySpace(decl.unsafety),
lifetimes = if decl.lifetimes.len() == 0 {
"".to_string()
} else {
format!("for &lt;{}&gt;",
CommaSep(decl.lifetimes.as_slice()))
},
args = decl.decl.inputs,
arrow = decl.decl.output,
bounds = {
let mut ret = String::new();
for bound in decl.bounds.iter() {
match *bound {
clean::RegionBound(..) => {}
clean::TraitBound(ref t, modifier) => {
if ret.len() == 0 {
ret.push_str(": ");
} else {
ret.push_str(" + ");
}
if modifier == ast::TraitBoundModifier::Maybe {
ret.push_str("?");
}
ret.push_str(format!("{}",
*t).as_slice());
}
}
}
ret
})
}
clean::Proc(ref decl) => {
write!(f, "{style}{lifetimes}proc({args}){bounds}{arrow}",
style = UnsafetySpace(decl.unsafety),
lifetimes = if decl.lifetimes.len() == 0 {
"".to_string()
} else {
format!("for &lt;{}&gt;",
CommaSep(decl.lifetimes.as_slice()))
},
args = decl.decl.inputs,
bounds = if decl.bounds.len() == 0 {
"".to_string()
} else {
let m = decl.bounds
.iter()
.map(|s| s.to_string());
format!(
": {}",
m.collect::<Vec<String>>().connect(" + "))
},
arrow = decl.decl.output)
}
clean::BareFunction(ref decl) => {
write!(f, "{}{}fn{}{}",
UnsafetySpace(decl.unsafety),