Skip to content

Commit 8a69d35

Browse files
committed
rustdoc: Fix where clauses on re-exports
Projection predicates on re-exports, for the time being, are rendered as equality predicates because that's easier. It would be nice to fix this in the future. Some gymnastics were needed to remove redundant bounds from the `types` and `lifetimes` fields, remove implicit `Sized` bounds, and re-create `?Sized` bounds. Fix #20203, fix #20924, fix #20911, fix #20534
1 parent 099b411 commit 8a69d35

File tree

2 files changed

+160
-15
lines changed

2 files changed

+160
-15
lines changed

src/librustdoc/clean/mod.rs

Lines changed: 158 additions & 13 deletions
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()
@@ -603,12 +609,6 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
603609
}
604610
}
605611

606-
impl<'tcx> Clean<TyParamBound> for ty::PolyTraitRef<'tcx> {
607-
fn clean(&self, cx: &DocContext) -> TyParamBound {
608-
self.0.clean(cx)
609-
}
610-
}
611-
612612
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
613613
fn clean(&self, cx: &DocContext) -> TyParamBound {
614614
let tcx = match cx.tcx_opt() {
@@ -730,8 +730,7 @@ impl Clean<Option<Lifetime>> for ty::Region {
730730
pub enum WherePredicate {
731731
BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
732732
RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
733-
// FIXME (#20041)
734-
EqPredicate
733+
EqPredicate { lhs: Type, rhs: Type }
735734
}
736735

737736
impl Clean<WherePredicate> for ast::WherePredicate {
@@ -752,12 +751,89 @@ impl Clean<WherePredicate> for ast::WherePredicate {
752751
}
753752

754753
ast::WherePredicate::EqPredicate(_) => {
755-
WherePredicate::EqPredicate
754+
unimplemented!() // FIXME(#20041)
756755
}
757756
}
758757
}
759758
}
760759

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

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

src/librustdoc/html/format.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ impl<'a> fmt::String for WhereClause<'a> {
153153
try!(write!(f, "{}", lifetime));
154154
}
155155
}
156-
&clean::WherePredicate::EqPredicate => {
157-
unimplemented!()
156+
&clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
157+
try!(write!(f, "{} == {}", lhs, rhs));
158158
}
159159
}
160160
}

0 commit comments

Comments
 (0)