From 8a69d35e1edf6dee4c1f5163e8b7160d8479ebc0 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Sat, 10 Jan 2015 23:50:46 -0800 Subject: [PATCH 1/3] 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 --- src/librustdoc/clean/mod.rs | 171 +++++++++++++++++++++++++++++++--- 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 a44c73e8c412..80494e381109 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -104,6 +104,12 @@ impl, U> Clean> for Option { } } +impl Clean for ty::Binder where T: Clean { + fn clean(&self, cx: &DocContext) -> U { + self.0.clean(cx) + } +} + impl, U> Clean> for syntax::owned_slice::OwnedSlice { fn clean(&self, cx: &DocContext) -> Vec { self.iter().map(|x| x.clean(cx)).collect() @@ -603,12 +609,6 @@ impl Clean for ty::BuiltinBound { } } -impl<'tcx> Clean for ty::PolyTraitRef<'tcx> { - fn clean(&self, cx: &DocContext) -> TyParamBound { - self.0.clean(cx) - } -} - impl<'tcx> Clean for ty::TraitRef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParamBound { let tcx = match cx.tcx_opt() { @@ -730,8 +730,7 @@ impl Clean> for ty::Region { pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec}, - // FIXME (#20041) - EqPredicate + EqPredicate { lhs: Type, rhs: Type } } impl Clean for ast::WherePredicate { @@ -752,12 +751,89 @@ impl Clean for ast::WherePredicate { } ast::WherePredicate::EqPredicate(_) => { - WherePredicate::EqPredicate + unimplemented!() // FIXME(#20041) } } } } +impl<'a> Clean 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 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 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 for ty::OutlivesPredicate { + 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 for ty::OutlivesPredicate, 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 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 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 for ast::Generics { impl<'a, 'tcx> Clean 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::>(); + let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| { + let mut srp = rp.clone(); + srp.bounds = Vec::new(); + srp.clean(cx) + }).collect::>(); + + 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::>(); + // 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 00f7c570b5d0..4bfde9e5d7d9 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)); } } } From 072a89642bae1a1aca96acda290dab1bcf318696 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Mon, 12 Jan 2015 09:08:50 -0800 Subject: [PATCH 2/3] rustdoc: Remove traces of old closures --- src/librustdoc/clean/mod.rs | 23 --------------- src/librustdoc/html/format.rs | 55 ----------------------------------- 2 files changed, 78 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 80494e381109..4c2cd8864c76 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1055,27 +1055,6 @@ impl Clean for doctree::Function { } } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)] -pub struct ClosureDecl { - pub lifetimes: Vec, - pub decl: FnDecl, - pub onceness: ast::Onceness, - pub unsafety: ast::Unsafety, - pub bounds: Vec, -} - -impl Clean 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, @@ -1352,8 +1331,6 @@ pub enum Type { Generic(String), /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char. Primitive(PrimitiveType), - Closure(Box), - Proc(Box), /// extern "ABI" fn BareFunction(Box), Tuple(Vec), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4bfde9e5d7d9..61d2a9ee0710 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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::>().connect(" + ")) - }, - arrow = decl.decl.output) - } clean::BareFunction(ref decl) => { write!(f, "{}{}fn{}{}", UnsafetySpace(decl.unsafety), From 616db5a501510cf29acf118812c192788e4e81e7 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Mon, 12 Jan 2015 09:43:24 -0800 Subject: [PATCH 3/3] rustdoc: Show type bindings on object types Fix #20299 --- src/librustdoc/clean/mod.rs | 47 +++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4c2cd8864c76..b65e1d1d664b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -504,22 +504,28 @@ impl Clean for ast::TyParamBound { } } -impl<'tcx> Clean> for ty::ExistentialBounds<'tcx> { - fn clean(&self, cx: &DocContext) -> Vec { - let mut vec = vec![]; - self.region_bound.clean(cx).map(|b| vec.push(RegionBound(b))); +impl<'tcx> Clean<(Vec, Vec)> for ty::ExistentialBounds<'tcx> { + fn clean(&self, cx: &DocContext) -> (Vec, Vec) { + 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, - substs: &subst::Substs) -> PathParameters { + bindings: Vec, substs: &subst::Substs) -> PathParameters { use rustc::middle::ty::sty; let lifetimes = substs.regions().get_slice(subst::TypeSpace) .iter() @@ -537,7 +543,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, return PathParameters::AngleBracketed { lifetimes: lifetimes, types: types.clean(cx), - bindings: vec![] + bindings: bindings } } }; @@ -554,7 +560,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, PathParameters::AngleBracketed { lifetimes: lifetimes, types: types.clean(cx), - bindings: vec![] // FIXME(#20646) + bindings: bindings } } } @@ -563,12 +569,12 @@ fn external_path_params(cx: &DocContext, trait_did: Option, // 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, - substs: &subst::Substs) -> Path { + bindings: Vec, 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) }], } } @@ -583,16 +589,16 @@ impl Clean 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(); @@ -619,7 +625,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { let fqn = fqn.into_iter().map(|i| i.to_string()) .collect::>(); 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)); @@ -1558,7 +1564,7 @@ impl<'tcx> Clean 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, @@ -1570,12 +1576,13 @@ impl<'tcx> Clean 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, } }