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