From 37225288be1f29ce15ad24855cdbbf06ba5890c8 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Tue, 16 Dec 2014 08:50:52 -0800 Subject: [PATCH] rustdoc: render higher-rank trait bounds Fix #19915 --- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 68 ++++++++++++++++++++++++++-------- src/librustdoc/html/format.rs | 34 ++++++++++++----- 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2bc93ade7774e..cdc51bb801c58 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -328,7 +328,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, derived: clean::detect_derived(attrs.as_slice()), trait_: associated_trait.clean(cx).map(|bound| { match bound { - clean::TraitBound(ty) => ty, + clean::TraitBound(polyt) => polyt.trait_, clean::RegionBound(..) => unreachable!(), } }), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0dd6c2a7ce730..749686fa28351 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -43,8 +43,7 @@ use rustc::metadata::cstore; use rustc::metadata::csearch; use rustc::metadata::decoder; use rustc::middle::def; -use rustc::middle::subst; -use rustc::middle::subst::VecPerParamSpace; +use rustc::middle::subst::{mod, ParamSpace, VecPerParamSpace}; use rustc::middle::ty; use rustc::middle::stability; use rustc::session::config; @@ -493,7 +492,7 @@ impl<'tcx> Clean for ty::TypeParameterDef<'tcx> { #[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)] pub enum TyParamBound { RegionBound(Lifetime), - TraitBound(Type) + TraitBound(PolyTrait) } impl Clean for ast::TyParamBound { @@ -558,10 +557,13 @@ impl Clean for ty::BuiltinBound { let fqn = fqn.into_iter().map(|i| i.to_string()).collect(); cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait)); - TraitBound(ResolvedPath { - path: path, - typarams: None, - did: did, + TraitBound(PolyTrait { + trait_: ResolvedPath { + path: path, + typarams: None, + did: did, + }, + lifetimes: vec![] }) } } @@ -585,10 +587,31 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { &self.substs); cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id, (fqn, TypeTrait)); - TraitBound(ResolvedPath { - path: path, - typarams: None, - did: self.def_id, + + debug!("ty::TraitRef\n substs.types(TypeSpace): {}\n", + self.substs.types.get_slice(ParamSpace::TypeSpace)); + + // collect any late bound regions + let mut late_bounds = vec![]; + for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace).iter() { + use rustc::middle::ty::{Region, sty}; + if let sty::ty_tup(ref ts) = ty_s.sty { + for &ty_s in ts.iter() { + if let sty::ty_rptr(ref reg, _) = ty_s.sty { + if let &Region::ReLateBound(_, _) = reg { + debug!(" hit an ReLateBound {}", reg); + if let Some(lt) = reg.clean(cx) { + late_bounds.push(lt) + } + } + } + } + } + } + + TraitBound(PolyTrait { + trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, }, + lifetimes: late_bounds }) } } @@ -615,7 +638,7 @@ impl<'tcx> Clean<(Vec, Option)> for ty::ParamBounds<'tcx> { (v, None) } else { let ty = match ty::BoundSized.clean(cx) { - TraitBound(ty) => ty, + TraitBound(polyt) => polyt.trait_, _ => unreachable!() }; (v, Some(ty)) @@ -627,7 +650,10 @@ impl<'tcx> Clean>> for subst::Substs<'tcx> { fn clean(&self, cx: &DocContext) -> Option> { let mut v = Vec::new(); v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound)); - v.extend(self.types.iter().map(|t| TraitBound(t.clean(cx)))); + v.extend(self.types.iter().map(|t| TraitBound(PolyTrait { + trait_: t.clean(cx), + lifetimes: vec![] + }))); if v.len() > 0 {Some(v)} else {None} } } @@ -1006,9 +1032,12 @@ impl Clean for ast::TraitRef { } } -impl Clean for ast::PolyTraitRef { - fn clean(&self, cx: &DocContext) -> Type { - self.trait_ref.clean(cx) +impl Clean for ast::PolyTraitRef { + fn clean(&self, cx: &DocContext) -> PolyTrait { + PolyTrait { + trait_: self.trait_ref.clean(cx), + lifetimes: self.bound_lifetimes.clean(cx) + } } } @@ -1129,6 +1158,13 @@ impl<'tcx> Clean for ty::ImplOrTraitItem<'tcx> { } } +/// A trait reference, which may have higher ranked lifetimes. +#[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)] +pub struct PolyTrait { + pub trait_: Type, + pub lifetimes: Vec +} + /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original /// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly /// it does not preserve mutability or boxes. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4ec974b0cf777..83f760f15f63a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -142,6 +142,22 @@ impl fmt::Show for clean::Lifetime { } } +impl fmt::Show for clean::PolyTrait { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.lifetimes.len() > 0 { + try!(f.write("for<".as_bytes())); + for (i, lt) in self.lifetimes.iter().enumerate() { + if i > 0 { + try!(f.write(", ".as_bytes())); + } + try!(write!(f, "{}", lt)); + } + try!(f.write("> ".as_bytes())); + } + write!(f, "{}", self.trait_) + } +} + impl fmt::Show for clean::TyParamBound { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -389,15 +405,6 @@ impl fmt::Show for clean::Type { try!(resolved_path(f, did, path, false)); tybounds(f, typarams) } - clean::PolyTraitRef(ref bounds) => { - for (i, bound) in bounds.iter().enumerate() { - if i != 0 { - try!(write!(f, " + ")); - } - try!(write!(f, "{}", *bound)); - } - Ok(()) - } clean::Infer => write!(f, "_"), clean::Self(..) => f.write("Self".as_bytes()), clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()), @@ -505,6 +512,15 @@ impl fmt::Show for clean::Type { } } } + clean::PolyTraitRef(ref bounds) => { + for (i, bound) in bounds.iter().enumerate() { + if i != 0 { + try!(write!(f, " + ")); + } + try!(write!(f, "{}", *bound)); + } + Ok(()) + } clean::QPath { ref name, ref self_type, ref trait_ } => { write!(f, "<{} as {}>::{}", self_type, trait_, name) }