Auto merge of #105183 - GuillaumeGomez:merge-and-dedup-predicates, r=notriddle
Merge generics and where predicates and prevent duplicates in where predicates Part of #104886 (I didn't include bounds from parent trait yet as I think the PR is already big enough). Also we'll need to run a perf check. cc `@fmease` since you worked a bit on this. r? `@notriddle`
This commit is contained in:
commit
4bb15759d7
7 changed files with 119 additions and 41 deletions
|
@ -12,7 +12,7 @@ pub(crate) mod utils;
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
|
@ -598,47 +598,105 @@ pub(crate) fn clean_generics<'tcx>(
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut params = ThinVec::with_capacity(gens.params.len());
|
||||
for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
|
||||
let p = clean_generic_param(cx, Some(gens), p);
|
||||
params.push(p);
|
||||
}
|
||||
params.extend(impl_trait_params);
|
||||
|
||||
let mut generics = Generics {
|
||||
params,
|
||||
where_predicates: gens
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|x| clean_where_predicate(x, cx))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
// Some duplicates are generated for ?Sized bounds between type params and where
|
||||
// predicates. The point in here is to move the bounds definitions from type params
|
||||
// to where predicates when such cases occur.
|
||||
for where_pred in &mut generics.where_predicates {
|
||||
match *where_pred {
|
||||
WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => {
|
||||
if bounds.is_empty() {
|
||||
for param in &mut generics.params {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime { .. } => {}
|
||||
GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
|
||||
if ¶m.name == name {
|
||||
mem::swap(bounds, ty_bounds);
|
||||
break;
|
||||
}
|
||||
let mut bound_predicates = FxIndexMap::default();
|
||||
let mut region_predicates = FxIndexMap::default();
|
||||
let mut eq_predicates = ThinVec::default();
|
||||
for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) {
|
||||
match pred {
|
||||
WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
|
||||
match bound_predicates.entry(ty) {
|
||||
IndexEntry::Vacant(v) => {
|
||||
v.insert((bounds, bound_params));
|
||||
}
|
||||
IndexEntry::Occupied(mut o) => {
|
||||
// we merge both bounds.
|
||||
for bound in bounds {
|
||||
if !o.get().0.contains(&bound) {
|
||||
o.get_mut().0.push(bound);
|
||||
}
|
||||
}
|
||||
for bound_param in bound_params {
|
||||
if !o.get().1.contains(&bound_param) {
|
||||
o.get_mut().1.push(bound_param);
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
WherePredicate::RegionPredicate { lifetime, bounds } => {
|
||||
match region_predicates.entry(lifetime) {
|
||||
IndexEntry::Vacant(v) => {
|
||||
v.insert(bounds);
|
||||
}
|
||||
IndexEntry::Occupied(mut o) => {
|
||||
// we merge both bounds.
|
||||
for bound in bounds {
|
||||
if !o.get().contains(&bound) {
|
||||
o.get_mut().push(bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
|
||||
eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs, bound_params });
|
||||
}
|
||||
}
|
||||
}
|
||||
generics
|
||||
|
||||
let mut params = ThinVec::with_capacity(gens.params.len());
|
||||
// In this loop, we gather the generic parameters (`<'a, B: 'a>`) and check if they have
|
||||
// bounds in the where predicates. If so, we move their bounds into the where predicates
|
||||
// while also preventing duplicates.
|
||||
for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
|
||||
let mut p = clean_generic_param(cx, Some(gens), p);
|
||||
match &mut p.kind {
|
||||
GenericParamDefKind::Lifetime { ref mut outlives } => {
|
||||
if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) {
|
||||
// We merge bounds in the `where` clause.
|
||||
for outlive in outlives.drain(..) {
|
||||
let outlive = GenericBound::Outlives(outlive);
|
||||
if !region_pred.contains(&outlive) {
|
||||
region_pred.push(outlive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Type { bounds, synthetic: false, .. } => {
|
||||
if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) {
|
||||
// We merge bounds in the `where` clause.
|
||||
for bound in bounds.drain(..) {
|
||||
if !bound_pred.0.contains(&bound) {
|
||||
bound_pred.0.push(bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
// nothing to do here.
|
||||
}
|
||||
}
|
||||
params.push(p);
|
||||
}
|
||||
params.extend(impl_trait_params);
|
||||
|
||||
Generics {
|
||||
params,
|
||||
where_predicates: bound_predicates
|
||||
.into_iter()
|
||||
.map(|(ty, (bounds, bound_params))| WherePredicate::BoundPredicate {
|
||||
ty,
|
||||
bounds,
|
||||
bound_params,
|
||||
})
|
||||
.chain(
|
||||
region_predicates
|
||||
.into_iter()
|
||||
.map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }),
|
||||
)
|
||||
.chain(eq_predicates.into_iter())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_ty_generics<'tcx>(
|
||||
|
|
20
src/test/rustdoc/bounds-in-multiple-parts.rs
Normal file
20
src/test/rustdoc/bounds-in-multiple-parts.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
#![crate_name = "foo"]
|
||||
|
||||
pub trait Eq {}
|
||||
pub trait Eq2 {}
|
||||
|
||||
// Checking that "where predicates" and "generics params" are merged.
|
||||
// @has 'foo/trait.T.html'
|
||||
// @has - "//*[@id='tymethod.f']/h4" "fn f<'a, 'b, 'c, T>()where Self: Eq, T: Eq + 'a, 'c: 'b + 'a,"
|
||||
pub trait T {
|
||||
fn f<'a, 'b, 'c: 'a, T: Eq + 'a>()
|
||||
where Self: Eq, Self: Eq, T: Eq, 'c: 'b;
|
||||
}
|
||||
|
||||
// Checking that a duplicated "where predicate" is removed.
|
||||
// @has 'foo/trait.T2.html'
|
||||
// @has - "//*[@id='tymethod.f']/h4" "fn f<T>()where Self: Eq + Eq2, T: Eq2 + Eq,"
|
||||
pub trait T2 {
|
||||
fn f<T: Eq>()
|
||||
where Self: Eq, Self: Eq2, T: Eq2;
|
||||
}
|
|
@ -6,7 +6,7 @@ pub auto trait AnAutoTrait {}
|
|||
pub struct Foo<T> { field: T }
|
||||
|
||||
// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \
|
||||
// "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
|
||||
// "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
|
||||
// @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \
|
||||
// "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
|
||||
// "impl<T> !AnAutoTrait for Foo<T>where T: Sync + Clone,"
|
||||
impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
|
||||
|
|
|
@ -61,7 +61,7 @@ impl<T> S<T> {
|
|||
// @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
|
||||
// @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
|
||||
// @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
|
||||
pub const fn foo<B: ~const Clone + ~const Destruct>()
|
||||
pub const fn foo<B, C: ~const Clone + ~const Destruct>()
|
||||
where
|
||||
B: ~const Clone + ~const Destruct,
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="item-decl"><pre class="rust enum"><code>pub enum Cow<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>,</span>{
|
||||
<div class="item-decl"><pre class="rust enum"><code>pub enum Cow<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
|
||||
Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B),
|
||||
Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
|
||||
}</code></pre></div>
|
|
@ -1,4 +1,4 @@
|
|||
<div class="item-decl"><pre class="rust struct"><code>pub struct Struct<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>,</span>{
|
||||
<div class="item-decl"><pre class="rust struct"><code>pub struct Struct<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
|
||||
pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B,
|
||||
pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
|
||||
}</code></pre></div>
|
|
@ -1,3 +1,3 @@
|
|||
<div class="item-decl"><pre class="rust union"><code>pub union Union<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>,</span>{
|
||||
<div class="item-decl"><pre class="rust union"><code>pub union Union<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
|
||||
/* private fields */
|
||||
}</code></pre></div>
|
Loading…
Add table
Add a link
Reference in a new issue