diff options
| author | Michael Goulet <michael@errs.io> | 2022-02-14 18:14:38 -0800 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2022-02-27 21:36:29 -0800 |
| commit | ca6e06efba2201da6be9d48f3f922fbb4e90af5f (patch) | |
| tree | d589db449ecfe4427c7dee2f447ec7942f44140d /src | |
| parent | 8a0c2c4e83c216811d96a4a5af9987431b75bd6f (diff) | |
| download | rust-ca6e06efba2201da6be9d48f3f922fbb4e90af5f.tar.gz rust-ca6e06efba2201da6be9d48f3f922fbb4e90af5f.zip | |
make GATs print properly in traits
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 70 | ||||
| -rw-r--r-- | src/librustdoc/clean/types.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/fold.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/html/render/mod.rs | 57 | ||||
| -rw-r--r-- | src/librustdoc/json/conversions.rs | 5 | ||||
| -rw-r--r-- | src/librustdoc/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustdoc/passes/check_doc_test_visibility.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/visit.rs | 2 | ||||
| -rw-r--r-- | src/rustdoc-json-types/lib.rs | 3 |
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>, |
