diff options
| author | León Orell Valerian Liehr <liehr.exchange@gmx.net> | 2022-09-28 22:54:39 +0200 |
|---|---|---|
| committer | León Orell Valerian Liehr <liehr.exchange@gmx.net> | 2022-10-03 04:36:39 +0200 |
| commit | a5402343f60271c7e428bb6e6aac704bd88bb2bf (patch) | |
| tree | dae2c78e0e784bf6130ac7dd8a5c06027e5d025c | |
| parent | ff40f2ec95923c4d45366e85bcff17d75df68d68 (diff) | |
| download | rust-a5402343f60271c7e428bb6e6aac704bd88bb2bf.tar.gz rust-a5402343f60271c7e428bb6e6aac704bd88bb2bf.zip | |
rustdoc: re-sugar more cross-crate trait bounds
6 files changed, 107 insertions, 23 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bd68dffb823..dc17865d163 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1176,6 +1176,15 @@ 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 = diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index af7813a7740..f82ea8969ab 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -14,7 +14,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_middle::ty; -use rustc_span::Symbol; use crate::clean; use crate::clean::GenericArgs as PP; @@ -26,21 +25,17 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> { // // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to // the order of the generated bounds. - let mut params: FxIndexMap<Symbol, (Vec<_>, Vec<_>)> = FxIndexMap::default(); + let mut tybounds = FxIndexMap::default(); let mut lifetimes = Vec::new(); let mut equalities = Vec::new(); - let mut tybounds = Vec::new(); for clause in clauses { match clause { - WP::BoundPredicate { ty, bounds, bound_params } => match ty { - clean::Generic(s) => { - let (b, p) = params.entry(s).or_default(); - b.extend(bounds); - p.extend(bound_params); - } - t => tybounds.push((t, (bounds, bound_params))), - }, + WP::BoundPredicate { ty, bounds, bound_params } => { + let (b, p): &mut (Vec<_>, Vec<_>) = tybounds.entry(ty).or_default(); + b.extend(bounds); + p.extend(bound_params); + } WP::RegionPredicate { lifetime, bounds } => { lifetimes.push((lifetime, bounds)); } @@ -49,14 +44,17 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> { } // Look for equality predicates on associated types that can be merged into - // general bound predicates + // general bound predicates. equalities.retain(|&(ref lhs, ref rhs)| { - let Some((self_, trait_did, name)) = lhs.projection() else { - return true; - }; - let clean::Generic(generic) = self_ else { return true }; - let Some((bounds, _)) = params.get_mut(generic) else { return true }; - + let Some((ty, trait_did, name)) = lhs.projection() else { return true; }; + // FIXME(fmease): We don't handle HRTBs correctly here. + // Pass `_bound_params` (higher-rank lifetimes) to a modified version of + // `merge_bounds`. That vector is currently always empty though since we + // don't keep track of late-bound lifetimes when cleaning projection + // predicates to cleaned equality predicates while we should first query + // them with `collect_referenced_late_bound_regions` and then store them + // (or something similar). For prior art, see `clean::auto_trait`. + let Some((bounds, _bound_params)) = tybounds.get_mut(ty) else { return true }; merge_bounds(cx, bounds, trait_did, name, rhs) }); @@ -65,11 +63,6 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> { clauses.extend( lifetimes.into_iter().map(|(lt, bounds)| WP::RegionPredicate { lifetime: lt, bounds }), ); - clauses.extend(params.into_iter().map(|(k, (bounds, params))| WP::BoundPredicate { - ty: clean::Generic(k), - bounds, - bound_params: params, - })); clauses.extend(tybounds.into_iter().map(|(ty, (bounds, bound_params))| WP::BoundPredicate { ty, bounds, diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html new file mode 100644 index 00000000000..927a1a42a1f --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html @@ -0,0 +1 @@ +<h4 class="code-header">type <a href="#associatedtype.Out0" class="associatedtype">Out0</a>: <a class="trait" href="../assoc_item_trait_bounds_with_bindings/trait.Support.html" title="trait assoc_item_trait_bounds_with_bindings::Support">Support</a><Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>></h4> \ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html new file mode 100644 index 00000000000..69d84e1b2c1 --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html @@ -0,0 +1 @@ +<h4 class="code-header">type <a href="#associatedtype.Out9" class="associatedtype">Out9</a>: <a class="trait" href="{{channel}}/core/ops/function/trait.FnMut.html" title="trait core::ops::function::FnMut">FnMut</a>(<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>) -> <a class="primitive" href="{{channel}}/std/primitive.bool.html">bool</a> + <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a></h4> \ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs new file mode 100644 index 00000000000..b026f399a56 --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs @@ -0,0 +1,40 @@ +// Regression test for issues #77763, #84579 and #102142. +#![crate_name = "main"] + +// aux-build:assoc_item_trait_bounds_with_bindings.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. +// FIXME(fmease): Print the `for<>` parameter list in the bounds of +// `Main::Out{6,11,12}`. + +// @has main/trait.Main.html +// @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support<Item = ()>' +// @has - '//*[@id="associatedtype.Out1"]' 'type Out1: Support<Item = Self::Item>' +// @has - '//*[@id="associatedtype.Out2"]' 'type Out2<T>: Support<Item = T>' +// @has - '//*[@id="associatedtype.Out3"]' 'type Out3: Support<Produce<()> = bool>' +// @has - '//*[@id="associatedtype.Out4"]' 'type Out4<T>: Support<Produce<T> = T>' +// @has - '//*[@id="associatedtype.Out5"]' "type Out5: Support<Output<'static> = &'static ()>" +// @has - '//*[@id="associatedtype.Out6"]' "type Out6: Support<Output<'a> = &'a ()>" +// @has - '//*[@id="associatedtype.Out7"]' "type Out7: Support<Item = String, Produce<i32> = u32> + Unrelated" +// @has - '//*[@id="associatedtype.Out8"]' "type Out8: Unrelated + Protocol<i16, Q1 = u128, Q0 = ()>" +// @has - '//*[@id="associatedtype.Out9"]' "type Out9: FnMut(i32) -> bool + Clone" +// @has - '//*[@id="associatedtype.Out10"]' "type Out10<'q>: Support<Output<'q> = ()>" +// @has - '//*[@id="associatedtype.Out11"]' "type Out11: Helper<A<'s> = &'s (), B<'r> = ()>" +// @has - '//*[@id="associatedtype.Out12"]' "type Out12: Helper<B<'w> = Cow<'w, str>, A<'w> = bool>" +// +// 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. +// +// @snapshot out0 - '//*[@id="associatedtype.Out0"]/*[@class="code-header"]' +// @snapshot out9 - '//*[@id="associatedtype.Out9"]/*[@class="code-header"]' +// +// @has - '//*[@id="tymethod.make"]' \ +// "fn make<F>(F, impl FnMut(&str) -> bool)\ +// where \ +// F: FnOnce(u32) -> String, \ +// Self::Out2<()>: Protocol<u8, Q0 = Self::Item, Q1 = ()>" +pub use aux::Main; diff --git a/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs new file mode 100644 index 00000000000..7225f2dca10 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs @@ -0,0 +1,40 @@ +pub trait Main { + type Item; + + type Out0: Support<Item = ()>; + type Out1: Support<Item = Self::Item>; + type Out2<T>: Support<Item = T>; + type Out3: Support<Produce<()> = bool>; + type Out4<T>: Support<Produce<T> = T>; + type Out5: Support<Output<'static> = &'static ()>; + type Out6: for<'a> Support<Output<'a> = &'a ()>; + type Out7: Support<Item = String, Produce<i32> = u32> + Unrelated; + type Out8: Unrelated + Protocol<i16, Q1 = u128, Q0 = ()>; + type Out9: FnMut(i32) -> bool + Clone; + type Out10<'q>: Support<Output<'q> = ()>; + 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>; + + fn make<F>(_: F, _: impl FnMut(&str) -> bool) + where + F: FnOnce(u32) -> String, + Self::Out2<()>: Protocol<u8, Q0 = Self::Item, Q1 = ()>; +} + +pub trait Support { + type Item; + type Output<'a>; + type Produce<T>; +} + +pub trait Protocol<K> { + type Q0; + type Q1; +} + +pub trait Unrelated {} + +pub trait Helper { + type A<'q>; + type B<'q>; +} |
