Skip to content

Commit af45040

Browse files
Merge generics and where predicates and prevent duplicates in where predicates
1 parent 11663b1 commit af45040

File tree

1 file changed

+91
-33
lines changed

1 file changed

+91
-33
lines changed

src/librustdoc/clean/mod.rs

+91-33
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub(crate) mod utils;
1212

1313
use rustc_ast as ast;
1414
use rustc_attr as attr;
15-
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
15+
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
1616
use rustc_hir as hir;
1717
use rustc_hir::def::{CtorKind, DefKind, Res};
1818
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@@ -598,47 +598,105 @@ pub(crate) fn clean_generics<'tcx>(
598598
})
599599
.collect::<Vec<_>>();
600600

601+
let mut bound_predicates = FxIndexMap::default();
602+
let mut region_predicates = FxIndexMap::default();
603+
let mut eq_predicates = ThinVec::default();
604+
for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) {
605+
match pred {
606+
WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
607+
match bound_predicates.entry(ty) {
608+
IndexEntry::Vacant(v) => {
609+
v.insert((bounds, bound_params));
610+
}
611+
IndexEntry::Occupied(mut o) => {
612+
// we merge both bounds.
613+
for bound in bounds {
614+
if !o.get().0.contains(&bound) {
615+
o.get_mut().0.push(bound);
616+
}
617+
}
618+
for bound_param in bound_params {
619+
if !o.get().1.contains(&bound_param) {
620+
o.get_mut().1.push(bound_param);
621+
}
622+
}
623+
}
624+
}
625+
}
626+
WherePredicate::RegionPredicate { lifetime, bounds } => {
627+
match region_predicates.entry(lifetime) {
628+
IndexEntry::Vacant(v) => {
629+
v.insert(bounds);
630+
}
631+
IndexEntry::Occupied(mut o) => {
632+
// we merge both bounds.
633+
for bound in bounds {
634+
if !o.get().contains(&bound) {
635+
o.get_mut().push(bound);
636+
}
637+
}
638+
}
639+
}
640+
}
641+
WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
642+
eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs, bound_params });
643+
}
644+
}
645+
}
646+
601647
let mut params = ThinVec::with_capacity(gens.params.len());
648+
// In this loop, we gather the generic parameters (`<'a, B: 'a>`) and check if they have
649+
// bounds in the where predicates. If so, we move their bounds into the where predicates
650+
// while also preventing duplicates.
602651
for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
603-
let p = clean_generic_param(cx, Some(gens), p);
652+
let mut p = clean_generic_param(cx, Some(gens), p);
653+
match &mut p.kind {
654+
GenericParamDefKind::Lifetime { ref mut outlives } => {
655+
if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) {
656+
// We merge bounds in the `where` clause.
657+
for outlive in outlives.drain(..) {
658+
let outlive = GenericBound::Outlives(outlive);
659+
if !region_pred.contains(&outlive) {
660+
region_pred.push(outlive);
661+
}
662+
}
663+
}
664+
}
665+
GenericParamDefKind::Type { bounds, synthetic: false, .. } => {
666+
if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) {
667+
// We merge bounds in the `where` clause.
668+
for bound in bounds.drain(..) {
669+
if !bound_pred.0.contains(&bound) {
670+
bound_pred.0.push(bound);
671+
}
672+
}
673+
}
674+
}
675+
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
676+
// nothing to do here.
677+
}
678+
}
604679
params.push(p);
605680
}
606681
params.extend(impl_trait_params);
607682

608-
let mut generics = Generics {
683+
Generics {
609684
params,
610-
where_predicates: gens
611-
.predicates
612-
.iter()
613-
.filter_map(|x| clean_where_predicate(x, cx))
685+
where_predicates: bound_predicates
686+
.into_iter()
687+
.map(|(ty, (bounds, bound_params))| WherePredicate::BoundPredicate {
688+
ty,
689+
bounds,
690+
bound_params,
691+
})
692+
.chain(
693+
region_predicates
694+
.into_iter()
695+
.map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }),
696+
)
697+
.chain(eq_predicates.into_iter())
614698
.collect(),
615-
};
616-
617-
// Some duplicates are generated for ?Sized bounds between type params and where
618-
// predicates. The point in here is to move the bounds definitions from type params
619-
// to where predicates when such cases occur.
620-
for where_pred in &mut generics.where_predicates {
621-
match *where_pred {
622-
WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => {
623-
if bounds.is_empty() {
624-
for param in &mut generics.params {
625-
match param.kind {
626-
GenericParamDefKind::Lifetime { .. } => {}
627-
GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
628-
if &param.name == name {
629-
mem::swap(bounds, ty_bounds);
630-
break;
631-
}
632-
}
633-
GenericParamDefKind::Const { .. } => {}
634-
}
635-
}
636-
}
637-
}
638-
_ => continue,
639-
}
640699
}
641-
generics
642700
}
643701

644702
fn clean_ty_generics<'tcx>(

0 commit comments

Comments
 (0)