Skip to content

Commit 170c439

Browse files
committed
auto merge of #21018 : tomjakubowski/rust/rustdoc-where-xcrate, r=alexcrichton
Various fixes for `rustdoc`, including showing where clauses finally on re-exported items.
2 parents c366e43 + 616db5a commit 170c439

File tree

2 files changed

+187
-113
lines changed

2 files changed

+187
-113
lines changed

src/librustdoc/clean/mod.rs

+185-56
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
104104
}
105105
}
106106

107+
impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
108+
fn clean(&self, cx: &DocContext) -> U {
109+
self.0.clean(cx)
110+
}
111+
}
112+
107113
impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
108114
fn clean(&self, cx: &DocContext) -> Vec<U> {
109115
self.iter().map(|x| x.clean(cx)).collect()
@@ -498,22 +504,28 @@ impl Clean<TyParamBound> for ast::TyParamBound {
498504
}
499505
}
500506

501-
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ExistentialBounds<'tcx> {
502-
fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
503-
let mut vec = vec![];
504-
self.region_bound.clean(cx).map(|b| vec.push(RegionBound(b)));
507+
impl<'tcx> Clean<(Vec<TyParamBound>, Vec<TypeBinding>)> for ty::ExistentialBounds<'tcx> {
508+
fn clean(&self, cx: &DocContext) -> (Vec<TyParamBound>, Vec<TypeBinding>) {
509+
let mut tp_bounds = vec![];
510+
self.region_bound.clean(cx).map(|b| tp_bounds.push(RegionBound(b)));
505511
for bb in self.builtin_bounds.iter() {
506-
vec.push(bb.clean(cx));
512+
tp_bounds.push(bb.clean(cx));
507513
}
508514

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

511-
vec
523+
(tp_bounds, bindings)
512524
}
513525
}
514526

515527
fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
516-
substs: &subst::Substs) -> PathParameters {
528+
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
517529
use rustc::middle::ty::sty;
518530
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
519531
.iter()
@@ -531,7 +543,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
531543
return PathParameters::AngleBracketed {
532544
lifetimes: lifetimes,
533545
types: types.clean(cx),
534-
bindings: vec![]
546+
bindings: bindings
535547
}
536548
}
537549
};
@@ -548,7 +560,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
548560
PathParameters::AngleBracketed {
549561
lifetimes: lifetimes,
550562
types: types.clean(cx),
551-
bindings: vec![] // FIXME(#20646)
563+
bindings: bindings
552564
}
553565
}
554566
}
@@ -557,12 +569,12 @@ fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
557569
// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
558570
// from Fn<(A, B,), C> to Fn(A, B) -> C
559571
fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
560-
substs: &subst::Substs) -> Path {
572+
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
561573
Path {
562574
global: false,
563575
segments: vec![PathSegment {
564576
name: name.to_string(),
565-
params: external_path_params(cx, trait_did, substs)
577+
params: external_path_params(cx, trait_did, bindings, substs)
566578
}],
567579
}
568580
}
@@ -577,16 +589,16 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
577589
let (did, path) = match *self {
578590
ty::BoundSend =>
579591
(tcx.lang_items.send_trait().unwrap(),
580-
external_path(cx, "Send", None, &empty)),
592+
external_path(cx, "Send", None, vec![], &empty)),
581593
ty::BoundSized =>
582594
(tcx.lang_items.sized_trait().unwrap(),
583-
external_path(cx, "Sized", None, &empty)),
595+
external_path(cx, "Sized", None, vec![], &empty)),
584596
ty::BoundCopy =>
585597
(tcx.lang_items.copy_trait().unwrap(),
586-
external_path(cx, "Copy", None, &empty)),
598+
external_path(cx, "Copy", None, vec![], &empty)),
587599
ty::BoundSync =>
588600
(tcx.lang_items.sync_trait().unwrap(),
589-
external_path(cx, "Sync", None, &empty)),
601+
external_path(cx, "Sync", None, vec![], &empty)),
590602
};
591603
let fqn = csearch::get_item_path(tcx, did);
592604
let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
@@ -603,12 +615,6 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
603615
}
604616
}
605617

606-
impl<'tcx> Clean<TyParamBound> for ty::PolyTraitRef<'tcx> {
607-
fn clean(&self, cx: &DocContext) -> TyParamBound {
608-
self.0.clean(cx)
609-
}
610-
}
611-
612618
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
613619
fn clean(&self, cx: &DocContext) -> TyParamBound {
614620
let tcx = match cx.tcx_opt() {
@@ -619,7 +625,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
619625
let fqn = fqn.into_iter().map(|i| i.to_string())
620626
.collect::<Vec<String>>();
621627
let path = external_path(cx, fqn.last().unwrap().as_slice(),
622-
Some(self.def_id), self.substs);
628+
Some(self.def_id), vec![], self.substs);
623629
cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
624630
(fqn, TypeTrait));
625631

@@ -730,8 +736,7 @@ impl Clean<Option<Lifetime>> for ty::Region {
730736
pub enum WherePredicate {
731737
BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
732738
RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
733-
// FIXME (#20041)
734-
EqPredicate
739+
EqPredicate { lhs: Type, rhs: Type }
735740
}
736741

737742
impl Clean<WherePredicate> for ast::WherePredicate {
@@ -752,12 +757,89 @@ impl Clean<WherePredicate> for ast::WherePredicate {
752757
}
753758

754759
ast::WherePredicate::EqPredicate(_) => {
755-
WherePredicate::EqPredicate
760+
unimplemented!() // FIXME(#20041)
756761
}
757762
}
758763
}
759764
}
760765

766+
impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
767+
fn clean(&self, cx: &DocContext) -> WherePredicate {
768+
use rustc::middle::ty::Predicate;
769+
770+
match *self {
771+
Predicate::Trait(ref pred) => pred.clean(cx),
772+
Predicate::Equate(ref pred) => pred.clean(cx),
773+
Predicate::RegionOutlives(ref pred) => pred.clean(cx),
774+
Predicate::TypeOutlives(ref pred) => pred.clean(cx),
775+
Predicate::Projection(ref pred) => pred.clean(cx)
776+
}
777+
}
778+
}
779+
780+
impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
781+
fn clean(&self, cx: &DocContext) -> WherePredicate {
782+
WherePredicate::BoundPredicate {
783+
ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
784+
bounds: vec![self.trait_ref.clean(cx)]
785+
}
786+
}
787+
}
788+
789+
impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
790+
fn clean(&self, cx: &DocContext) -> WherePredicate {
791+
let ty::EquatePredicate(ref lhs, ref rhs) = *self;
792+
WherePredicate::EqPredicate {
793+
lhs: lhs.clean(cx),
794+
rhs: rhs.clean(cx)
795+
}
796+
}
797+
}
798+
799+
impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
800+
fn clean(&self, cx: &DocContext) -> WherePredicate {
801+
let ty::OutlivesPredicate(ref a, ref b) = *self;
802+
WherePredicate::RegionPredicate {
803+
lifetime: a.clean(cx).unwrap(),
804+
bounds: vec![b.clean(cx).unwrap()]
805+
}
806+
}
807+
}
808+
809+
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
810+
fn clean(&self, cx: &DocContext) -> WherePredicate {
811+
let ty::OutlivesPredicate(ref ty, ref lt) = *self;
812+
813+
WherePredicate::BoundPredicate {
814+
ty: ty.clean(cx),
815+
bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
816+
}
817+
}
818+
}
819+
820+
impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
821+
fn clean(&self, cx: &DocContext) -> WherePredicate {
822+
WherePredicate::EqPredicate {
823+
lhs: self.projection_ty.clean(cx),
824+
rhs: self.ty.clean(cx)
825+
}
826+
}
827+
}
828+
829+
impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
830+
fn clean(&self, cx: &DocContext) -> Type {
831+
let trait_ = match self.trait_ref.clean(cx) {
832+
TyParamBound::TraitBound(t, _) => t.trait_,
833+
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
834+
};
835+
Type::QPath {
836+
name: self.item_name.clean(cx),
837+
self_type: box self.trait_ref.self_ty().clean(cx),
838+
trait_: box trait_
839+
}
840+
}
841+
}
842+
761843
// maybe use a Generic enum and use ~[Generic]?
762844
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
763845
pub struct Generics {
@@ -778,11 +860,80 @@ impl Clean<Generics> for ast::Generics {
778860

779861
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
780862
fn clean(&self, cx: &DocContext) -> Generics {
781-
let (me, space) = *self;
863+
use std::collections::HashSet;
864+
use syntax::ast::TraitBoundModifier as TBM;
865+
use self::WherePredicate as WP;
866+
867+
fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool {
868+
if let Some(tcx) = cx.tcx_opt() {
869+
let sized_did = match tcx.lang_items.sized_trait() {
870+
Some(did) => did,
871+
None => return false
872+
};
873+
for bound in bounds.iter() {
874+
if let TyParamBound::TraitBound(PolyTrait {
875+
trait_: Type::ResolvedPath { did, .. }, ..
876+
}, TBM::None) = *bound {
877+
if did == sized_did {
878+
return true
879+
}
880+
}
881+
}
882+
}
883+
false
884+
}
885+
886+
let (gens, space) = *self;
887+
// Bounds in the type_params and lifetimes fields are repeated in the predicates
888+
// field (see rustc_typeck::collect::ty_generics), so remove them.
889+
let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
890+
let mut stp = tp.clone();
891+
stp.bounds = ty::ParamBounds::empty();
892+
stp.clean(cx)
893+
}).collect::<Vec<_>>();
894+
let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
895+
let mut srp = rp.clone();
896+
srp.bounds = Vec::new();
897+
srp.clean(cx)
898+
}).collect::<Vec<_>>();
899+
900+
let where_predicates = gens.predicates.get_slice(space).to_vec().clean(cx);
901+
// Type parameters have a Sized bound by default unless removed with ?Sized.
902+
// Scan through the predicates and mark any type parameter with a Sized
903+
// bound, removing the bounds as we find them.
904+
let mut sized_params = HashSet::new();
905+
let mut where_predicates = where_predicates.into_iter().filter_map(|pred| {
906+
if let WP::BoundPredicate { ty: Type::Generic(ref g), ref bounds } = pred {
907+
if has_sized_bound(&**bounds, cx) {
908+
sized_params.insert(g.clone());
909+
return None
910+
}
911+
}
912+
Some(pred)
913+
}).collect::<Vec<_>>();
914+
// Finally, run through the type parameters again and insert a ?Sized unbound for
915+
// any we didn't find to be Sized.
916+
for tp in stripped_typarams.iter() {
917+
if !sized_params.contains(&tp.name) {
918+
let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
919+
if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
920+
*tbm = TBM::Maybe
921+
};
922+
where_predicates.push(WP::BoundPredicate {
923+
ty: Type::Generic(tp.name.clone()),
924+
bounds: vec![sized_bound]
925+
})
926+
}
927+
}
928+
929+
// It would be nice to collect all of the bounds on a type and recombine
930+
// them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
931+
// and instead see `where T: Foo + Bar + Sized + 'a`
932+
782933
Generics {
783-
type_params: me.types.get_slice(space).to_vec().clean(cx),
784-
lifetimes: me.regions.get_slice(space).to_vec().clean(cx),
785-
where_predicates: vec![]
934+
type_params: stripped_typarams,
935+
lifetimes: stripped_lifetimes,
936+
where_predicates: where_predicates
786937
}
787938
}
788939
}
@@ -910,27 +1061,6 @@ impl Clean<Item> for doctree::Function {
9101061
}
9111062
}
9121063

913-
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
914-
pub struct ClosureDecl {
915-
pub lifetimes: Vec<Lifetime>,
916-
pub decl: FnDecl,
917-
pub onceness: ast::Onceness,
918-
pub unsafety: ast::Unsafety,
919-
pub bounds: Vec<TyParamBound>,
920-
}
921-
922-
impl Clean<ClosureDecl> for ast::ClosureTy {
923-
fn clean(&self, cx: &DocContext) -> ClosureDecl {
924-
ClosureDecl {
925-
lifetimes: self.lifetimes.clean(cx),
926-
decl: self.decl.clean(cx),
927-
onceness: self.onceness,
928-
unsafety: self.unsafety,
929-
bounds: self.bounds.clean(cx)
930-
}
931-
}
932-
}
933-
9341064
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
9351065
pub struct FnDecl {
9361066
pub inputs: Arguments,
@@ -1207,8 +1337,6 @@ pub enum Type {
12071337
Generic(String),
12081338
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
12091339
Primitive(PrimitiveType),
1210-
Closure(Box<ClosureDecl>),
1211-
Proc(Box<ClosureDecl>),
12121340
/// extern "ABI" fn
12131341
BareFunction(Box<BareFunctionDecl>),
12141342
Tuple(Vec<Type>),
@@ -1436,7 +1564,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
14361564
_ => TypeEnum,
14371565
};
14381566
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
1439-
None, substs);
1567+
None, vec![], substs);
14401568
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
14411569
ResolvedPath {
14421570
path: path,
@@ -1448,12 +1576,13 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
14481576
let did = principal.def_id();
14491577
let fqn = csearch::get_item_path(cx.tcx(), did);
14501578
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
1579+
let (typarams, bindings) = bounds.clean(cx);
14511580
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
1452-
Some(did), principal.substs());
1581+
Some(did), bindings, principal.substs());
14531582
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
14541583
ResolvedPath {
14551584
path: path,
1456-
typarams: Some(bounds.clean(cx)),
1585+
typarams: Some(typarams),
14571586
did: did,
14581587
}
14591588
}

0 commit comments

Comments
 (0)