@@ -12,7 +12,7 @@ pub(crate) mod utils;
1212
1313use rustc_ast as ast;
1414use rustc_attr as attr;
15- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexSet } ;
15+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexMap , FxIndexSet , IndexEntry } ;
1616use rustc_hir as hir;
1717use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
1818use 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
644702fn clean_ty_generics < ' tcx > (
0 commit comments