@@ -12,7 +12,7 @@ pub(crate) mod utils;
12
12
13
13
use rustc_ast as ast;
14
14
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 } ;
16
16
use rustc_hir as hir;
17
17
use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
18
18
use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
@@ -598,47 +598,105 @@ pub(crate) fn clean_generics<'tcx>(
598
598
} )
599
599
. collect :: < Vec < _ > > ( ) ;
600
600
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
+
601
647
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.
602
651
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
+ }
604
679
params. push ( p) ;
605
680
}
606
681
params. extend ( impl_trait_params) ;
607
682
608
- let mut generics = Generics {
683
+ Generics {
609
684
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 ( ) )
614
698
. 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
- }
640
699
}
641
- generics
642
700
}
643
701
644
702
fn clean_ty_generics < ' tcx > (
0 commit comments