Skip to content

Commit ca6e06e

Browse files
make GATs print properly in traits
1 parent 8a0c2c4 commit ca6e06e

File tree

9 files changed

+98
-48
lines changed

9 files changed

+98
-48
lines changed

src/librustdoc/clean/mod.rs

+47-23
Original file line numberDiff line numberDiff line change
@@ -985,9 +985,10 @@ impl Clean<Item> for hir::TraitItem<'_> {
985985
TyMethodItem(t)
986986
}
987987
hir::TraitItemKind::Type(bounds, ref default) => {
988+
let generics = self.generics.clean(cx);
988989
let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
989990
let default = default.map(|t| t.clean(cx));
990-
AssocTypeItem(bounds, default)
991+
AssocTypeItem(Box::new(generics), bounds, default)
991992
}
992993
};
993994
let what_rustc_thinks =
@@ -1138,32 +1139,55 @@ impl Clean<Item> for ty::AssocItem {
11381139
if let ty::TraitContainer(_) = self.container {
11391140
let bounds = tcx.explicit_item_bounds(self.def_id);
11401141
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
1141-
let generics = clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
1142+
let mut generics =
1143+
clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
1144+
// Filter out the bounds that are (likely?) directly attached to the associated type,
1145+
// as opposed to being located in the where clause.
11421146
let mut bounds = generics
11431147
.where_predicates
1144-
.iter()
1145-
.filter_map(|pred| {
1146-
let (name, self_type, trait_, bounds) = match *pred {
1147-
WherePredicate::BoundPredicate {
1148-
ty: QPath { ref name, ref self_type, ref trait_, .. },
1149-
ref bounds,
1150-
..
1151-
} => (name, self_type, trait_, bounds),
1152-
_ => return None,
1153-
};
1154-
if *name != my_name {
1155-
return None;
1156-
}
1157-
if trait_.def_id() != self.container.id() {
1158-
return None;
1148+
.drain_filter(|pred| match *pred {
1149+
WherePredicate::BoundPredicate {
1150+
ty: QPath { name, ref self_type, ref trait_, .. },
1151+
..
1152+
} => {
1153+
if name != my_name {
1154+
return false;
1155+
}
1156+
if trait_.def_id() != self.container.id() {
1157+
return false;
1158+
}
1159+
match **self_type {
1160+
Generic(ref s) if *s == kw::SelfUpper => {}
1161+
_ => return false,
1162+
}
1163+
match &assoc.args {
1164+
GenericArgs::AngleBracketed { args, bindings } => {
1165+
if !bindings.is_empty()
1166+
|| generics
1167+
.params
1168+
.iter()
1169+
.zip(args)
1170+
.any(|(param, arg)| !param_eq_arg(param, arg))
1171+
{
1172+
return false;
1173+
}
1174+
}
1175+
GenericArgs::Parenthesized { .. } => {
1176+
// The only time this happens is if we're inside the rustdoc for Fn(),
1177+
// which only has one associated type, which is not a GAT, so whatever.
1178+
}
1179+
}
1180+
true
11591181
}
1160-
match **self_type {
1161-
Generic(ref s) if *s == kw::SelfUpper => {}
1162-
_ => return None,
1182+
_ => false,
1183+
})
1184+
.flat_map(|pred| {
1185+
if let WherePredicate::BoundPredicate { bounds, .. } = pred {
1186+
bounds
1187+
} else {
1188+
unreachable!()
11631189
}
1164-
Some(bounds)
11651190
})
1166-
.flat_map(|i| i.iter().cloned())
11671191
.collect::<Vec<_>>();
11681192
// Our Sized/?Sized bound didn't get handled when creating the generics
11691193
// because we didn't actually get our whole set of bounds until just now
@@ -1183,7 +1207,7 @@ impl Clean<Item> for ty::AssocItem {
11831207
None
11841208
};
11851209

1186-
AssocTypeItem(bounds, ty.map(|t| t.clean(cx)))
1210+
AssocTypeItem(Box::new(generics), bounds, ty.map(|t| t.clean(cx)))
11871211
} else {
11881212
// FIXME: when could this happen? Associated items in inherent impls?
11891213
let type_ = tcx.type_of(self.def_id).clean(cx);

src/librustdoc/clean/types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ crate enum ItemKind {
683683
///
684684
/// The bounds may be non-empty if there is a `where` clause.
685685
/// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
686-
AssocTypeItem(Vec<GenericBound>, Option<Type>),
686+
AssocTypeItem(Box<Generics>, Vec<GenericBound>, Option<Type>),
687687
/// An item that has been stripped by a rustdoc pass
688688
StrippedItem(Box<ItemKind>),
689689
KeywordItem(Symbol),
@@ -721,7 +721,7 @@ impl ItemKind {
721721
| ProcMacroItem(_)
722722
| PrimitiveItem(_)
723723
| AssocConstItem(_, _)
724-
| AssocTypeItem(_, _)
724+
| AssocTypeItem(..)
725725
| StrippedItem(_)
726726
| KeywordItem(_) => [].iter(),
727727
}

src/librustdoc/fold.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ crate trait DocFolder: Sized {
8686
| ProcMacroItem(_)
8787
| PrimitiveItem(_)
8888
| AssocConstItem(_, _)
89-
| AssocTypeItem(_, _)
89+
| AssocTypeItem(..)
9090
| KeywordItem(_) => kind,
9191
}
9292
}

src/librustdoc/html/render/mod.rs

+39-18
Original file line numberDiff line numberDiff line change
@@ -773,22 +773,25 @@ fn assoc_const(
773773
fn assoc_type(
774774
w: &mut Buffer,
775775
it: &clean::Item,
776+
generics: &clean::Generics,
776777
bounds: &[clean::GenericBound],
777778
default: Option<&clean::Type>,
778779
link: AssocItemLink<'_>,
779-
extra: &str,
780+
indent: usize,
780781
cx: &Context<'_>,
781782
) {
782783
write!(
783784
w,
784-
"{}type <a href=\"{}\" class=\"associatedtype\">{}</a>",
785-
extra,
786-
naive_assoc_href(it, link, cx),
787-
it.name.as_ref().unwrap()
785+
"{indent}type <a href=\"{href}\" class=\"associatedtype\">{name}</a>{generics}",
786+
indent = " ".repeat(indent),
787+
href = naive_assoc_href(it, link, cx),
788+
name = it.name.as_ref().unwrap(),
789+
generics = generics.print(cx),
788790
);
789791
if !bounds.is_empty() {
790792
write!(w, ": {}", print_generic_bounds(bounds, cx))
791793
}
794+
write!(w, "{}", print_where_clause(generics, cx, indent, false));
792795
if let Some(default) = default {
793796
write!(w, " = {}", default.print(cx))
794797
}
@@ -812,11 +815,8 @@ fn assoc_method(
812815
AssocItemLink::GotoSource(did, provided_methods) => {
813816
// We're creating a link from an impl-item to the corresponding
814817
// trait-item and need to map the anchored type accordingly.
815-
let ty = if provided_methods.contains(name) {
816-
ItemType::Method
817-
} else {
818-
ItemType::TyMethod
819-
};
818+
let ty =
819+
if provided_methods.contains(name) { ItemType::Method } else { ItemType::TyMethod };
820820

821821
match (href(did.expect_def_id(), cx), ty) {
822822
(Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
@@ -974,13 +974,14 @@ fn render_assoc_item(
974974
clean::AssocConstItem(ref ty, _) => {
975975
assoc_const(w, item, ty, link, if parent == ItemType::Trait { " " } else { "" }, cx)
976976
}
977-
clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
977+
clean::AssocTypeItem(ref generics, ref bounds, ref default) => assoc_type(
978978
w,
979979
item,
980+
generics,
980981
bounds,
981982
default.as_ref(),
982983
link,
983-
if parent == ItemType::Trait { " " } else { "" },
984+
if parent == ItemType::Trait { 4 } else { 0 },
984985
cx,
985986
),
986987
_ => panic!("render_assoc_item called on non-associated-item"),
@@ -1284,7 +1285,16 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
12841285
let empty_set = FxHashSet::default();
12851286
let src_link =
12861287
AssocItemLink::GotoSource(trait_did.into(), &empty_set);
1287-
assoc_type(&mut out, it, &[], Some(&tydef.type_), src_link, "", cx);
1288+
assoc_type(
1289+
&mut out,
1290+
it,
1291+
&tydef.generics,
1292+
&[],
1293+
Some(&tydef.type_),
1294+
src_link,
1295+
0,
1296+
cx,
1297+
);
12881298
out.push_str(";</span>");
12891299
}
12901300
}
@@ -1463,10 +1473,11 @@ fn render_impl(
14631473
assoc_type(
14641474
w,
14651475
item,
1466-
&Vec::new(),
1476+
&tydef.generics,
1477+
&[],
14671478
Some(&tydef.type_),
14681479
link.anchor(if trait_.is_some() { &source_id } else { &id }),
1469-
"",
1480+
0,
14701481
cx,
14711482
);
14721483
w.write_str("</h4>");
@@ -1494,7 +1505,7 @@ fn render_impl(
14941505
w.write_str("</h4>");
14951506
w.write_str("</section>");
14961507
}
1497-
clean::AssocTypeItem(ref bounds, ref default) => {
1508+
clean::AssocTypeItem(ref generics, ref bounds, ref default) => {
14981509
let source_id = format!("{}.{}", item_type, name);
14991510
let id = cx.derive_id(source_id.clone());
15001511
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
@@ -1503,10 +1514,11 @@ fn render_impl(
15031514
assoc_type(
15041515
w,
15051516
item,
1517+
generics,
15061518
bounds,
15071519
default.as_ref(),
15081520
link.anchor(if trait_.is_some() { &source_id } else { &id }),
1509-
"",
1521+
0,
15101522
cx,
15111523
);
15121524
w.write_str("</h4>");
@@ -1727,7 +1739,16 @@ pub(crate) fn render_impl_summary(
17271739
for it in &i.inner_impl().items {
17281740
if let clean::TypedefItem(ref tydef, _) = *it.kind {
17291741
w.write_str("<span class=\"where fmt-newline\"> ");
1730-
assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
1742+
assoc_type(
1743+
w,
1744+
it,
1745+
&tydef.generics,
1746+
&[],
1747+
Some(&tydef.type_),
1748+
AssocItemLink::Anchor(None),
1749+
0,
1750+
cx,
1751+
);
17311752
w.write_str(";</span>");
17321753
}
17331754
}

src/librustdoc/json/conversions.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
222222
AssocConstItem(ty, default) => {
223223
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) }
224224
}
225-
AssocTypeItem(g, t) => ItemEnum::AssocType {
226-
bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(),
225+
AssocTypeItem(g, b, t) => ItemEnum::AssocType {
226+
generics: (*g).into_tcx(tcx),
227+
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
227228
default: t.map(|x| x.into_tcx(tcx)),
228229
},
229230
// `convert_item` early returns `None` for striped items

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#![feature(box_patterns)]
1010
#![feature(control_flow_enum)]
1111
#![feature(box_syntax)]
12+
#![feature(drain_filter)]
1213
#![feature(let_else)]
1314
#![feature(nll)]
1415
#![feature(test)]

src/librustdoc/passes/check_doc_test_visibility.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo
6262
clean::StructFieldItem(_)
6363
| clean::VariantItem(_)
6464
| clean::AssocConstItem(_, _)
65-
| clean::AssocTypeItem(_, _)
65+
| clean::AssocTypeItem(..)
6666
| clean::TypedefItem(_, _)
6767
| clean::StaticItem(_)
6868
| clean::ConstantItem(_)

src/librustdoc/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ crate trait DocVisitor: Sized {
4141
| ProcMacroItem(_)
4242
| PrimitiveItem(_)
4343
| AssocConstItem(_, _)
44-
| AssocTypeItem(_, _)
44+
| AssocTypeItem(..)
4545
| KeywordItem(_) => {}
4646
}
4747
}

src/rustdoc-json-types/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ pub enum ItemEnum {
233233
default: Option<String>,
234234
},
235235
AssocType {
236+
/// generics and `where` clause
237+
generics: Generics,
238+
/// e.g. `: Sized`
236239
bounds: Vec<GenericBound>,
237240
/// e.g. `type X = usize;`
238241
default: Option<Type>,

0 commit comments

Comments
 (0)