@@ -16,6 +16,7 @@ use borrow_check::nll::ConstraintDescription;
1616use rustc:: hir:: def_id:: DefId ;
1717use rustc:: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
1818use rustc:: infer:: InferCtxt ;
19+ use rustc:: infer:: NLLRegionVariableOrigin ;
1920use rustc:: mir:: { ConstraintCategory , Location , Mir } ;
2021use rustc:: ty:: { self , RegionVid } ;
2122use rustc_data_structures:: indexed_vec:: IndexVec ;
@@ -177,6 +178,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
177178 deque. push_back ( from_region) ;
178179
179180 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+
180188 // Check if we reached the region we were looking for. If so,
181189 // we can reconstruct the path that led to it and return it.
182190 if target_test ( r) {
@@ -238,7 +246,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
238246 ) {
239247 debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
240248
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+ } ) ;
242252
243253 // Check if we can use one of the "nice region errors".
244254 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> {
296306 } ;
297307 }
298308
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+
299336 /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
300337 /// This function expects `fr` to be local and `outlived_fr` to not be local.
301338 ///
@@ -636,11 +673,37 @@ impl<'tcx> RegionInferenceContext<'tcx> {
636673 // `elem`.
637674 crate fn find_sub_region_live_at ( & self , fr1 : RegionVid , elem : Location ) -> RegionVid {
638675 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+ ) ;
641683 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 ( )
644707 }
645708
646709 // Finds a good span to blame for the fact that `fr1` outlives `fr2`.
@@ -650,7 +713,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
650713 fr1 : RegionVid ,
651714 fr2 : RegionVid ,
652715 ) -> ( 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) ) ;
654718 ( category, span)
655719 }
656720
@@ -684,4 +748,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
684748
685749 false
686750 }
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+ }
687771}
0 commit comments