about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJustus K <justus.k@protonmail.com>2021-05-02 14:48:28 +0200
committerJustus K <justus.k@protonmail.com>2021-06-18 21:57:55 +0200
commite0162a8a56d1c59e185e293f33c38d94a5a2d462 (patch)
tree068b7709ff8b46d74e5872d460038a34699c8f57
parent312b894cc12240a3fcc645474c3daa14f7d568ea (diff)
downloadrust-e0162a8a56d1c59e185e293f33c38d94a5a2d462.tar.gz
rust-e0162a8a56d1c59e185e293f33c38d94a5a2d462.zip
rustdoc: Render `for<'_>` lifetimes in front of where bound
-rw-r--r--src/librustdoc/clean/auto_trait.rs8
-rw-r--r--src/librustdoc/clean/inline.rs11
-rw-r--r--src/librustdoc/clean/mod.rs11
-rw-r--r--src/librustdoc/clean/simplify.rs28
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/html/format.rs22
-rw-r--r--src/librustdoc/json/conversions.rs3
-rw-r--r--src/test/rustdoc/higher-ranked-trait-bounds.rs41
8 files changed, 104 insertions, 22 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index a3f63ea1046..0828f0b3e51 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -414,7 +414,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 let mut bounds_vec = bounds.into_iter().collect();
                 self.sort_where_bounds(&mut bounds_vec);
 
-                Some(WherePredicate::BoundPredicate { ty, bounds: bounds_vec })
+                Some(WherePredicate::BoundPredicate {
+                    ty,
+                    bounds: bounds_vec,
+                    bound_params: Vec::new(),
+                })
             })
             .chain(
                 lifetime_to_bounds.into_iter().filter(|&(_, ref bounds)| !bounds.is_empty()).map(
@@ -492,7 +496,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
             }
             let p = p.unwrap();
             match p {
-                WherePredicate::BoundPredicate { ty, mut bounds } => {
+                WherePredicate::BoundPredicate { ty, mut bounds, .. } => {
                     // Writing a projection trait bound of the form
                     // <T as Trait>::Name : ?Sized
                     // is illegal, because ?Sized bounds can only
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 111827aacdf..e8f0960da79 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -566,9 +566,11 @@ fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::Item
 fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
     for pred in &mut g.where_predicates {
         match *pred {
-            clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref mut bounds }
-                if *s == kw::SelfUpper =>
-            {
+            clean::WherePredicate::BoundPredicate {
+                ty: clean::Generic(ref s),
+                ref mut bounds,
+                ..
+            } if *s == kw::SelfUpper => {
                 bounds.retain(|bound| match *bound {
                     clean::GenericBound::TraitBound(
                         clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. },
@@ -591,6 +593,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
                     ..
                 },
             ref bounds,
+            ..
         } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did),
         _ => true,
     });
@@ -605,7 +608,7 @@ fn separate_supertrait_bounds(
 ) -> (clean::Generics, Vec<clean::GenericBound>) {
     let mut ty_bounds = Vec::new();
     g.where_predicates.retain(|pred| match *pred {
-        clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds }
+        clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
             if *s == kw::SelfUpper =>
         {
             ty_bounds.extend(bounds.iter().cloned());
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bc04480ab7c..634a8dae763 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -330,6 +330,7 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
             hir::WherePredicate::BoundPredicate(ref wbp) => WherePredicate::BoundPredicate {
                 ty: wbp.bounded_ty.clean(cx),
                 bounds: wbp.bounds.clean(cx),
+                bound_params: wbp.bound_generic_params.into_iter().map(|x| x.clean(cx)).collect(),
             },
 
             hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
@@ -370,6 +371,7 @@ impl<'a> Clean<WherePredicate> for ty::PolyTraitPredicate<'a> {
         WherePredicate::BoundPredicate {
             ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
             bounds: vec![poly_trait_ref.clean(cx)],
+            bound_params: Vec::new(),
         }
     }
 }
@@ -402,6 +404,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
         Some(WherePredicate::BoundPredicate {
             ty: ty.clean(cx),
             bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
+            bound_params: Vec::new(),
         })
     }
 }
@@ -567,7 +570,9 @@ impl Clean<Generics> for hir::Generics<'_> {
         // to where predicates when such cases occur.
         for where_pred in &mut generics.where_predicates {
             match *where_pred {
-                WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
+                WherePredicate::BoundPredicate {
+                    ty: Generic(ref name), ref mut bounds, ..
+                } => {
                     if bounds.is_empty() {
                         for param in &mut generics.params {
                             match param.kind {
@@ -721,7 +726,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
         // handled in cleaning associated types
         let mut sized_params = FxHashSet::default();
         where_predicates.retain(|pred| match *pred {
-            WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
+            WP::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
                 if bounds.iter().any(|b| b.is_sized_bound(cx)) {
                     sized_params.insert(*g);
                     false
@@ -741,6 +746,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
                 where_predicates.push(WP::BoundPredicate {
                     ty: Type::Generic(tp.name),
                     bounds: vec![GenericBound::maybe_sized(cx)],
+                    bound_params: Vec::new(),
                 })
             }
         }
@@ -1117,6 +1123,7 @@ impl Clean<Item> for ty::AssocItem {
                                 WherePredicate::BoundPredicate {
                                     ty: QPath { ref name, ref self_type, ref trait_, .. },
                                     ref bounds,
+                                    ..
                                 } => (name, self_type, trait_, bounds),
                                 _ => return None,
                             };
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index d4d0a8ce24c..3ec0a22a2c0 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -24,16 +24,20 @@ use crate::core::DocContext;
 
 crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     // First, partition the where clause into its separate components
-    let mut params: BTreeMap<_, Vec<_>> = BTreeMap::new();
+    let mut params: BTreeMap<_, (Vec<_>, Vec<_>)> = BTreeMap::new();
     let mut lifetimes = Vec::new();
     let mut equalities = Vec::new();
     let mut tybounds = Vec::new();
 
     for clause in clauses {
         match clause {
-            WP::BoundPredicate { ty, bounds } => match ty {
-                clean::Generic(s) => params.entry(s).or_default().extend(bounds),
-                t => tybounds.push((t, bounds)),
+            WP::BoundPredicate { ty, bounds, bound_params } => match ty {
+                clean::Generic(s) => {
+                    let (b, p) = params.entry(s).or_default();
+                    b.extend(bounds);
+                    p.extend(bound_params);
+                }
+                t => tybounds.push((t, (bounds, bound_params))),
             },
             WP::RegionPredicate { lifetime, bounds } => {
                 lifetimes.push((lifetime, bounds));
@@ -54,7 +58,7 @@ crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
             clean::Generic(s) => s,
             _ => return true,
         };
-        let bounds = match params.get_mut(generic) {
+        let (bounds, _) = match params.get_mut(generic) {
             Some(bound) => bound,
             None => return true,
         };
@@ -67,10 +71,16 @@ crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     clauses.extend(
         lifetimes.into_iter().map(|(lt, bounds)| WP::RegionPredicate { lifetime: lt, bounds }),
     );
-    clauses.extend(
-        params.into_iter().map(|(k, v)| WP::BoundPredicate { ty: clean::Generic(k), bounds: v }),
-    );
-    clauses.extend(tybounds.into_iter().map(|(ty, bounds)| WP::BoundPredicate { ty, bounds }));
+    clauses.extend(params.into_iter().map(|(k, (bounds, params))| WP::BoundPredicate {
+        ty: clean::Generic(k),
+        bounds,
+        bound_params: params,
+    }));
+    clauses.extend(tybounds.into_iter().map(|(ty, (bounds, bound_params))| WP::BoundPredicate {
+        ty,
+        bounds,
+        bound_params,
+    }));
     clauses.extend(equalities.into_iter().map(|(lhs, rhs)| WP::EqPredicate { lhs, rhs }));
     clauses
 }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6a7c3f8caa4..5d036d4d35b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1193,7 +1193,7 @@ impl Lifetime {
 
 #[derive(Clone, Debug)]
 crate enum WherePredicate {
-    BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
+    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
     EqPredicate { lhs: Type, rhs: Type },
 }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 918a5cb5094..a424932d83f 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -249,17 +249,33 @@ crate fn print_where_clause<'a, 'tcx: 'a>(
             }
 
             match pred {
-                clean::WherePredicate::BoundPredicate { ty, bounds } => {
+                clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
                     let bounds = bounds;
+                    let for_prefix = match bound_params.len() {
+                        0 => String::new(),
+                        _ if f.alternate() => {
+                            format!(
+                                "for<{:#}> ",
+                                comma_sep(bound_params.iter().map(|lt| lt.print()))
+                            )
+                        }
+                        _ => format!(
+                            "for&lt;{}&gt; ",
+                            comma_sep(bound_params.iter().map(|lt| lt.print()))
+                        ),
+                    };
+
                     if f.alternate() {
                         clause.push_str(&format!(
-                            "{:#}: {:#}",
+                            "{}{:#}: {:#}",
+                            for_prefix,
                             ty.print(cx),
                             print_generic_bounds(bounds, cx)
                         ));
                     } else {
                         clause.push_str(&format!(
-                            "{}: {}",
+                            "{}{}: {}",
+                            for_prefix,
                             ty.print(cx),
                             print_generic_bounds(bounds, cx)
                         ));
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 7086dd8c4d2..c844d91096a 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -328,9 +328,10 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
     fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
         use clean::WherePredicate::*;
         match predicate {
-            BoundPredicate { ty, bounds } => WherePredicate::BoundPredicate {
+            BoundPredicate { ty, bounds, .. } => WherePredicate::BoundPredicate {
                 ty: ty.into_tcx(tcx),
                 bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+                // FIXME: add `bound_params` to rustdoc-json-params?
             },
             RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
                 lifetime: lifetime.0.to_string(),
diff --git a/src/test/rustdoc/higher-ranked-trait-bounds.rs b/src/test/rustdoc/higher-ranked-trait-bounds.rs
new file mode 100644
index 00000000000..b5c55df287b
--- /dev/null
+++ b/src/test/rustdoc/higher-ranked-trait-bounds.rs
@@ -0,0 +1,41 @@
+#![crate_name = "foo"]
+
+trait A<'x> {}
+
+// @has foo/fn.test1.html
+// @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator,"
+pub fn test1<T>()
+where
+    for<'a> &'a T: Iterator,
+{
+}
+
+// @has foo/fn.test2.html
+// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: A<'b>,"
+pub fn test2<T>()
+where
+    for<'a, 'b> &'a T: A<'b>,
+{
+}
+
+// @has foo/fn.test3.html
+// @has - '//pre' "pub fn test3<F>() where F: for<'a, 'b> Fn(&'a u8, &'b u8),"
+pub fn test3<F>()
+where
+    F: for<'a, 'b> Fn(&'a u8, &'b u8),
+{
+}
+
+// @has foo/struct.Foo.html
+pub struct Foo<'a> {
+    _x: &'a u8,
+}
+
+impl<'a> Foo<'a> {
+    // @has - '//code' "pub fn bar<T>() where T: A<'a>,"
+    pub fn bar<T>()
+    where
+        T: A<'a>,
+    {
+    }
+}