@@ -1777,18 +1777,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1777
1777
}
1778
1778
1779
1779
/// Walks the graph of constraints (where `'a: 'b` is considered
1780
- /// an edge `'a -> 'b`) to find all paths from `from_region` to
1781
- /// `to_region`. The paths are accumulated into the vector
1782
- /// `results`. The paths are stored as a series of
1783
- /// `ConstraintIndex` values -- in other words, a list of *edges*.
1784
- ///
1780
+ /// an edge `'a -> 'b`) to find a path from `from_region` to
1781
+ /// the first region `R` for which the predicate function
1782
+ /// `target_test` returns `true`.
1785
1783
/// Returns: a series of constraints as well as the region `R`
1786
1784
/// that passed the target test.
1785
+ /// If `include_static_outlives_all` is `true`, then the synthetic
1786
+ /// outlives constraints `'static -> a` for every region `a` are
1787
+ /// considered in the search, otherwise they are ignored.
1787
1788
#[ instrument( skip( self , target_test) , ret) ]
1788
- pub ( crate ) fn find_constraint_paths_between_regions (
1789
+ pub ( crate ) fn find_constraint_path_to (
1789
1790
& self ,
1790
1791
from_region : RegionVid ,
1791
1792
target_test : impl Fn ( RegionVid ) -> bool ,
1793
+ include_static_outlives_all : bool ,
1792
1794
) -> Option < ( Vec < OutlivesConstraint < ' tcx > > , RegionVid ) > {
1793
1795
let mut context = IndexVec :: from_elem ( Trace :: NotVisited , & self . definitions ) ;
1794
1796
context[ from_region] = Trace :: StartRegion ;
@@ -1801,7 +1803,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1801
1803
1802
1804
while let Some ( r) = deque. pop_front ( ) {
1803
1805
debug ! (
1804
- "find_constraint_paths_between_regions : from_region={:?} r={:?} value={}" ,
1806
+ "find_constraint_path_to : from_region={:?} r={:?} value={}" ,
1805
1807
from_region,
1806
1808
r,
1807
1809
self . region_value_str( r) ,
@@ -1837,7 +1839,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1837
1839
1838
1840
// A constraint like `'r: 'x` can come from our constraint
1839
1841
// graph.
1840
- let fr_static = self . universal_regions . fr_static ;
1842
+ let fr_static = if include_static_outlives_all {
1843
+ Some ( self . universal_regions . fr_static )
1844
+ } else {
1845
+ None
1846
+ } ;
1841
1847
let outgoing_edges_from_graph =
1842
1848
self . constraint_graph . outgoing_edges ( r, & self . constraints , fr_static) ;
1843
1849
@@ -1883,11 +1889,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1883
1889
pub ( crate ) fn find_sub_region_live_at ( & self , fr1 : RegionVid , location : Location ) -> RegionVid {
1884
1890
trace ! ( scc = ?self . constraint_sccs. scc( fr1) ) ;
1885
1891
trace ! ( universe = ?self . region_universe( fr1) ) ;
1886
- self . find_constraint_paths_between_regions ( fr1, |r| {
1892
+ self . find_constraint_path_to ( fr1, |r| {
1887
1893
// First look for some `r` such that `fr1: r` and `r` is live at `location`
1888
1894
trace ! ( ?r, liveness_constraints=?self . liveness_constraints. pretty_print_live_points( r) ) ;
1889
1895
self . liveness_constraints . is_live_at ( r, location)
1890
- } )
1896
+ } ,
1897
+ true
1898
+ )
1891
1899
. map ( |( _path, r) | r)
1892
1900
. unwrap ( )
1893
1901
}
@@ -1919,6 +1927,66 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1919
1927
self . universal_regions . as_ref ( )
1920
1928
}
1921
1929
1930
+ /// Find a path of outlives constraints from `from` to `to`,
1931
+ /// taking placeholder blame constraints into account, e.g.
1932
+ /// if there is a relationship where `r1` reaches `r2` and
1933
+ /// r2 has a larger universe or if r1 and r2 both come from
1934
+ /// placeholder regions.
1935
+ ///
1936
+ /// Returns the path and the target region, which may or may
1937
+ /// not be the original `to`. It panics if there is no such
1938
+ /// path.
1939
+ fn path_to_modulo_placeholders (
1940
+ & self ,
1941
+ from : RegionVid ,
1942
+ to : RegionVid ,
1943
+ ) -> ( Vec < OutlivesConstraint < ' tcx > > , RegionVid ) {
1944
+ let path = self . find_constraint_path_to ( from, |r| r == to, true ) . unwrap ( ) . 0 ;
1945
+
1946
+ // If we are looking for a path to 'static, and we are passing
1947
+ // through a constraint synthesised from an illegal placeholder
1948
+ // relation, redirect the search to the placeholder to blame.
1949
+ if self . is_static ( to) {
1950
+ for constraint in path. iter ( ) {
1951
+ let ConstraintCategory :: IllegalPlaceholder ( culprit_r) = constraint. category else {
1952
+ continue ;
1953
+ } ;
1954
+
1955
+ debug ! ( "{culprit_r:?} is the reason {from:?}: 'static!" ) ;
1956
+ // FIXME: think: this may be for transitive reasons and
1957
+ // we may have to do this arbitrarily many times. Or may we?
1958
+ return self . find_constraint_path_to ( from, |r| r == culprit_r, false ) . unwrap ( ) ;
1959
+ }
1960
+ }
1961
+ // No funny business; just return the path!
1962
+ ( path, to)
1963
+ }
1964
+
1965
+ /// Find interesting spans from bound placeholders' predicates
1966
+ /// from a constraint path.
1967
+ fn find_bound_region_predicate_span (
1968
+ & self ,
1969
+ path : & [ OutlivesConstraint < ' _ > ] ,
1970
+ ) -> Vec < ExtraConstraintInfo > {
1971
+ for constraint in path. iter ( ) {
1972
+ let outlived = constraint. sub ;
1973
+ let Some ( origin) = self . var_infos . get ( outlived) else {
1974
+ continue ;
1975
+ } ;
1976
+ let RegionVariableOrigin :: Nll ( NllRegionVariableOrigin :: Placeholder ( p) ) = origin. origin
1977
+ else {
1978
+ continue ;
1979
+ } ;
1980
+ debug ! ( ?constraint, ?p) ;
1981
+ let ConstraintCategory :: Predicate ( span) = constraint. category else {
1982
+ continue ;
1983
+ } ;
1984
+ // We only want to point to one
1985
+ return vec ! [ ExtraConstraintInfo :: PlaceholderFromPredicate ( span) ] ;
1986
+ }
1987
+ vec ! [ ]
1988
+ }
1989
+
1922
1990
/// Tries to find the best constraint to blame for the fact that
1923
1991
/// `to_region: from_region`.
1924
1992
/// This works by following the constraint graph,
@@ -1932,34 +2000,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1932
2000
from_region_origin : NllRegionVariableOrigin ,
1933
2001
to_region : RegionVid ,
1934
2002
) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
1935
- let result = self . best_blame_constraint_ ( from_region, from_region_origin, to_region) ;
1936
-
1937
- // We are trying to blame an outlives-static constraint added
1938
- // by an issue with placeholder regions. We figure out why the placeholder
1939
- // region issue happened instead.
1940
- if let ConstraintCategory :: IllegalPlaceholder ( offending_r) = result. 0 . category {
1941
- debug ! ( "best_blame_constraint: placeholder issue caused by {offending_r:?}" ) ;
1942
-
1943
- if to_region == offending_r {
1944
- // We do not want an infinite loop.
1945
- return result;
1946
- }
1947
- return self . best_blame_constraint ( from_region, from_region_origin, offending_r) ;
1948
- }
2003
+ assert ! ( from_region != to_region, "Trying to blame a region for itself!" ) ;
1949
2004
1950
- result
1951
- }
2005
+ let ( path, new_to_region) = self . path_to_modulo_placeholders ( from_region, to_region) ;
1952
2006
1953
- #[ instrument( level = "debug" , skip( self ) ) ]
1954
- pub ( crate ) fn best_blame_constraint_ (
1955
- & self ,
1956
- from_region : RegionVid ,
1957
- from_region_origin : NllRegionVariableOrigin ,
1958
- to_region : RegionVid ,
1959
- ) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
1960
- // Find all paths
1961
- let ( path, target_region) =
1962
- self . find_constraint_paths_between_regions ( from_region, |r| r == to_region) . unwrap ( ) ;
1963
2007
debug ! (
1964
2008
"path={:#?}" ,
1965
2009
path. iter( )
@@ -1972,24 +2016,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1972
2016
. collect:: <Vec <_>>( )
1973
2017
) ;
1974
2018
1975
- let mut extra_info = vec ! [ ] ;
1976
- for constraint in path. iter ( ) {
1977
- let outlived = constraint. sub ;
1978
- let Some ( origin) = self . var_infos . get ( outlived) else {
1979
- continue ;
1980
- } ;
1981
- let RegionVariableOrigin :: Nll ( NllRegionVariableOrigin :: Placeholder ( p) ) = origin. origin
1982
- else {
1983
- continue ;
1984
- } ;
1985
- debug ! ( ?constraint, ?p) ;
1986
- let ConstraintCategory :: Predicate ( span) = constraint. category else {
1987
- continue ;
1988
- } ;
1989
- extra_info. push ( ExtraConstraintInfo :: PlaceholderFromPredicate ( span) ) ;
1990
- // We only want to point to one
1991
- break ;
1992
- }
2019
+ let extra_info = self . find_bound_region_predicate_span ( & path) ;
1993
2020
1994
2021
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
1995
2022
// Instead, we use it to produce an improved `ObligationCauseCode`.
@@ -2040,7 +2067,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
2040
2067
// most likely to be the point where the value escapes -- but
2041
2068
// we still want to screen for an "interesting" point to
2042
2069
// highlight (e.g., a call site or something).
2043
- let target_scc = self . constraint_sccs . scc ( target_region ) ;
2070
+ let target_scc = self . constraint_sccs . scc ( new_to_region ) ;
2044
2071
let mut range = 0 ..path. len ( ) ;
2045
2072
2046
2073
// As noted above, when reporting an error, there is typically a chain of constraints
@@ -2237,6 +2264,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
2237
2264
fn scc_representative ( & self , scc : ConstraintSccIndex ) -> RegionVid {
2238
2265
self . constraint_sccs . annotation ( scc) . representative
2239
2266
}
2267
+
2268
+ /// Returns true if `r` is `'static`.
2269
+ fn is_static ( & self , r : RegionVid ) -> bool {
2270
+ r == self . universal_regions . fr_static
2271
+ }
2240
2272
}
2241
2273
2242
2274
impl < ' tcx > RegionDefinition < ' tcx > {
0 commit comments