44//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/variance.html
55
66use rustc_arena:: DroplessArena ;
7+ use rustc_hir as hir;
78use rustc_hir:: def:: DefKind ;
8- use rustc_hir:: def_id:: DefId ;
9+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
910use 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 ;
1113
1214/// Defines the `TermsContext` basically houses an arena where we can
1315/// allocate terms.
@@ -50,6 +52,9 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] {
5052 | DefKind :: Union
5153 | DefKind :: Variant
5254 | DefKind :: Ctor ( ..) => { }
55+ DefKind :: OpaqueTy | DefKind :: ImplTraitPlaceholder => {
56+ return variance_of_opaque ( tcx, item_def_id. expect_local ( ) ) ;
57+ }
5358 _ => {
5459 // Variance not relevant.
5560 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] {
6166 let crate_map = tcx. crate_variances ( ( ) ) ;
6267 crate_map. variances . get ( & item_def_id) . copied ( ) . unwrap_or ( & [ ] )
6368}
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