diff options
| author | Tom Jakubowski <tom@crystae.net> | 2015-01-10 23:50:46 -0800 |
|---|---|---|
| committer | Tom Jakubowski <tom@crystae.net> | 2015-01-12 09:25:07 -0800 |
| commit | 8a69d35e1edf6dee4c1f5163e8b7160d8479ebc0 (patch) | |
| tree | 13f20094786697381d2dd24417ff3a39f603048c | |
| parent | 099b411e080d302ec0dc5f3aebe53d76c50acfc7 (diff) | |
| download | rust-8a69d35e1edf6dee4c1f5163e8b7160d8479ebc0.tar.gz rust-8a69d35e1edf6dee4c1f5163e8b7160d8479ebc0.zip | |
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
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 171 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 4 |
2 files changed, 160 insertions, 15 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a44c73e8c41..80494e38110 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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() @@ -603,12 +609,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() { @@ -730,8 +730,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 +751,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 +854,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 } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 00f7c570b5d..4bfde9e5d7d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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)); } } } |
