@@ -321,7 +321,7 @@ fn clean_where_predicate<'tcx>(
321321 let bound_params = wbp
322322 . bound_generic_params
323323 . iter ( )
324- . map ( |param| clean_generic_param ( cx, None , param ) )
324+ . map ( |param| clean_generic_param ( cx, param , None , None ) )
325325 . collect ( ) ;
326326 WherePredicate :: BoundPredicate {
327327 ty : clean_ty ( wbp. bounded_ty , cx) ,
@@ -502,11 +502,12 @@ fn projection_to_path_segment<'tcx>(
502502
503503fn clean_generic_param_def < ' tcx > (
504504 def : & ty:: GenericParamDef ,
505+ variance : Option < ty:: Variance > ,
505506 cx : & mut DocContext < ' tcx > ,
506507) -> GenericParamDef {
507508 let ( name, kind) = match def. kind {
508509 ty:: GenericParamDefKind :: Lifetime => {
509- ( def. name , LifetimeParam { outlives : ThinVec :: new ( ) } . into ( ) )
510+ ( def. name , LifetimeParam { variance , outlives : ThinVec :: new ( ) } . into ( ) )
510511 }
511512 ty:: GenericParamDefKind :: Type { has_default, synthetic, .. } => {
512513 let default = has_default. then ( || {
@@ -520,6 +521,7 @@ fn clean_generic_param_def<'tcx>(
520521 (
521522 def. name ,
522523 TypeParam {
524+ variance,
523525 bounds : ThinVec :: new ( ) , // These are filled in from the where-clause.
524526 default,
525527 synthetic,
@@ -555,8 +557,9 @@ fn clean_generic_param_def<'tcx>(
555557
556558fn clean_generic_param < ' tcx > (
557559 cx : & mut DocContext < ' tcx > ,
558- generics : Option < & hir:: Generics < ' tcx > > ,
559560 param : & hir:: GenericParam < ' tcx > ,
561+ variance : Option < ty:: Variance > ,
562+ generics : Option < & hir:: Generics < ' tcx > > ,
560563) -> GenericParamDef {
561564 let ( name, kind) = match param. kind {
562565 hir:: GenericParamKind :: Lifetime { .. } => {
@@ -573,7 +576,7 @@ fn clean_generic_param<'tcx>(
573576 } else {
574577 ThinVec :: new ( )
575578 } ;
576- ( param. name . ident ( ) . name , LifetimeParam { outlives } . into ( ) )
579+ ( param. name . ident ( ) . name , LifetimeParam { variance , outlives } . into ( ) )
577580 }
578581 hir:: GenericParamKind :: Type { ref default, synthetic } => {
579582 let bounds = if let Some ( generics) = generics {
@@ -588,7 +591,13 @@ fn clean_generic_param<'tcx>(
588591 } ;
589592 (
590593 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 ( ) ,
592601 )
593602 }
594603 hir:: GenericParamKind :: Const { ty, default, is_host_effect } => (
@@ -629,14 +638,43 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
629638pub ( crate ) fn clean_generics < ' tcx > (
630639 generics : & hir:: Generics < ' tcx > ,
631640 cx : & mut DocContext < ' tcx > ,
632- _item_def_id : DefId ,
641+ item_def_id : DefId ,
633642) -> 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+
634666 let impl_trait_params = generics
635667 . params
636668 . iter ( )
637669 . filter ( |param| is_impl_trait ( param) )
638670 . 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) ) ;
640678 let GenericParamDefKind :: Type ( ty_param) = & param. kind else { unreachable ! ( ) } ;
641679 cx. impl_trait_bounds . insert ( param. def_id . into ( ) , ty_param. bounds . to_vec ( ) ) ;
642680 param
@@ -694,7 +732,14 @@ pub(crate) fn clean_generics<'tcx>(
694732 // bounds in the where predicates. If so, we move their bounds into the where predicates
695733 // while also preventing duplicates.
696734 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+
698743 match & mut param. kind {
699744 GenericParamDefKind :: Lifetime ( lt_param) => {
700745 if let Some ( region_pred) = region_predicates. get_mut ( & Lifetime ( param. name ) ) {
@@ -748,8 +793,25 @@ fn clean_ty_generics<'tcx>(
748793 cx : & mut DocContext < ' tcx > ,
749794 generics : & ty:: Generics ,
750795 predicates : ty:: GenericPredicates < ' tcx > ,
751- _item_def_id : DefId ,
796+ item_def_id : DefId ,
752797) -> 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+
753815 // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
754816 // since `Clean for ty::Predicate` would consume them.
755817 let mut impl_trait = BTreeMap :: < u32 , Vec < GenericBound > > :: default ( ) ;
@@ -760,22 +822,26 @@ fn clean_ty_generics<'tcx>(
760822 let stripped_params = generics
761823 . params
762824 . 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 ( ) ,
766827 ty:: GenericParamDefKind :: Type { synthetic, .. } => {
767828 if param. name == kw:: SelfUpper {
768829 assert_eq ! ( param. index, 0 ) ;
769- return None ;
830+ return false ;
770831 }
771832 if synthetic {
772833 impl_trait. insert ( param. index , vec ! [ ] ) ;
773- return None ;
834+ return false ;
774835 }
775- Some ( clean_generic_param_def ( param , cx ) )
836+ true
776837 }
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)
779845 } )
780846 . collect :: < ThinVec < GenericParamDef > > ( ) ;
781847
@@ -1223,7 +1289,7 @@ fn clean_poly_trait_ref<'tcx>(
12231289 . bound_generic_params
12241290 . iter ( )
12251291 . 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 ) )
12271293 . collect ( ) ,
12281294 }
12291295}
@@ -2558,7 +2624,7 @@ fn clean_bare_fn_ty<'tcx>(
25582624 . generic_params
25592625 . iter ( )
25602626 . 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?
25622628 . collect ( ) ;
25632629 let args = clean_args_from_types_and_names ( cx, bare_fn. decl . inputs , bare_fn. param_names ) ;
25642630 let decl = clean_fn_decl_with_args ( cx, bare_fn. decl , None , args) ;
@@ -3141,8 +3207,13 @@ fn clean_bound_vars<'tcx>(
31413207 Some ( GenericParamDef {
31423208 name,
31433209 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 ( ) ,
31463217 } )
31473218 }
31483219 // FIXME(non_lifetime_binders): Support higher-ranked const parameters.
0 commit comments