5
5
6
6
use rustc_arena:: DroplessArena ;
7
7
use rustc_hir:: def:: DefKind ;
8
- use rustc_hir:: def_id:: DefId ;
8
+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
9
9
use rustc_middle:: ty:: query:: Providers ;
10
- use rustc_middle:: ty:: { self , CrateVariancesMap , TyCtxt } ;
10
+ use rustc_middle:: ty:: { self , CrateVariancesMap , TyCtxt , TypeSuperVisitable , TypeVisitable } ;
11
+ use std:: ops:: ControlFlow ;
11
12
12
13
/// Defines the `TermsContext` basically houses an arena where we can
13
14
/// allocate terms.
@@ -50,6 +51,9 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
50
51
| DefKind :: Union
51
52
| DefKind :: Variant
52
53
| DefKind :: Ctor ( ..) => { }
54
+ DefKind :: OpaqueTy | DefKind :: ImplTraitPlaceholder => {
55
+ return variance_of_opaque ( tcx, item_def_id. expect_local ( ) ) ;
56
+ }
53
57
_ => {
54
58
// Variance not relevant.
55
59
span_bug ! ( tcx. def_span( item_def_id) , "asked to compute variance for wrong kind of item" )
@@ -61,3 +65,89 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
61
65
let crate_map = tcx. crate_variances ( ( ) ) ;
62
66
crate_map. variances . get ( & item_def_id) . copied ( ) . unwrap_or ( & [ ] )
63
67
}
68
+
69
+ #[ instrument( level = "trace" , skip( tcx) , ret) ]
70
+ fn variance_of_opaque ( tcx : TyCtxt < ' _ > , item_def_id : LocalDefId ) -> & [ ty:: Variance ] {
71
+ let generics = tcx. generics_of ( item_def_id) ;
72
+
73
+ // Opaque types may only use regions that are bound. So for
74
+ // ```rust
75
+ // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
76
+ // ```
77
+ // we may not use `'c` in the hidden type.
78
+ struct OpaqueTypeLifetimeCollector {
79
+ variances : Vec < ty:: Variance > ,
80
+ }
81
+
82
+ impl < ' tcx > ty:: TypeVisitor < ' tcx > for OpaqueTypeLifetimeCollector {
83
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
84
+ fn visit_region ( & mut self , r : ty:: Region < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
85
+ if let ty:: RegionKind :: ReEarlyBound ( ebr) = r. kind ( ) {
86
+ self . variances [ ebr. index as usize ] = ty:: Invariant ;
87
+ }
88
+ r. super_visit_with ( self )
89
+ }
90
+ }
91
+
92
+ // By default, we RPIT are invariant wrt type and const generics, but they are bivariant wrt
93
+ // lifetime generics.
94
+ let mut variances: Vec < _ > = std:: iter:: repeat ( ty:: Invariant ) . take ( generics. count ( ) ) . collect ( ) ;
95
+
96
+ // Mark all lifetimes from parent generics as unused (Bivariant).
97
+ // This will be overridden later if required.
98
+ {
99
+ let mut generics = generics;
100
+ while let Some ( def_id) = generics. parent {
101
+ generics = tcx. generics_of ( def_id) ;
102
+ for param in & generics. params {
103
+ match param. kind {
104
+ ty:: GenericParamDefKind :: Lifetime => {
105
+ variances[ param. index as usize ] = ty:: Bivariant ;
106
+ }
107
+ ty:: GenericParamDefKind :: Type { .. }
108
+ | ty:: GenericParamDefKind :: Const { .. } => { }
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ let mut collector = OpaqueTypeLifetimeCollector { variances } ;
115
+ let id_substs = ty:: InternalSubsts :: identity_for_item ( tcx, item_def_id. to_def_id ( ) ) ;
116
+ for pred in tcx. bound_explicit_item_bounds ( item_def_id. to_def_id ( ) ) . transpose_iter ( ) {
117
+ let pred = pred. map_bound ( |( pred, _) | * pred) . subst ( tcx, id_substs) ;
118
+ debug ! ( ?pred) ;
119
+
120
+ // We only ignore opaque type substs if the opaque type is the outermost type.
121
+ // The opaque type may be nested within itself via recursion in e.g.
122
+ // type Foo<'a> = impl PartialEq<Foo<'a>>;
123
+ // which thus mentions `'a` and should thus accept hidden types that borrow 'a
124
+ // instead of requiring an additional `+ 'a`.
125
+ match pred. kind ( ) . skip_binder ( ) {
126
+ ty:: PredicateKind :: Trait ( ty:: TraitPredicate {
127
+ trait_ref : ty:: TraitRef { def_id : _, substs } ,
128
+ constness : _,
129
+ polarity : _,
130
+ } ) => {
131
+ for subst in & substs[ 1 ..] {
132
+ subst. visit_with ( & mut collector) ;
133
+ }
134
+ }
135
+ ty:: PredicateKind :: Projection ( ty:: ProjectionPredicate {
136
+ projection_ty : ty:: ProjectionTy { substs, item_def_id : _ } ,
137
+ term,
138
+ } ) => {
139
+ for subst in & substs[ 1 ..] {
140
+ subst. visit_with ( & mut collector) ;
141
+ }
142
+ term. visit_with ( & mut collector) ;
143
+ }
144
+ ty:: PredicateKind :: TypeOutlives ( ty:: OutlivesPredicate ( _, region) ) => {
145
+ region. visit_with ( & mut collector) ;
146
+ }
147
+ _ => {
148
+ pred. visit_with ( & mut collector) ;
149
+ }
150
+ }
151
+ }
152
+ tcx. arena . alloc_from_iter ( collector. variances . into_iter ( ) )
153
+ }
0 commit comments