@@ -321,7 +321,7 @@ fn clean_where_predicate<'tcx>(
321
321
let bound_params = wbp
322
322
. bound_generic_params
323
323
. iter ( )
324
- . map ( |param| clean_generic_param ( cx, None , param ) )
324
+ . map ( |param| clean_generic_param ( cx, param , None , None ) )
325
325
. collect ( ) ;
326
326
WherePredicate :: BoundPredicate {
327
327
ty : clean_ty ( wbp. bounded_ty , cx) ,
@@ -502,11 +502,12 @@ fn projection_to_path_segment<'tcx>(
502
502
503
503
fn clean_generic_param_def < ' tcx > (
504
504
def : & ty:: GenericParamDef ,
505
+ variance : Option < ty:: Variance > ,
505
506
cx : & mut DocContext < ' tcx > ,
506
507
) -> GenericParamDef {
507
508
let ( name, kind) = match def. kind {
508
509
ty:: GenericParamDefKind :: Lifetime => {
509
- ( def. name , LifetimeParam { outlives : ThinVec :: new ( ) } . into ( ) )
510
+ ( def. name , LifetimeParam { variance , outlives : ThinVec :: new ( ) } . into ( ) )
510
511
}
511
512
ty:: GenericParamDefKind :: Type { has_default, synthetic, .. } => {
512
513
let default = has_default. then ( || {
@@ -520,6 +521,7 @@ fn clean_generic_param_def<'tcx>(
520
521
(
521
522
def. name ,
522
523
TypeParam {
524
+ variance,
523
525
bounds : ThinVec :: new ( ) , // These are filled in from the where-clause.
524
526
default,
525
527
synthetic,
@@ -555,8 +557,9 @@ fn clean_generic_param_def<'tcx>(
555
557
556
558
fn clean_generic_param < ' tcx > (
557
559
cx : & mut DocContext < ' tcx > ,
558
- generics : Option < & hir:: Generics < ' tcx > > ,
559
560
param : & hir:: GenericParam < ' tcx > ,
561
+ variance : Option < ty:: Variance > ,
562
+ generics : Option < & hir:: Generics < ' tcx > > ,
560
563
) -> GenericParamDef {
561
564
let ( name, kind) = match param. kind {
562
565
hir:: GenericParamKind :: Lifetime { .. } => {
@@ -573,7 +576,7 @@ fn clean_generic_param<'tcx>(
573
576
} else {
574
577
ThinVec :: new ( )
575
578
} ;
576
- ( param. name . ident ( ) . name , LifetimeParam { outlives } . into ( ) )
579
+ ( param. name . ident ( ) . name , LifetimeParam { variance , outlives } . into ( ) )
577
580
}
578
581
hir:: GenericParamKind :: Type { ref default, synthetic } => {
579
582
let bounds = if let Some ( generics) = generics {
@@ -588,7 +591,13 @@ fn clean_generic_param<'tcx>(
588
591
} ;
589
592
(
590
593
param. name . ident ( ) . name ,
591
- TypeParam { bounds, default : default. map ( |t| clean_ty ( t, cx) ) , synthetic } . into ( ) ,
594
+ TypeParam {
595
+ variance,
596
+ bounds,
597
+ default : default. map ( |t| clean_ty ( t, cx) ) ,
598
+ synthetic,
599
+ }
600
+ . into ( ) ,
592
601
)
593
602
}
594
603
hir:: GenericParamKind :: Const { ty, default, is_host_effect } => (
@@ -629,14 +638,43 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
629
638
pub ( crate ) fn clean_generics < ' tcx > (
630
639
generics : & hir:: Generics < ' tcx > ,
631
640
cx : & mut DocContext < ' tcx > ,
632
- _item_def_id : DefId ,
641
+ item_def_id : DefId ,
633
642
) -> Generics {
643
+ // FIXME(fmease): Instead of querying the DefKind, we could instead let the caller somehow make
644
+ // the decision of whether to compute variances or not. Mostly relevant for synthetic impls but
645
+ // also for function items since we probably want to *invert* the variances going forward.
646
+ // FIXME(fmease): Add support for lazy type aliases (`DefKind::TyAlias if type_alias_is_lazy()`).
647
+ let def_kind = cx. tcx . def_kind ( item_def_id) ;
648
+ let variances = if !generics. params . is_empty ( )
649
+ && let DefKind :: Fn
650
+ | DefKind :: AssocFn
651
+ | DefKind :: Enum
652
+ | DefKind :: Struct
653
+ | DefKind :: Union
654
+ | DefKind :: OpaqueTy = def_kind
655
+ {
656
+ // We need to obtain the middle generics since we can't simply enumerate the HIR params when
657
+ // iterating over them and index into the variances directly. We need to account for late-bound
658
+ // regions and parent generics.
659
+ let variances = cx. tcx . variances_of ( item_def_id) ;
660
+ let generics = cx. tcx . generics_of ( item_def_id) ;
661
+ Some ( ( variances, generics) )
662
+ } else {
663
+ None
664
+ } ;
665
+
634
666
let impl_trait_params = generics
635
667
. params
636
668
. iter ( )
637
669
. filter ( |param| is_impl_trait ( param) )
638
670
. map ( |param| {
639
- let param = clean_generic_param ( cx, Some ( generics) , param) ;
671
+ let variance = variances. and_then ( |( variances, generics) | {
672
+ // The `param` might be late-bound in which case it doesn't have a variance associated
673
+ // with it. Hence the fallible indexing.
674
+ let index = * generics. param_def_id_to_index . get ( & param. def_id . to_def_id ( ) ) ?;
675
+ Some ( variances[ index as usize ] )
676
+ } ) ;
677
+ let param = clean_generic_param ( cx, param, variance, Some ( generics) ) ;
640
678
let GenericParamDefKind :: Type ( ty_param) = & param. kind else { unreachable ! ( ) } ;
641
679
cx. impl_trait_bounds . insert ( param. def_id . into ( ) , ty_param. bounds . to_vec ( ) ) ;
642
680
param
@@ -694,7 +732,14 @@ pub(crate) fn clean_generics<'tcx>(
694
732
// bounds in the where predicates. If so, we move their bounds into the where predicates
695
733
// while also preventing duplicates.
696
734
for param in generics. params . iter ( ) . filter ( |p| !is_impl_trait ( p) && !is_elided_lifetime ( p) ) {
697
- let mut param = clean_generic_param ( cx, Some ( generics) , param) ;
735
+ let variance = variances. and_then ( |( variances, generics) | {
736
+ // The `param` might be late-bound in which case it doesn't have a variance associated
737
+ // with it. Hence the fallible indexing.
738
+ let index = * generics. param_def_id_to_index . get ( & param. def_id . to_def_id ( ) ) ?;
739
+ Some ( variances[ index as usize ] )
740
+ } ) ;
741
+ let mut param = clean_generic_param ( cx, param, variance, Some ( generics) ) ;
742
+
698
743
match & mut param. kind {
699
744
GenericParamDefKind :: Lifetime ( lt_param) => {
700
745
if let Some ( region_pred) = region_predicates. get_mut ( & Lifetime ( param. name ) ) {
@@ -748,8 +793,25 @@ fn clean_ty_generics<'tcx>(
748
793
cx : & mut DocContext < ' tcx > ,
749
794
generics : & ty:: Generics ,
750
795
predicates : ty:: GenericPredicates < ' tcx > ,
751
- _item_def_id : DefId ,
796
+ item_def_id : DefId ,
752
797
) -> Generics {
798
+ // FIXME(fmease): Instead of querying the DefKind, we could instead let the caller somehow make
799
+ // the decision of whether to compute variances or not. Mostly relevant for synthetic impls but
800
+ // also for function items since we probably want to *invert* the variances going forward.
801
+ // FIXME(fmease): Add support for lazy type aliases (`DefKind::TyAlias if type_alias_is_lazy()`).
802
+ let variances = if !generics. params . is_empty ( )
803
+ && let DefKind :: Fn
804
+ | DefKind :: AssocFn
805
+ | DefKind :: Enum
806
+ | DefKind :: Struct
807
+ | DefKind :: Union
808
+ | DefKind :: OpaqueTy = cx. tcx . def_kind ( item_def_id)
809
+ {
810
+ Some ( cx. tcx . variances_of ( item_def_id) )
811
+ } else {
812
+ None
813
+ } ;
814
+
753
815
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
754
816
// since `Clean for ty::Predicate` would consume them.
755
817
let mut impl_trait = BTreeMap :: < u32 , Vec < GenericBound > > :: default ( ) ;
@@ -760,22 +822,26 @@ fn clean_ty_generics<'tcx>(
760
822
let stripped_params = generics
761
823
. params
762
824
. iter ( )
763
- . filter_map ( |param| match param. kind {
764
- ty:: GenericParamDefKind :: Lifetime if param. is_anonymous_lifetime ( ) => None ,
765
- ty:: GenericParamDefKind :: Lifetime => Some ( clean_generic_param_def ( param, cx) ) ,
825
+ . filter ( |param| match param. kind {
826
+ ty:: GenericParamDefKind :: Lifetime => !param. is_anonymous_lifetime ( ) ,
766
827
ty:: GenericParamDefKind :: Type { synthetic, .. } => {
767
828
if param. name == kw:: SelfUpper {
768
829
assert_eq ! ( param. index, 0 ) ;
769
- return None ;
830
+ return false ;
770
831
}
771
832
if synthetic {
772
833
impl_trait. insert ( param. index , vec ! [ ] ) ;
773
- return None ;
834
+ return false ;
774
835
}
775
- Some ( clean_generic_param_def ( param , cx ) )
836
+ true
776
837
}
777
- ty:: GenericParamDefKind :: Const { is_host_effect : true , .. } => None ,
778
- ty:: GenericParamDefKind :: Const { .. } => Some ( clean_generic_param_def ( param, cx) ) ,
838
+ ty:: GenericParamDefKind :: Const { is_host_effect, .. } => !is_host_effect,
839
+ } )
840
+ . map ( |param| {
841
+ let variance = variances
842
+ . map ( |variances| variances[ generics. param_def_id_to_index [ & param. def_id ] as usize ] ) ;
843
+
844
+ clean_generic_param_def ( param, variance, cx)
779
845
} )
780
846
. collect :: < ThinVec < GenericParamDef > > ( ) ;
781
847
@@ -1223,7 +1289,7 @@ fn clean_poly_trait_ref<'tcx>(
1223
1289
. bound_generic_params
1224
1290
. iter ( )
1225
1291
. filter ( |p| !is_elided_lifetime ( p) )
1226
- . map ( |x| clean_generic_param ( cx, None , x ) )
1292
+ . map ( |x| clean_generic_param ( cx, x , None , None ) )
1227
1293
. collect ( ) ,
1228
1294
}
1229
1295
}
@@ -2558,7 +2624,7 @@ fn clean_bare_fn_ty<'tcx>(
2558
2624
. generic_params
2559
2625
. iter ( )
2560
2626
. filter ( |p| !is_elided_lifetime ( p) )
2561
- . map ( |x| clean_generic_param ( cx, None , x ) )
2627
+ . map ( |x| clean_generic_param ( cx, x , None , None ) ) // FIXME(fmease): variance?
2562
2628
. collect ( ) ;
2563
2629
let args = clean_args_from_types_and_names ( cx, bare_fn. decl . inputs , bare_fn. param_names ) ;
2564
2630
let decl = clean_fn_decl_with_args ( cx, bare_fn. decl , None , args) ;
@@ -3141,8 +3207,13 @@ fn clean_bound_vars<'tcx>(
3141
3207
Some ( GenericParamDef {
3142
3208
name,
3143
3209
def_id,
3144
- kind : TypeParam { bounds : ThinVec :: new ( ) , default : None , synthetic : false }
3145
- . into ( ) ,
3210
+ kind : TypeParam {
3211
+ variance : None ,
3212
+ bounds : ThinVec :: new ( ) ,
3213
+ default : None ,
3214
+ synthetic : false ,
3215
+ }
3216
+ . into ( ) ,
3146
3217
} )
3147
3218
}
3148
3219
// FIXME(non_lifetime_binders): Support higher-ranked const parameters.
0 commit comments