@@ -12,8 +12,9 @@ use rustc_infer::infer::outlives::test_type_match;
12
12
use rustc_infer:: infer:: region_constraints:: { GenericKind , VarInfos , VerifyBound , VerifyIfEq } ;
13
13
use rustc_infer:: infer:: { InferCtxt , NllRegionVariableOrigin , RegionVariableOrigin } ;
14
14
use rustc_middle:: mir:: {
15
- Body , ClosureOutlivesRequirement , ClosureOutlivesSubject , ClosureRegionRequirements ,
16
- ConstraintCategory , Local , Location , ReturnConstraint , TerminatorKind ,
15
+ Body , ClosureOutlivesRequirement , ClosureOutlivesSubject , ClosureOutlivesSubjectTy ,
16
+ ClosureRegionRequirements , ConstraintCategory , Local , Location , ReturnConstraint ,
17
+ TerminatorKind ,
17
18
} ;
18
19
use rustc_middle:: traits:: ObligationCause ;
19
20
use rustc_middle:: traits:: ObligationCauseCode ;
@@ -1084,18 +1085,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1084
1085
true
1085
1086
}
1086
1087
1087
- /// When we promote a type test `T: 'r`, we have to convert the
1088
- /// type `T` into something we can store in a query result (so
1089
- /// something allocated for `'tcx`). This is problematic if `ty`
1090
- /// contains regions. During the course of NLL region checking, we
1091
- /// will have replaced all of those regions with fresh inference
1092
- /// variables. To create a test subject, we want to replace those
1093
- /// inference variables with some region from the closure
1094
- /// signature -- this is not always possible, so this is a
1095
- /// fallible process. Presuming we do find a suitable region, we
1096
- /// will use it's *external name*, which will be a `RegionKind`
1097
- /// variant that can be used in query responses such as
1098
- /// `ReEarlyBound`.
1088
+ /// When we promote a type test `T: 'r`, we have to replace all region
1089
+ /// variables in the type `T` with an equal universal region from the
1090
+ /// closure signature.
1091
+ /// This is not always possible, so this is a fallible process.
1099
1092
#[ instrument( level = "debug" , skip( self , infcx) ) ]
1100
1093
fn try_promote_type_test_subject (
1101
1094
& self ,
@@ -1104,91 +1097,63 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1104
1097
) -> Option < ClosureOutlivesSubject < ' tcx > > {
1105
1098
let tcx = infcx. tcx ;
1106
1099
1100
+ // Opaque types' substs may include useless lifetimes.
1101
+ // We will replace them with ReStatic.
1102
+ struct OpaqueFolder < ' tcx > {
1103
+ tcx : TyCtxt < ' tcx > ,
1104
+ }
1105
+ impl < ' tcx > ty:: TypeFolder < TyCtxt < ' tcx > > for OpaqueFolder < ' tcx > {
1106
+ fn interner ( & self ) -> TyCtxt < ' tcx > {
1107
+ self . tcx
1108
+ }
1109
+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
1110
+ use ty:: TypeSuperFoldable as _;
1111
+ let tcx = self . tcx ;
1112
+ let & ty:: Alias ( ty:: Opaque , ty:: AliasTy { substs, def_id, .. } ) = t. kind ( ) else {
1113
+ return t. super_fold_with ( self ) ;
1114
+ } ;
1115
+ let substs =
1116
+ std:: iter:: zip ( substs, tcx. variances_of ( def_id) ) . map ( |( arg, v) | {
1117
+ match ( arg. unpack ( ) , v) {
1118
+ ( ty:: GenericArgKind :: Lifetime ( _) , ty:: Bivariant ) => {
1119
+ tcx. lifetimes . re_static . into ( )
1120
+ }
1121
+ _ => arg. fold_with ( self ) ,
1122
+ }
1123
+ } ) ;
1124
+ tcx. mk_opaque ( def_id, tcx. mk_substs_from_iter ( substs) )
1125
+ }
1126
+ }
1127
+
1128
+ let ty = ty. fold_with ( & mut OpaqueFolder { tcx } ) ;
1129
+
1107
1130
let ty = tcx. fold_regions ( ty, |r, _depth| {
1108
- let region_vid = self . to_region_vid ( r) ;
1131
+ let r_vid = self . to_region_vid ( r) ;
1132
+ let r_scc = self . constraint_sccs . scc ( r_vid) ;
1109
1133
1110
1134
// The challenge if this. We have some region variable `r`
1111
1135
// whose value is a set of CFG points and universal
1112
1136
// regions. We want to find if that set is *equivalent* to
1113
1137
// any of the named regions found in the closure.
1114
- //
1115
- // To do so, we compute the
1116
- // `non_local_universal_upper_bound`. This will be a
1117
- // non-local, universal region that is greater than `r`.
1118
- // However, it might not be *contained* within `r`, so
1119
- // then we further check whether this bound is contained
1120
- // in `r`. If so, we can say that `r` is equivalent to the
1121
- // bound.
1122
- //
1123
- // Let's work through a few examples. For these, imagine
1124
- // that we have 3 non-local regions (I'll denote them as
1125
- // `'static`, `'a`, and `'b`, though of course in the code
1126
- // they would be represented with indices) where:
1127
- //
1128
- // - `'static: 'a`
1129
- // - `'static: 'b`
1130
- //
1131
- // First, let's assume that `r` is some existential
1132
- // variable with an inferred value `{'a, 'static}` (plus
1133
- // some CFG nodes). In this case, the non-local upper
1134
- // bound is `'static`, since that outlives `'a`. `'static`
1135
- // is also a member of `r` and hence we consider `r`
1136
- // equivalent to `'static` (and replace it with
1137
- // `'static`).
1138
- //
1139
- // Now let's consider the inferred value `{'a, 'b}`. This
1140
- // means `r` is effectively `'a | 'b`. I'm not sure if
1141
- // this can come about, actually, but assuming it did, we
1142
- // would get a non-local upper bound of `'static`. Since
1143
- // `'static` is not contained in `r`, we would fail to
1144
- // find an equivalent.
1145
- let upper_bound = self . non_local_universal_upper_bound ( region_vid) ;
1146
- if self . region_contains ( region_vid, upper_bound) {
1147
- self . definitions [ upper_bound] . external_name . unwrap_or ( r)
1148
- } else {
1149
- // In the case of a failure, use a `ReVar` result. This will
1150
- // cause the `needs_infer` later on to return `None`.
1151
- r
1152
- }
1138
+ // To do so, we simply check every candidate `u_r` for equality.
1139
+ self . scc_values
1140
+ . universal_regions_outlived_by ( r_scc)
1141
+ . filter ( |& u_r| !self . universal_regions . is_local_free_region ( u_r) )
1142
+ . find ( |& u_r| self . eval_equal ( u_r, r_vid) )
1143
+ . map ( |u_r| tcx. mk_re_var ( u_r) )
1144
+ // In the case of a failure, use `ReErased`. We will eventually
1145
+ // return `None` in this case.
1146
+ . unwrap_or ( tcx. lifetimes . re_erased )
1153
1147
} ) ;
1154
1148
1155
1149
debug ! ( "try_promote_type_test_subject: folded ty = {:?}" , ty) ;
1156
1150
1157
- // `needs_infer` will only be true if we failed to promote some region.
1158
- if ty. needs_infer ( ) {
1151
+ // This will be true if we failed to promote some region.
1152
+ if ty. has_erased_regions ( ) {
1159
1153
return None ;
1160
1154
}
1161
1155
1162
- Some ( ClosureOutlivesSubject :: Ty ( ty) )
1163
- }
1164
-
1165
- /// Given some universal or existential region `r`, finds a
1166
- /// non-local, universal region `r+` that outlives `r` at entry to (and
1167
- /// exit from) the closure. In the worst case, this will be
1168
- /// `'static`.
1169
- ///
1170
- /// This is used for two purposes. First, if we are propagated
1171
- /// some requirement `T: r`, we can use this method to enlarge `r`
1172
- /// to something we can encode for our creator (which only knows
1173
- /// about non-local, universal regions). It is also used when
1174
- /// encoding `T` as part of `try_promote_type_test_subject` (see
1175
- /// that fn for details).
1176
- ///
1177
- /// This is based on the result `'y` of `universal_upper_bound`,
1178
- /// except that it converts further takes the non-local upper
1179
- /// bound of `'y`, so that the final result is non-local.
1180
- fn non_local_universal_upper_bound ( & self , r : RegionVid ) -> RegionVid {
1181
- debug ! ( "non_local_universal_upper_bound(r={:?}={})" , r, self . region_value_str( r) ) ;
1182
-
1183
- let lub = self . universal_upper_bound ( r) ;
1184
-
1185
- // Grow further to get smallest universal region known to
1186
- // creator.
1187
- let non_local_lub = self . universal_region_relations . non_local_upper_bound ( lub) ;
1188
-
1189
- debug ! ( "non_local_universal_upper_bound: non_local_lub={:?}" , non_local_lub) ;
1190
-
1191
- non_local_lub
1156
+ Some ( ClosureOutlivesSubject :: Ty ( ClosureOutlivesSubjectTy :: bind ( tcx, ty) ) )
1192
1157
}
1193
1158
1194
1159
/// Returns a universally quantified region that outlives the
0 commit comments