about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-02-14 18:14:38 -0800
committerMichael Goulet <michael@errs.io>2022-02-27 21:36:29 -0800
commitca6e06efba2201da6be9d48f3f922fbb4e90af5f (patch)
treed589db449ecfe4427c7dee2f447ec7942f44140d /src
parent8a0c2c4e83c216811d96a4a5af9987431b75bd6f (diff)
downloadrust-ca6e06efba2201da6be9d48f3f922fbb4e90af5f.tar.gz
rust-ca6e06efba2201da6be9d48f3f922fbb4e90af5f.zip
make GATs print properly in traits
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/clean/mod.rs70
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/librustdoc/fold.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs57
-rw-r--r--src/librustdoc/json/conversions.rs5
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs2
-rw-r--r--src/librustdoc/visit.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs3
9 files changed, 98 insertions, 48 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e0e641c2f9b..2864f69756b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -985,9 +985,10 @@ impl Clean<Item> for hir::TraitItem<'_> {
                     TyMethodItem(t)
                 }
                 hir::TraitItemKind::Type(bounds, ref default) => {
+                    let generics = self.generics.clean(cx);
                     let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
                     let default = default.map(|t| t.clean(cx));
-                    AssocTypeItem(bounds, default)
+                    AssocTypeItem(Box::new(generics), bounds, default)
                 }
             };
             let what_rustc_thinks =
@@ -1138,32 +1139,55 @@ impl Clean<Item> for ty::AssocItem {
                 if let ty::TraitContainer(_) = self.container {
                     let bounds = tcx.explicit_item_bounds(self.def_id);
                     let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
-                    let generics = clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
+                    let mut generics =
+                        clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
+                    // Filter out the bounds that are (likely?) directly attached to the associated type,
+                    // as opposed to being located in the where clause.
                     let mut bounds = generics
                         .where_predicates
-                        .iter()
-                        .filter_map(|pred| {
-                            let (name, self_type, trait_, bounds) = match *pred {
-                                WherePredicate::BoundPredicate {
-                                    ty: QPath { ref name, ref self_type, ref trait_, .. },
-                                    ref bounds,
-                                    ..
-                                } => (name, self_type, trait_, bounds),
-                                _ => return None,
-                            };
-                            if *name != my_name {
-                                return None;
-                            }
-                            if trait_.def_id() != self.container.id() {
-                                return None;
+                        .drain_filter(|pred| match *pred {
+                            WherePredicate::BoundPredicate {
+                                ty: QPath { name, ref self_type, ref trait_, .. },
+                                ..
+                            } => {
+                                if name != my_name {
+                                    return false;
+                                }
+                                if trait_.def_id() != self.container.id() {
+                                    return false;
+                                }
+                                match **self_type {
+                                    Generic(ref s) if *s == kw::SelfUpper => {}
+                                    _ => return false,
+                                }
+                                match &assoc.args {
+                                    GenericArgs::AngleBracketed { args, bindings } => {
+                                        if !bindings.is_empty()
+                                            || generics
+                                                .params
+                                                .iter()
+                                                .zip(args)
+                                                .any(|(param, arg)| !param_eq_arg(param, arg))
+                                        {
+                                            return false;
+                                        }
+                                    }
+                                    GenericArgs::Parenthesized { .. } => {
+                                        // The only time this happens is if we're inside the rustdoc for Fn(),
+                                        // which only has one associated type, which is not a GAT, so whatever.
+                                    }
+                                }
+                                true
                             }
-                            match **self_type {
-                                Generic(ref s) if *s == kw::SelfUpper => {}
-                                _ => return None,
+                            _ => false,
+                        })
+                        .flat_map(|pred| {
+                            if let WherePredicate::BoundPredicate { bounds, .. } = pred {
+                                bounds
+                            } else {
+                                unreachable!()
                             }
-                            Some(bounds)
                         })
-                        .flat_map(|i| i.iter().cloned())
                         .collect::<Vec<_>>();
                     // Our Sized/?Sized bound didn't get handled when creating the generics
                     // because we didn't actually get our whole set of bounds until just now
@@ -1183,7 +1207,7 @@ impl Clean<Item> for ty::AssocItem {
                         None
                     };
 
-                    AssocTypeItem(bounds, ty.map(|t| t.clean(cx)))
+                    AssocTypeItem(Box::new(generics), bounds, ty.map(|t| t.clean(cx)))
                 } else {
                     // FIXME: when could this happen? Associated items in inherent impls?
                     let type_ = tcx.type_of(self.def_id).clean(cx);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 467a6940628..3f40385f9b9 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -683,7 +683,7 @@ crate enum ItemKind {
     ///
     /// The bounds may be non-empty if there is a `where` clause.
     /// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
-    AssocTypeItem(Vec<GenericBound>, Option<Type>),
+    AssocTypeItem(Box<Generics>, Vec<GenericBound>, Option<Type>),
     /// An item that has been stripped by a rustdoc pass
     StrippedItem(Box<ItemKind>),
     KeywordItem(Symbol),
@@ -721,7 +721,7 @@ impl ItemKind {
             | ProcMacroItem(_)
             | PrimitiveItem(_)
             | AssocConstItem(_, _)
-            | AssocTypeItem(_, _)
+            | AssocTypeItem(..)
             | StrippedItem(_)
             | KeywordItem(_) => [].iter(),
         }
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index cd0f44e5696..fbb8b572ea4 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -86,7 +86,7 @@ crate trait DocFolder: Sized {
             | ProcMacroItem(_)
             | PrimitiveItem(_)
             | AssocConstItem(_, _)
-            | AssocTypeItem(_, _)
+            | AssocTypeItem(..)
             | KeywordItem(_) => kind,
         }
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 1d111077606..558dbb3b396 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -773,22 +773,25 @@ fn assoc_const(
 fn assoc_type(
     w: &mut Buffer,
     it: &clean::Item,
+    generics: &clean::Generics,
     bounds: &[clean::GenericBound],
     default: Option<&clean::Type>,
     link: AssocItemLink<'_>,
-    extra: &str,
+    indent: usize,
     cx: &Context<'_>,
 ) {
     write!(
         w,
-        "{}type <a href=\"{}\" class=\"associatedtype\">{}</a>",
-        extra,
-        naive_assoc_href(it, link, cx),
-        it.name.as_ref().unwrap()
+        "{indent}type <a href=\"{href}\" class=\"associatedtype\">{name}</a>{generics}",
+        indent = " ".repeat(indent),
+        href = naive_assoc_href(it, link, cx),
+        name = it.name.as_ref().unwrap(),
+        generics = generics.print(cx),
     );
     if !bounds.is_empty() {
         write!(w, ": {}", print_generic_bounds(bounds, cx))
     }
+    write!(w, "{}", print_where_clause(generics, cx, indent, false));
     if let Some(default) = default {
         write!(w, " = {}", default.print(cx))
     }
@@ -812,11 +815,8 @@ fn assoc_method(
         AssocItemLink::GotoSource(did, provided_methods) => {
             // We're creating a link from an impl-item to the corresponding
             // trait-item and need to map the anchored type accordingly.
-            let ty = if provided_methods.contains(name) {
-                ItemType::Method
-            } else {
-                ItemType::TyMethod
-            };
+            let ty =
+                if provided_methods.contains(name) { ItemType::Method } else { ItemType::TyMethod };
 
             match (href(did.expect_def_id(), cx), ty) {
                 (Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
@@ -974,13 +974,14 @@ fn render_assoc_item(
         clean::AssocConstItem(ref ty, _) => {
             assoc_const(w, item, ty, link, if parent == ItemType::Trait { "    " } else { "" }, cx)
         }
-        clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
+        clean::AssocTypeItem(ref generics, ref bounds, ref default) => assoc_type(
             w,
             item,
+            generics,
             bounds,
             default.as_ref(),
             link,
-            if parent == ItemType::Trait { "    " } else { "" },
+            if parent == ItemType::Trait { 4 } else { 0 },
             cx,
         ),
         _ => panic!("render_assoc_item called on non-associated-item"),
@@ -1284,7 +1285,16 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
                                 let empty_set = FxHashSet::default();
                                 let src_link =
                                     AssocItemLink::GotoSource(trait_did.into(), &empty_set);
-                                assoc_type(&mut out, it, &[], Some(&tydef.type_), src_link, "", cx);
+                                assoc_type(
+                                    &mut out,
+                                    it,
+                                    &tydef.generics,
+                                    &[],
+                                    Some(&tydef.type_),
+                                    src_link,
+                                    0,
+                                    cx,
+                                );
                                 out.push_str(";</span>");
                             }
                         }
@@ -1463,10 +1473,11 @@ fn render_impl(
                 assoc_type(
                     w,
                     item,
-                    &Vec::new(),
+                    &tydef.generics,
+                    &[],
                     Some(&tydef.type_),
                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                    "",
+                    0,
                     cx,
                 );
                 w.write_str("</h4>");
@@ -1494,7 +1505,7 @@ fn render_impl(
                 w.write_str("</h4>");
                 w.write_str("</section>");
             }
-            clean::AssocTypeItem(ref bounds, ref default) => {
+            clean::AssocTypeItem(ref generics, ref bounds, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
                 write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
@@ -1503,10 +1514,11 @@ fn render_impl(
                 assoc_type(
                     w,
                     item,
+                    generics,
                     bounds,
                     default.as_ref(),
                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                    "",
+                    0,
                     cx,
                 );
                 w.write_str("</h4>");
@@ -1727,7 +1739,16 @@ pub(crate) fn render_impl_summary(
             for it in &i.inner_impl().items {
                 if let clean::TypedefItem(ref tydef, _) = *it.kind {
                     w.write_str("<span class=\"where fmt-newline\">  ");
-                    assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
+                    assoc_type(
+                        w,
+                        it,
+                        &tydef.generics,
+                        &[],
+                        Some(&tydef.type_),
+                        AssocItemLink::Anchor(None),
+                        0,
+                        cx,
+                    );
                     w.write_str(";</span>");
                 }
             }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index d4aedb41ddb..da92e682fe8 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -222,8 +222,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
         AssocConstItem(ty, default) => {
             ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) }
         }
-        AssocTypeItem(g, t) => ItemEnum::AssocType {
-            bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+        AssocTypeItem(g, b, t) => ItemEnum::AssocType {
+            generics: (*g).into_tcx(tcx),
+            bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
             default: t.map(|x| x.into_tcx(tcx)),
         },
         // `convert_item` early returns `None` for striped items
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 5c8a8fb80f1..3c2a08463d8 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -9,6 +9,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(box_syntax)]
+#![feature(drain_filter)]
 #![feature(let_else)]
 #![feature(nll)]
 #![feature(test)]
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index e8f8ff988c1..6cffb52bb87 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -62,7 +62,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo
             clean::StructFieldItem(_)
                 | clean::VariantItem(_)
                 | clean::AssocConstItem(_, _)
-                | clean::AssocTypeItem(_, _)
+                | clean::AssocTypeItem(..)
                 | clean::TypedefItem(_, _)
                 | clean::StaticItem(_)
                 | clean::ConstantItem(_)
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index df4d1558ebd..b16cab1c646 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -41,7 +41,7 @@ crate trait DocVisitor: Sized {
             | ProcMacroItem(_)
             | PrimitiveItem(_)
             | AssocConstItem(_, _)
-            | AssocTypeItem(_, _)
+            | AssocTypeItem(..)
             | KeywordItem(_) => {}
         }
     }
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index be9bbc7391d..dfaec6991a4 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -233,6 +233,9 @@ pub enum ItemEnum {
         default: Option<String>,
     },
     AssocType {
+        /// generics and `where` clause
+        generics: Generics,
+        /// e.g. `: Sized`
         bounds: Vec<GenericBound>,
         /// e.g. `type X = usize;`
         default: Option<Type>,