@@ -16,6 +16,7 @@ use borrow_check::nll::ConstraintDescription;
16
16
use rustc:: hir:: def_id:: DefId ;
17
17
use rustc:: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
18
18
use rustc:: infer:: InferCtxt ;
19
+ use rustc:: infer:: NLLRegionVariableOrigin ;
19
20
use rustc:: mir:: { ConstraintCategory , Location , Mir } ;
20
21
use rustc:: ty:: { self , RegionVid } ;
21
22
use rustc_data_structures:: indexed_vec:: IndexVec ;
@@ -177,6 +178,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
177
178
deque. push_back ( from_region) ;
178
179
179
180
while let Some ( r) = deque. pop_front ( ) {
181
+ debug ! (
182
+ "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}" ,
183
+ from_region,
184
+ r,
185
+ self . region_value_str( r) ,
186
+ ) ;
187
+
180
188
// Check if we reached the region we were looking for. If so,
181
189
// we can reconstruct the path that led to it and return it.
182
190
if target_test ( r) {
@@ -238,7 +246,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
238
246
) {
239
247
debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
240
248
241
- let ( category, _, span) = self . best_blame_constraint ( mir, fr, |r| r == outlived_fr) ;
249
+ let ( category, _, span) = self . best_blame_constraint ( mir, fr, |r| {
250
+ self . provides_universal_region ( r, fr, outlived_fr)
251
+ } ) ;
242
252
243
253
// Check if we can use one of the "nice region errors".
244
254
if let ( Some ( f) , Some ( o) ) = ( self . to_error_region ( fr) , self . to_error_region ( outlived_fr) ) {
@@ -296,6 +306,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
296
306
} ;
297
307
}
298
308
309
+ /// We have a constraint `fr1: fr2` that is not satisfied, where
310
+ /// `fr2` represents some universal region. Here, `r` is some
311
+ /// region where we know that `fr1: r` and this function has the
312
+ /// job of determining whether `r` is "to blame" for the fact that
313
+ /// `fr1: fr2` is required.
314
+ ///
315
+ /// This is true under two conditions:
316
+ ///
317
+ /// - `r == fr2`
318
+ /// - `fr2` is `'static` and `r` is some placeholder in a universe
319
+ /// that cannot be named by `fr1`; in that case, we will require
320
+ /// that `fr1: 'static` because it is the only way to `fr1: r` to
321
+ /// be satisfied. (See `add_incompatible_universe`.)
322
+ fn provides_universal_region ( & self , r : RegionVid , fr1 : RegionVid , fr2 : RegionVid ) -> bool {
323
+ debug ! (
324
+ "provides_universal_region(r={:?}, fr1={:?}, fr2={:?})" ,
325
+ r, fr1, fr2
326
+ ) ;
327
+ let result = {
328
+ r == fr2 || {
329
+ fr2 == self . universal_regions . fr_static && self . cannot_name_placeholder ( fr1, r)
330
+ }
331
+ } ;
332
+ debug ! ( "provides_universal_region: result = {:?}" , result) ;
333
+ result
334
+ }
335
+
299
336
/// Report a specialized error when `FnMut` closures return a reference to a captured variable.
300
337
/// This function expects `fr` to be local and `outlived_fr` to not be local.
301
338
///
@@ -636,11 +673,37 @@ impl<'tcx> RegionInferenceContext<'tcx> {
636
673
// `elem`.
637
674
crate fn find_sub_region_live_at ( & self , fr1 : RegionVid , elem : Location ) -> RegionVid {
638
675
debug ! ( "find_sub_region_live_at(fr1={:?}, elem={:?})" , fr1, elem) ;
639
- // Find all paths
640
- let ( _path, r) = self . find_constraint_paths_between_regions ( fr1, |r| {
676
+ self . find_constraint_paths_between_regions ( fr1, |r| {
677
+ // First look for some `r` such that `fr1: r` and `r` is live at `elem`
678
+ debug ! (
679
+ "find_sub_region_live_at: liveness_constraints for {:?} are {:?}" ,
680
+ r,
681
+ self . liveness_constraints. region_value_str( r) ,
682
+ ) ;
641
683
self . liveness_constraints . contains ( r, elem)
642
- } ) . unwrap ( ) ;
643
- r
684
+ } ) . or_else ( || {
685
+ // If we fail to find that, we may find some `r` such that
686
+ // `fr1: r` and `r` is a placeholder from some universe
687
+ // `fr1` cannot name. This would force `fr1` to be
688
+ // `'static`.
689
+ self . find_constraint_paths_between_regions ( fr1, |r| {
690
+ self . cannot_name_placeholder ( fr1, r)
691
+ } )
692
+ } )
693
+ . or_else ( || {
694
+ // If we fail to find THAT, it may be that `fr1` is a
695
+ // placeholder that cannot "fit" into its SCC. In that
696
+ // case, there should be some `r` where `fr1: r`, both
697
+ // `fr1` and `r` are in the same SCC, and `fr1` is a
698
+ // placeholder that `r` cannot name. We can blame that
699
+ // edge.
700
+ self . find_constraint_paths_between_regions ( fr1, |r| {
701
+ self . constraint_sccs . scc ( fr1) == self . constraint_sccs . scc ( r)
702
+ && self . cannot_name_placeholder ( r, fr1)
703
+ } )
704
+ } )
705
+ . map ( |( _path, r) | r)
706
+ . unwrap ( )
644
707
}
645
708
646
709
// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
@@ -650,7 +713,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
650
713
fr1 : RegionVid ,
651
714
fr2 : RegionVid ,
652
715
) -> ( ConstraintCategory , Span ) {
653
- let ( category, _, span) = self . best_blame_constraint ( mir, fr1, |r| r == fr2) ;
716
+ let ( category, _, span) =
717
+ self . best_blame_constraint ( mir, fr1, |r| self . provides_universal_region ( r, fr1, fr2) ) ;
654
718
( category, span)
655
719
}
656
720
@@ -684,4 +748,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
684
748
685
749
false
686
750
}
751
+
752
+ /// If `r2` represents a placeholder region, then this returns
753
+ /// true if `r1` cannot name that placeholder in its
754
+ /// value. Otherwise, returns false.
755
+ fn cannot_name_placeholder ( & self , r1 : RegionVid , r2 : RegionVid ) -> bool {
756
+ debug ! ( "cannot_name_value_of(r1={:?}, r2={:?})" , r1, r2) ;
757
+
758
+ match self . definitions [ r2] . origin {
759
+ NLLRegionVariableOrigin :: Placeholder ( placeholder) => {
760
+ let universe1 = self . definitions [ r1] . universe ;
761
+ debug ! (
762
+ "cannot_name_value_of: universe1={:?} placeholder={:?}" ,
763
+ universe1, placeholder
764
+ ) ;
765
+ universe1. cannot_name ( placeholder. universe )
766
+ }
767
+
768
+ NLLRegionVariableOrigin :: FreeRegion | NLLRegionVariableOrigin :: Existential => false ,
769
+ }
770
+ }
687
771
}
0 commit comments