@@ -12,8 +12,9 @@ use rustc_infer::infer::outlives::test_type_match;
1212use rustc_infer:: infer:: region_constraints:: { GenericKind , VarInfos , VerifyBound , VerifyIfEq } ;
1313use rustc_infer:: infer:: { InferCtxt , NllRegionVariableOrigin , RegionVariableOrigin } ;
1414use 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 ,
1718} ;
1819use rustc_middle:: traits:: ObligationCause ;
1920use rustc_middle:: traits:: ObligationCauseCode ;
@@ -1084,18 +1085,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10841085 true
10851086 }
10861087
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.
10991092 #[ instrument( level = "debug" , skip( self , infcx) ) ]
11001093 fn try_promote_type_test_subject (
11011094 & self ,
@@ -1104,91 +1097,63 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11041097 ) -> Option < ClosureOutlivesSubject < ' tcx > > {
11051098 let tcx = infcx. tcx ;
11061099
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+
11071130 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) ;
11091133
11101134 // The challenge if this. We have some region variable `r`
11111135 // whose value is a set of CFG points and universal
11121136 // regions. We want to find if that set is *equivalent* to
11131137 // 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 )
11531147 } ) ;
11541148
11551149 debug ! ( "try_promote_type_test_subject: folded ty = {:?}" , ty) ;
11561150
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 ( ) {
11591153 return None ;
11601154 }
11611155
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) ) )
11921157 }
11931158
11941159 /// Returns a universally quantified region that outlives the
0 commit comments