1
Fork 0

make GATs print properly in traits

This commit is contained in:
Michael Goulet 2022-02-14 18:14:38 -08:00
parent 8a0c2c4e83
commit ca6e06efba
9 changed files with 99 additions and 49 deletions

View file

@ -985,9 +985,10 @@ impl Clean<Item> for hir::TraitItem<'_> {
TyMethodItem(t) TyMethodItem(t)
} }
hir::TraitItemKind::Type(bounds, ref default) => { hir::TraitItemKind::Type(bounds, ref default) => {
let generics = self.generics.clean(cx);
let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
let default = default.map(|t| t.clean(cx)); let default = default.map(|t| t.clean(cx));
AssocTypeItem(bounds, default) AssocTypeItem(Box::new(generics), bounds, default)
} }
}; };
let what_rustc_thinks = let what_rustc_thinks =
@ -1138,32 +1139,55 @@ impl Clean<Item> for ty::AssocItem {
if let ty::TraitContainer(_) = self.container { if let ty::TraitContainer(_) = self.container {
let bounds = tcx.explicit_item_bounds(self.def_id); let bounds = tcx.explicit_item_bounds(self.def_id);
let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; 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 let mut bounds = generics
.where_predicates .where_predicates
.iter() .drain_filter(|pred| match *pred {
.filter_map(|pred| { WherePredicate::BoundPredicate {
let (name, self_type, trait_, bounds) = match *pred { ty: QPath { name, ref self_type, ref trait_, .. },
WherePredicate::BoundPredicate { ..
ty: QPath { ref name, ref self_type, ref trait_, .. }, } => {
ref bounds, if name != my_name {
.. return false;
} => (name, self_type, trait_, bounds), }
_ => return None, if trait_.def_id() != self.container.id() {
}; return false;
if *name != my_name { }
return None; 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
}
_ => false,
})
.flat_map(|pred| {
if let WherePredicate::BoundPredicate { bounds, .. } = pred {
bounds
} else {
unreachable!()
} }
if trait_.def_id() != self.container.id() {
return None;
}
match **self_type {
Generic(ref s) if *s == kw::SelfUpper => {}
_ => return None,
}
Some(bounds)
}) })
.flat_map(|i| i.iter().cloned())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Our Sized/?Sized bound didn't get handled when creating the generics // 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 // 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 None
}; };
AssocTypeItem(bounds, ty.map(|t| t.clean(cx))) AssocTypeItem(Box::new(generics), bounds, ty.map(|t| t.clean(cx)))
} else { } else {
// FIXME: when could this happen? Associated items in inherent impls? // FIXME: when could this happen? Associated items in inherent impls?
let type_ = tcx.type_of(self.def_id).clean(cx); let type_ = tcx.type_of(self.def_id).clean(cx);

View file

@ -683,7 +683,7 @@ crate enum ItemKind {
/// ///
/// The bounds may be non-empty if there is a `where` clause. /// 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; }`) /// 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 /// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemKind>), StrippedItem(Box<ItemKind>),
KeywordItem(Symbol), KeywordItem(Symbol),
@ -721,7 +721,7 @@ impl ItemKind {
| ProcMacroItem(_) | ProcMacroItem(_)
| PrimitiveItem(_) | PrimitiveItem(_)
| AssocConstItem(_, _) | AssocConstItem(_, _)
| AssocTypeItem(_, _) | AssocTypeItem(..)
| StrippedItem(_) | StrippedItem(_)
| KeywordItem(_) => [].iter(), | KeywordItem(_) => [].iter(),
} }

View file

@ -86,7 +86,7 @@ crate trait DocFolder: Sized {
| ProcMacroItem(_) | ProcMacroItem(_)
| PrimitiveItem(_) | PrimitiveItem(_)
| AssocConstItem(_, _) | AssocConstItem(_, _)
| AssocTypeItem(_, _) | AssocTypeItem(..)
| KeywordItem(_) => kind, | KeywordItem(_) => kind,
} }
} }

View file

@ -773,22 +773,25 @@ fn assoc_const(
fn assoc_type( fn assoc_type(
w: &mut Buffer, w: &mut Buffer,
it: &clean::Item, it: &clean::Item,
generics: &clean::Generics,
bounds: &[clean::GenericBound], bounds: &[clean::GenericBound],
default: Option<&clean::Type>, default: Option<&clean::Type>,
link: AssocItemLink<'_>, link: AssocItemLink<'_>,
extra: &str, indent: usize,
cx: &Context<'_>, cx: &Context<'_>,
) { ) {
write!( write!(
w, w,
"{}type <a href=\"{}\" class=\"associatedtype\">{}</a>", "{indent}type <a href=\"{href}\" class=\"associatedtype\">{name}</a>{generics}",
extra, indent = " ".repeat(indent),
naive_assoc_href(it, link, cx), href = naive_assoc_href(it, link, cx),
it.name.as_ref().unwrap() name = it.name.as_ref().unwrap(),
generics = generics.print(cx),
); );
if !bounds.is_empty() { if !bounds.is_empty() {
write!(w, ": {}", print_generic_bounds(bounds, cx)) write!(w, ": {}", print_generic_bounds(bounds, cx))
} }
write!(w, "{}", print_where_clause(generics, cx, indent, false));
if let Some(default) = default { if let Some(default) = default {
write!(w, " = {}", default.print(cx)) write!(w, " = {}", default.print(cx))
} }
@ -812,11 +815,8 @@ fn assoc_method(
AssocItemLink::GotoSource(did, provided_methods) => { AssocItemLink::GotoSource(did, provided_methods) => {
// We're creating a link from an impl-item to the corresponding // We're creating a link from an impl-item to the corresponding
// trait-item and need to map the anchored type accordingly. // trait-item and need to map the anchored type accordingly.
let ty = if provided_methods.contains(name) { let ty =
ItemType::Method if provided_methods.contains(name) { ItemType::Method } else { ItemType::TyMethod };
} else {
ItemType::TyMethod
};
match (href(did.expect_def_id(), cx), ty) { match (href(did.expect_def_id(), cx), ty) {
(Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)), (Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
@ -974,13 +974,14 @@ fn render_assoc_item(
clean::AssocConstItem(ref ty, _) => { clean::AssocConstItem(ref ty, _) => {
assoc_const(w, item, ty, link, if parent == ItemType::Trait { " " } else { "" }, cx) 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, w,
item, item,
generics,
bounds, bounds,
default.as_ref(), default.as_ref(),
link, link,
if parent == ItemType::Trait { " " } else { "" }, if parent == ItemType::Trait { 4 } else { 0 },
cx, cx,
), ),
_ => panic!("render_assoc_item called on non-associated-item"), _ => 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 empty_set = FxHashSet::default();
let src_link = let src_link =
AssocItemLink::GotoSource(trait_did.into(), &empty_set); 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>"); out.push_str(";</span>");
} }
} }
@ -1463,10 +1473,11 @@ fn render_impl(
assoc_type( assoc_type(
w, w,
item, item,
&Vec::new(), &tydef.generics,
&[],
Some(&tydef.type_), Some(&tydef.type_),
link.anchor(if trait_.is_some() { &source_id } else { &id }), link.anchor(if trait_.is_some() { &source_id } else { &id }),
"", 0,
cx, cx,
); );
w.write_str("</h4>"); w.write_str("</h4>");
@ -1494,7 +1505,7 @@ fn render_impl(
w.write_str("</h4>"); w.write_str("</h4>");
w.write_str("</section>"); 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 source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone()); let id = cx.derive_id(source_id.clone());
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,); write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
@ -1503,10 +1514,11 @@ fn render_impl(
assoc_type( assoc_type(
w, w,
item, item,
generics,
bounds, bounds,
default.as_ref(), default.as_ref(),
link.anchor(if trait_.is_some() { &source_id } else { &id }), link.anchor(if trait_.is_some() { &source_id } else { &id }),
"", 0,
cx, cx,
); );
w.write_str("</h4>"); w.write_str("</h4>");
@ -1727,7 +1739,16 @@ pub(crate) fn render_impl_summary(
for it in &i.inner_impl().items { for it in &i.inner_impl().items {
if let clean::TypedefItem(ref tydef, _) = *it.kind { if let clean::TypedefItem(ref tydef, _) = *it.kind {
w.write_str("<span class=\"where fmt-newline\"> "); 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>"); w.write_str(";</span>");
} }
} }

View file

@ -222,8 +222,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
AssocConstItem(ty, default) => { AssocConstItem(ty, default) => {
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) } ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) }
} }
AssocTypeItem(g, t) => ItemEnum::AssocType { AssocTypeItem(g, b, t) => ItemEnum::AssocType {
bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(), generics: (*g).into_tcx(tcx),
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
default: t.map(|x| x.into_tcx(tcx)), default: t.map(|x| x.into_tcx(tcx)),
}, },
// `convert_item` early returns `None` for striped items // `convert_item` early returns `None` for striped items

View file

@ -9,6 +9,7 @@
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(control_flow_enum)] #![feature(control_flow_enum)]
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(drain_filter)]
#![feature(let_else)] #![feature(let_else)]
#![feature(nll)] #![feature(nll)]
#![feature(test)] #![feature(test)]

View file

@ -62,7 +62,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo
clean::StructFieldItem(_) clean::StructFieldItem(_)
| clean::VariantItem(_) | clean::VariantItem(_)
| clean::AssocConstItem(_, _) | clean::AssocConstItem(_, _)
| clean::AssocTypeItem(_, _) | clean::AssocTypeItem(..)
| clean::TypedefItem(_, _) | clean::TypedefItem(_, _)
| clean::StaticItem(_) | clean::StaticItem(_)
| clean::ConstantItem(_) | clean::ConstantItem(_)

View file

@ -41,7 +41,7 @@ crate trait DocVisitor: Sized {
| ProcMacroItem(_) | ProcMacroItem(_)
| PrimitiveItem(_) | PrimitiveItem(_)
| AssocConstItem(_, _) | AssocConstItem(_, _)
| AssocTypeItem(_, _) | AssocTypeItem(..)
| KeywordItem(_) => {} | KeywordItem(_) => {}
} }
} }

View file

@ -233,6 +233,9 @@ pub enum ItemEnum {
default: Option<String>, default: Option<String>,
}, },
AssocType { AssocType {
/// generics and `where` clause
generics: Generics,
/// e.g. `: Sized`
bounds: Vec<GenericBound>, bounds: Vec<GenericBound>,
/// e.g. `type X = usize;` /// e.g. `type X = usize;`
default: Option<Type>, default: Option<Type>,