Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: render bounds of cross-crate GAT params #103190

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1201,21 +1201,19 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
}

if let ty::TraitContainer = assoc_item.container {
// FIXME(fmease): `tcx.explicit_item_bounds` does not contain the bounds of GATs,
// e.g. the bounds `Copy`, `Display` & (implicitly) `Sized` in
// `type Assoc<T: Copy> where T: Display`. This also means that we
// later incorrectly render `where T: ?Sized`.
//
// The result of `tcx.explicit_predicates_of` *does* contain them but
// it does not contain the other bounds / predicates we need.
// Either merge those two interned lists somehow or refactor
// `clean_ty_generics` to call `explicit_item_bounds` by itself.
let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
let mut generics =
clean_ty_generics(cx, tcx.generics_of(assoc_item.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 predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
let predicates =
tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to manually merge the result of tcx.explicit_item_bounds and tcx.explicit_predicates_of even though there is a query that already does both, namely tcx.trait_explicit_predicates_and_bounds. However, the latter only works for local definitions (and therefore only accepts LocalDefIds) and we obviously need to be able to handle cross-crate definitions.

let mut generics = clean_ty_generics(
cx,
tcx.generics_of(assoc_item.def_id),
ty::GenericPredicates { parent: None, predicates },
);
// Move bounds that are (likely) directly attached to the associated type
// from the where clause to the associated type.
// There is no guarantee that this is what the user actually wrote but we have
// no way of knowing.
let mut bounds = generics
.where_predicates
.drain_filter(|pred| match *pred {
Expand Down Expand Up @@ -1273,6 +1271,24 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
}
None => bounds.push(GenericBound::maybe_sized(cx)),
}
// Move bounds that are (likely) directly attached to the parameters of the
// (generic) associated type from the where clause to the respective parameter.
// There is no guarantee that this is what the user actually wrote but we have
// no way of knowing.
let mut where_predicates = Vec::new();
for mut pred in generics.where_predicates {
if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
&& let Some(GenericParamDef {
kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
..
}) = generics.params.iter_mut().find(|param| &param.name == arg)
{
param_bounds.extend(mem::take(bounds));
} else {
where_predicates.push(pred);
}
}
generics.where_predicates = where_predicates;

if tcx.impl_defaultness(assoc_item.def_id).has_value() {
AssocTypeItem(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h4 class="code-header">type <a href="#associatedtype.Out0" class="associatedtype">Out0</a>: <a class="trait" href="../assoc_item_trait_bounds/trait.Support.html" title="trait assoc_item_trait_bounds::Support">Support</a>&lt;Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>&gt;</h4>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h4 class="code-header">type <a href="#associatedtype.Out2" class="associatedtype">Out2</a>&lt;T&gt;: <a class="trait" href="../assoc_item_trait_bounds/trait.Support.html" title="trait assoc_item_trait_bounds::Support">Support</a>&lt;Item = T&gt;</h4>
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
// Regression test for issues #77763, #84579 and #102142.
#![crate_name = "main"]

// aux-build:assoc_item_trait_bounds_with_bindings.rs
// aux-build:assoc_item_trait_bounds.rs
// build-aux-docs
// ignore-cross-compile
extern crate assoc_item_trait_bounds_with_bindings as aux;

// FIXME(fmease): Don't render an incorrect `T: ?Sized` where-clause for parameters
// of GATs like `Main::Out{2,4}`. Add a snapshot test once it's fixed.
extern crate assoc_item_trait_bounds as aux;

// @has main/trait.Main.html
// @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support<Item = ()>'
Expand All @@ -24,11 +21,15 @@ extern crate assoc_item_trait_bounds_with_bindings as aux;
// @has - '//*[@id="associatedtype.Out11"]' "type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>"
// @has - '//*[@id="associatedtype.Out12"]' "type Out12: for<'w> Helper<B<'w> = Cow<'w, str>, A<'w> = bool>"
// @has - '//*[@id="associatedtype.Out13"]' "type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>"
// @has - '//*[@id="associatedtype.Out14"]' "type Out14<P: Copy + Eq, Q: ?Sized>"
//
// Snapshots: Check that we do not render any where-clauses for those associated types since all of
// the trait bounds contained within were moved to the bounds of the respective item.
// Snapshots:
// Check that we don't render any where-clauses for the following associated types since
// all corresponding projection equality predicates should have already been re-sugared
// to associated type bindings:
//
// @snapshot out0 - '//*[@id="associatedtype.Out0"]/*[@class="code-header"]'
// @snapshot out2 - '//*[@id="associatedtype.Out2"]/*[@class="code-header"]'
// @snapshot out9 - '//*[@id="associatedtype.Out9"]/*[@class="code-header"]'
//
// @has - '//*[@id="tymethod.make"]' \
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub trait Main {
type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>;
type Out12: for<'w> Helper<B<'w> = std::borrow::Cow<'w, str>, A<'w> = bool>;
type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>;
type Out14<P: Copy + Eq, Q: ?Sized>;

fn make<F>(_: F, _: impl FnMut(&str) -> bool)
where
Expand Down