about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTom Jakubowski <tom@crystae.net>2014-12-16 08:50:52 -0800
committerTom Jakubowski <tom@crystae.net>2014-12-24 11:18:27 -0600
commit37225288be1f29ce15ad24855cdbbf06ba5890c8 (patch)
tree99e59df5f22721eaa029b5669ba436ee11352750
parentb39e99cfc72a21ae6e697e9db2cef252dfb1aecb (diff)
downloadrust-37225288be1f29ce15ad24855cdbbf06ba5890c8.tar.gz
rust-37225288be1f29ce15ad24855cdbbf06ba5890c8.zip
rustdoc: render higher-rank trait bounds
Fix #19915
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/clean/mod.rs68
-rw-r--r--src/librustdoc/html/format.rs34
3 files changed, 78 insertions, 26 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 2bc93ade777..cdc51bb801c 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 0dd6c2a7ce7..749686fa283 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<TyParam> for ty::TypeParameterDef<'tcx> {
 #[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)]
 pub enum TyParamBound {
     RegionBound(Lifetime),
-    TraitBound(Type)
+    TraitBound(PolyTrait)
 }
 
 impl Clean<TyParamBound> for ast::TyParamBound {
@@ -558,10 +557,13 @@ impl Clean<TyParamBound> 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<TyParamBound> 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<TyParamBound>, Option<Type>)> 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<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
     fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
         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<Type> for ast::TraitRef {
     }
 }
 
-impl Clean<Type> for ast::PolyTraitRef {
-    fn clean(&self, cx: &DocContext) -> Type {
-        self.trait_ref.clean(cx)
+impl Clean<PolyTrait> 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<Item> 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<Lifetime>
+}
+
 /// 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 4ec974b0cf7..83f760f15f6 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&lt;".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("&gt; ".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, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
             }