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:
commit
170c4399e6
2 changed files with 187 additions and 113 deletions
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <{}>",
|
||||
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 <{}>",
|
||||
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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue