@@ -1780,18 +1780,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
17801780 }
17811781
17821782 /// Walks the graph of constraints (where `'a: 'b` is considered
1783- /// an edge `'a -> 'b`) to find all paths from `from_region` to
1784- /// `to_region`. The paths are accumulated into the vector
1785- /// `results`. The paths are stored as a series of
1786- /// `ConstraintIndex` values -- in other words, a list of *edges*.
1787- ///
1783+ /// an edge `'a -> 'b`) to find a path from `from_region` to
1784+ /// the first region `R` for which the predicate function
1785+ /// `target_test` returns `true`.
17881786 /// Returns: a series of constraints as well as the region `R`
17891787 /// that passed the target test.
1788+ /// If `include_static_outlives_all` is `true`, then the synthetic
1789+ /// outlives constraints `'static -> a` for every region `a` are
1790+ /// considered in the search, otherwise they are ignored.
17901791 #[ instrument( skip( self , target_test) , ret) ]
1791- pub ( crate ) fn find_constraint_paths_between_regions (
1792+ pub ( crate ) fn find_constraint_path_to (
17921793 & self ,
17931794 from_region : RegionVid ,
17941795 target_test : impl Fn ( RegionVid ) -> bool ,
1796+ include_static_outlives_all : bool ,
17951797 ) -> Option < ( Vec < OutlivesConstraint < ' tcx > > , RegionVid ) > {
17961798 let mut context = IndexVec :: from_elem ( Trace :: NotVisited , & self . definitions ) ;
17971799 context[ from_region] = Trace :: StartRegion ;
@@ -1804,7 +1806,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18041806
18051807 while let Some ( r) = deque. pop_front ( ) {
18061808 debug ! (
1807- "find_constraint_paths_between_regions : from_region={:?} r={:?} value={}" ,
1809+ "find_constraint_path_to : from_region={:?} r={:?} value={}" ,
18081810 from_region,
18091811 r,
18101812 self . region_value_str( r) ,
@@ -1840,7 +1842,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18401842
18411843 // A constraint like `'r: 'x` can come from our constraint
18421844 // graph.
1843- let fr_static = self . universal_regions . fr_static ;
1845+ let fr_static = if include_static_outlives_all {
1846+ Some ( self . universal_regions . fr_static )
1847+ } else {
1848+ None
1849+ } ;
18441850 let outgoing_edges_from_graph =
18451851 self . constraint_graph . outgoing_edges ( r, & self . constraints , fr_static) ;
18461852
@@ -1886,11 +1892,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18861892 pub ( crate ) fn find_sub_region_live_at ( & self , fr1 : RegionVid , location : Location ) -> RegionVid {
18871893 trace ! ( scc = ?self . constraint_sccs. scc( fr1) ) ;
18881894 trace ! ( universe = ?self . region_universe( fr1) ) ;
1889- self . find_constraint_paths_between_regions ( fr1, |r| {
1895+ self . find_constraint_path_to ( fr1, |r| {
18901896 // First look for some `r` such that `fr1: r` and `r` is live at `location`
18911897 trace ! ( ?r, liveness_constraints=?self . liveness_constraints. pretty_print_live_points( r) ) ;
18921898 self . liveness_constraints . is_live_at ( r, location)
1893- } )
1899+ } ,
1900+ true
1901+ )
18941902 . map ( |( _path, r) | r)
18951903 . unwrap ( )
18961904 }
@@ -1922,6 +1930,66 @@ impl<'tcx> RegionInferenceContext<'tcx> {
19221930 self . universal_regions . as_ref ( )
19231931 }
19241932
1933+ /// Find a path of outlives constraints from `from` to `to`,
1934+ /// taking placeholder blame constraints into account, e.g.
1935+ /// if there is a relationship where `r1` reaches `r2` and
1936+ /// r2 has a larger universe or if r1 and r2 both come from
1937+ /// placeholder regions.
1938+ ///
1939+ /// Returns the path and the target region, which may or may
1940+ /// not be the original `to`. It panics if there is no such
1941+ /// path.
1942+ fn path_to_modulo_placeholders (
1943+ & self ,
1944+ from : RegionVid ,
1945+ to : RegionVid ,
1946+ ) -> ( Vec < OutlivesConstraint < ' tcx > > , RegionVid ) {
1947+ let path = self . find_constraint_path_to ( from, |r| r == to, true ) . unwrap ( ) . 0 ;
1948+
1949+ // If we are looking for a path to 'static, and we are passing
1950+ // through a constraint synthesised from an illegal placeholder
1951+ // relation, redirect the search to the placeholder to blame.
1952+ if self . is_static ( to) {
1953+ for constraint in path. iter ( ) {
1954+ let ConstraintCategory :: IllegalPlaceholder ( culprit_r) = constraint. category else {
1955+ continue ;
1956+ } ;
1957+
1958+ debug ! ( "{culprit_r:?} is the reason {from:?}: 'static!" ) ;
1959+ // FIXME: think: this may be for transitive reasons and
1960+ // we may have to do this arbitrarily many times. Or may we?
1961+ return self . find_constraint_path_to ( from, |r| r == culprit_r, false ) . unwrap ( ) ;
1962+ }
1963+ }
1964+ // No funny business; just return the path!
1965+ ( path, to)
1966+ }
1967+
1968+ /// Find interesting spans from bound placeholders' predicates
1969+ /// from a constraint path.
1970+ fn find_bound_region_predicate_span (
1971+ & self ,
1972+ path : & [ OutlivesConstraint < ' _ > ] ,
1973+ ) -> Vec < ExtraConstraintInfo > {
1974+ for constraint in path. iter ( ) {
1975+ let outlived = constraint. sub ;
1976+ let Some ( origin) = self . var_infos . get ( outlived) else {
1977+ continue ;
1978+ } ;
1979+ let RegionVariableOrigin :: Nll ( NllRegionVariableOrigin :: Placeholder ( p) ) = origin. origin
1980+ else {
1981+ continue ;
1982+ } ;
1983+ debug ! ( ?constraint, ?p) ;
1984+ let ConstraintCategory :: Predicate ( span) = constraint. category else {
1985+ continue ;
1986+ } ;
1987+ // We only want to point to one
1988+ return vec ! [ ExtraConstraintInfo :: PlaceholderFromPredicate ( span) ] ;
1989+ }
1990+ vec ! [ ]
1991+ }
1992+
19251993 /// Tries to find the best constraint to blame for the fact that
19261994 /// `to_region: from_region`.
19271995 /// This works by following the constraint graph,
@@ -1935,34 +2003,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
19352003 from_region_origin : NllRegionVariableOrigin ,
19362004 to_region : RegionVid ,
19372005 ) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
1938- let result = self . best_blame_constraint_ ( from_region, from_region_origin, to_region) ;
1939-
1940- // We are trying to blame an outlives-static constraint added
1941- // by an issue with placeholder regions. We figure out why the placeholder
1942- // region issue happened instead.
1943- if let ConstraintCategory :: IllegalPlaceholder ( offending_r) = result. 0 . category {
1944- debug ! ( "best_blame_constraint: placeholder issue caused by {offending_r:?}" ) ;
1945-
1946- if to_region == offending_r {
1947- // We do not want an infinite loop.
1948- return result;
1949- }
1950- return self . best_blame_constraint ( from_region, from_region_origin, offending_r) ;
1951- }
2006+ assert ! ( from_region != to_region, "Trying to blame a region for itself!" ) ;
19522007
1953- result
1954- }
2008+ let ( path, new_to_region) = self . path_to_modulo_placeholders ( from_region, to_region) ;
19552009
1956- #[ instrument( level = "debug" , skip( self ) ) ]
1957- pub ( crate ) fn best_blame_constraint_ (
1958- & self ,
1959- from_region : RegionVid ,
1960- from_region_origin : NllRegionVariableOrigin ,
1961- to_region : RegionVid ,
1962- ) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
1963- // Find all paths
1964- let ( path, target_region) =
1965- self . find_constraint_paths_between_regions ( from_region, |r| r == to_region) . unwrap ( ) ;
19662010 debug ! (
19672011 "path={:#?}" ,
19682012 path. iter( )
@@ -1975,24 +2019,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
19752019 . collect:: <Vec <_>>( )
19762020 ) ;
19772021
1978- let mut extra_info = vec ! [ ] ;
1979- for constraint in path. iter ( ) {
1980- let outlived = constraint. sub ;
1981- let Some ( origin) = self . var_infos . get ( outlived) else {
1982- continue ;
1983- } ;
1984- let RegionVariableOrigin :: Nll ( NllRegionVariableOrigin :: Placeholder ( p) ) = origin. origin
1985- else {
1986- continue ;
1987- } ;
1988- debug ! ( ?constraint, ?p) ;
1989- let ConstraintCategory :: Predicate ( span) = constraint. category else {
1990- continue ;
1991- } ;
1992- extra_info. push ( ExtraConstraintInfo :: PlaceholderFromPredicate ( span) ) ;
1993- // We only want to point to one
1994- break ;
1995- }
2022+ let extra_info = self . find_bound_region_predicate_span ( & path) ;
19962023
19972024 // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
19982025 // Instead, we use it to produce an improved `ObligationCauseCode`.
@@ -2043,7 +2070,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
20432070 // most likely to be the point where the value escapes -- but
20442071 // we still want to screen for an "interesting" point to
20452072 // highlight (e.g., a call site or something).
2046- let target_scc = self . constraint_sccs . scc ( target_region ) ;
2073+ let target_scc = self . constraint_sccs . scc ( new_to_region ) ;
20472074 let mut range = 0 ..path. len ( ) ;
20482075
20492076 // As noted above, when reporting an error, there is typically a chain of constraints
@@ -2240,6 +2267,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
22402267 fn scc_representative ( & self , scc : ConstraintSccIndex ) -> RegionVid {
22412268 self . constraint_sccs . annotation ( scc) . representative
22422269 }
2270+
2271+ /// Returns true if `r` is `'static`.
2272+ fn is_static ( & self , r : RegionVid ) -> bool {
2273+ r == self . universal_regions . fr_static
2274+ }
22432275}
22442276
22452277impl < ' tcx > RegionDefinition < ' tcx > {
0 commit comments