@@ -55,13 +55,25 @@ enum RepresentativeOrigin {
55
55
Placeholder ,
56
56
FreeRegion ,
57
57
}
58
+
59
+ /// A reachable placeholder. Note the lexicographic ordering ensures
60
+ /// that they are ordered by:
61
+ /// A placeholder is larger than no placeholder, then
62
+ /// by universe, then
63
+ /// by region ID.
64
+ #[ derive( Copy , Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
65
+ enum ReachablePlaceholder {
66
+ Nothing ,
67
+ Placeholder { universe : UniverseIndex , rvid : RegionVid } ,
68
+ }
58
69
/// An annotation for region graph SCCs that tracks
59
70
/// the values of its elements.
60
71
#[ derive( Copy , Debug , Clone ) ]
61
72
pub struct RegionTracker {
62
73
/// The largest universe of a placeholder reached from this SCC.
63
- /// This includes placeholders within this SCC.
64
- max_placeholder_universe_reached : UniverseIndex ,
74
+ /// This includes placeholders within this SCC. Including
75
+ /// the unverse's associated placeholder region ID.
76
+ max_universe_placeholder_reached : ReachablePlaceholder ,
65
77
66
78
/// The smallest universe index reachable form the nodes of this SCC.
67
79
min_reachable_universe : UniverseIndex ,
@@ -121,13 +133,16 @@ impl RegionTracker {
121
133
122
134
let rvid_is_placeholder = representative_origin == Placeholder ;
123
135
124
- let placeholder_universe =
125
- if rvid_is_placeholder { definition. universe } else { UniverseIndex :: ROOT } ;
136
+ let max_universe_placeholder_reached = if rvid_is_placeholder {
137
+ ReachablePlaceholder :: Placeholder { universe : definition. universe , rvid }
138
+ } else {
139
+ ReachablePlaceholder :: Nothing
140
+ } ;
126
141
127
142
let representative_if_placeholder = if rvid_is_placeholder { Some ( rvid) } else { None } ;
128
143
129
144
Self {
130
- max_placeholder_universe_reached : placeholder_universe ,
145
+ max_universe_placeholder_reached ,
131
146
min_reachable_universe : definition. universe ,
132
147
representative : rvid,
133
148
representative_origin,
@@ -192,21 +207,67 @@ impl RegionTracker {
192
207
fn merge_min_max_seen ( & mut self , other : & Self ) {
193
208
self . merge_reachable_placeholders ( other) ;
194
209
195
- self . max_placeholder_universe_reached = std:: cmp:: max (
196
- self . max_placeholder_universe_reached ,
197
- other. max_placeholder_universe_reached ,
210
+ self . max_universe_placeholder_reached = std:: cmp:: max (
211
+ self . max_universe_placeholder_reached ,
212
+ other. max_universe_placeholder_reached ,
198
213
) ;
199
214
200
215
self . min_reachable_universe =
201
216
std:: cmp:: min ( self . min_reachable_universe , other. min_reachable_universe ) ;
202
217
}
203
218
204
- /// Returns `true` if the annotated SCC reaches a placeholder
219
+ /// Returns an offending region if the annotated SCC reaches a placeholder
205
220
/// with a universe larger than the smallest reachable one,
206
- /// or if a placeholder reaches another placeholder, `false` otherwise.
207
- pub ( crate ) fn has_incompatible_universes ( & self ) -> bool {
208
- self . min_universe ( ) . cannot_name ( self . max_placeholder_universe_reached )
209
- || self . placeholder_reaches_placeholder ( )
221
+ /// or if a placeholder reaches another placeholder, `None` otherwise.
222
+ pub ( crate ) fn placeholder_violation (
223
+ & self ,
224
+ sccs : & Sccs < RegionVid , ConstraintSccIndex , Self > ,
225
+ ) -> Option < RegionVid > {
226
+ // Note: we arbitrarily prefer universe violations
227
+ // to placeholder-reaches-placeholder violations.
228
+ // violations.
229
+
230
+ // Case 1: a universe violation
231
+ if let ReachablePlaceholder :: Placeholder {
232
+ universe : max_reached_universe,
233
+ rvid : belonging_to_rvid,
234
+ } = self . max_universe_placeholder_reached
235
+ {
236
+ if self . min_universe ( ) . cannot_name ( max_reached_universe) {
237
+ return Some ( belonging_to_rvid) ;
238
+ }
239
+ }
240
+
241
+ // Case 2: a placeholder (in our SCC) reaches another placeholder
242
+ if self . placeholder_reaches_placeholder ( ) {
243
+ // We know that this SCC contains at least one placeholder
244
+ // and that at least two placeholders are reachable from
245
+ // this SCC.
246
+ //
247
+ // We try to pick one that isn't in our SCC, if possible.
248
+ // We *always* pick one that is not equal to the representative.
249
+
250
+ // Unwrap safety: we know both these values are Some, since
251
+ // there are two reachable placeholders at least.
252
+ let min_reachable = self . min_reachable_placeholder . unwrap ( ) ;
253
+
254
+ if sccs. scc ( min_reachable) != sccs. scc ( self . representative ) {
255
+ return Some ( min_reachable) ;
256
+ }
257
+
258
+ // Either the largest reachable placeholder is outside our SCC,
259
+ // or we *must* blame a placeholder in our SCC since the violation
260
+ // happens inside of it. It's slightly easier to always arbitrarily
261
+ // pick the largest one, so we do. This also nicely guarantees that
262
+ // we don't pick the representative, since the representative is the
263
+ // smallest placeholder by index in the SCC if it is a placeholder
264
+ // so in order for it to also be the largest reachable min would
265
+ // have to be equal to max, but then we would only have reached one
266
+ // placeholder.
267
+ return Some ( self . max_reachable_placeholder . unwrap ( ) ) ;
268
+ }
269
+
270
+ None
210
271
}
211
272
}
212
273
@@ -860,7 +921,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
860
921
861
922
// Otherwise, there can be no placeholder in `b` with a too high
862
923
// universe index to name from `a`.
863
- a_universe. can_name ( b_annotation. max_placeholder_universe_reached )
924
+ if let ReachablePlaceholder :: Placeholder { universe, .. } =
925
+ b_annotation. max_universe_placeholder_reached
926
+ {
927
+ a_universe. can_name ( universe)
928
+ } else {
929
+ true
930
+ }
864
931
}
865
932
866
933
/// Once regions have been propagated, this method is used to see
@@ -1698,65 +1765,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1698
1765
}
1699
1766
}
1700
1767
1701
- /// We have a constraint `fr1: fr2` that is not satisfied, where
1702
- /// `fr2` represents some universal region. Here, `r` is some
1703
- /// region where we know that `fr1: r` and this function has the
1704
- /// job of determining whether `r` is "to blame" for the fact that
1705
- /// `fr1: fr2` is required.
1706
- ///
1707
- /// This is true under two conditions:
1708
- ///
1709
- /// - `r == fr2`
1710
- /// - `fr2` is `'static` and `r` is some placeholder in a universe
1711
- /// that cannot be named by `fr1`; in that case, we will require
1712
- /// that `fr1: 'static` because it is the only way to `fr1: r` to
1713
- /// be satisfied. (See `add_incompatible_universe`.)
1714
- pub ( crate ) fn provides_universal_region (
1715
- & self ,
1716
- r : RegionVid ,
1717
- fr1 : RegionVid ,
1718
- fr2 : RegionVid ,
1719
- ) -> bool {
1720
- debug ! ( "provides_universal_region(r={:?}, fr1={:?}, fr2={:?})" , r, fr1, fr2) ;
1721
- let result = {
1722
- r == fr2 || {
1723
- fr2 == self . universal_regions . fr_static && self . cannot_name_placeholder ( fr1, r)
1724
- }
1725
- } ;
1726
- debug ! ( "provides_universal_region: result = {:?}" , result) ;
1727
- result
1728
- }
1729
-
1730
- /// If `r2` represents a placeholder region, then this returns
1731
- /// `true` if `r1` cannot name that placeholder in its
1732
- /// value; otherwise, returns `false`.
1733
- pub ( crate ) fn cannot_name_placeholder ( & self , r1 : RegionVid , r2 : RegionVid ) -> bool {
1734
- match self . definitions [ r2] . origin {
1735
- NllRegionVariableOrigin :: Placeholder ( placeholder) => {
1736
- let r1_universe = self . definitions [ r1] . universe ;
1737
- debug ! (
1738
- "cannot_name_value_of: universe1={r1_universe:?} placeholder={:?}" ,
1739
- placeholder
1740
- ) ;
1741
- r1_universe. cannot_name ( placeholder. universe )
1742
- }
1743
-
1744
- NllRegionVariableOrigin :: FreeRegion | NllRegionVariableOrigin :: Existential { .. } => {
1745
- false
1746
- }
1747
- }
1748
- }
1749
-
1750
1768
/// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
1751
1769
pub ( crate ) fn find_outlives_blame_span (
1752
1770
& self ,
1753
1771
fr1 : RegionVid ,
1754
1772
fr1_origin : NllRegionVariableOrigin ,
1755
1773
fr2 : RegionVid ,
1756
1774
) -> ( ConstraintCategory < ' tcx > , ObligationCause < ' tcx > ) {
1757
- let BlameConstraint { category, cause, .. } = self
1758
- . best_blame_constraint ( fr1, fr1_origin, |r| self . provides_universal_region ( r, fr1, fr2) )
1759
- . 0 ;
1775
+ let BlameConstraint { category, cause, .. } =
1776
+ self . best_blame_constraint ( fr1, fr1_origin, fr2) . 0 ;
1760
1777
( category, cause)
1761
1778
}
1762
1779
@@ -1838,10 +1855,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1838
1855
1839
1856
// This loop can be hot.
1840
1857
for constraint in outgoing_edges_from_graph {
1841
- if matches ! ( constraint. category, ConstraintCategory :: IllegalUniverse ) {
1842
- debug ! ( "Ignoring illegal universe constraint: {constraint:?}" ) ;
1843
- continue ;
1844
- }
1845
1858
handle_constraint ( constraint) ;
1846
1859
}
1847
1860
@@ -1876,30 +1889,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1876
1889
trace ! ( ?r, liveness_constraints=?self . liveness_constraints. pretty_print_live_points( r) ) ;
1877
1890
self . liveness_constraints . is_live_at ( r, location)
1878
1891
} )
1879
- . or_else ( || {
1880
- // If we fail to find that, we may find some `r` such that
1881
- // `fr1: r` and `r` is a placeholder from some universe
1882
- // `fr1` cannot name. This would force `fr1` to be
1883
- // `'static`.
1884
- self . find_constraint_paths_between_regions ( fr1, |r| {
1885
- self . cannot_name_placeholder ( fr1, r)
1886
- } )
1887
- } )
1888
- . or_else ( || {
1889
- // If we fail to find THAT, it may be that `fr1` is a
1890
- // placeholder that cannot "fit" into its SCC. In that
1891
- // case, there should be some `r` where `fr1: r` and `fr1` is a
1892
- // placeholder that `r` cannot name. We can blame that
1893
- // edge.
1894
- //
1895
- // Remember that if `R1: R2`, then the universe of R1
1896
- // must be able to name the universe of R2, because R2 will
1897
- // be at least `'empty(Universe(R2))`, and `R1` must be at
1898
- // larger than that.
1899
- self . find_constraint_paths_between_regions ( fr1, |r| {
1900
- self . cannot_name_placeholder ( r, fr1)
1901
- } )
1902
- } )
1903
1892
. map ( |( _path, r) | r)
1904
1893
. unwrap ( )
1905
1894
}
@@ -1932,21 +1921,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1932
1921
}
1933
1922
1934
1923
/// Tries to find the best constraint to blame for the fact that
1935
- /// `R : from_region`, where `R` is some region that meets
1936
- /// `target_test`. This works by following the constraint graph,
1924
+ /// `to_region : from_region`.
1925
+ /// This works by following the constraint graph,
1937
1926
/// creating a constraint path that forces `R` to outlive
1938
1927
/// `from_region`, and then finding the best choices within that
1939
1928
/// path to blame.
1940
- #[ instrument( level = "debug" , skip( self , target_test ) ) ]
1929
+ #[ instrument( level = "debug" , skip( self ) ) ]
1941
1930
pub ( crate ) fn best_blame_constraint (
1942
1931
& self ,
1943
1932
from_region : RegionVid ,
1944
1933
from_region_origin : NllRegionVariableOrigin ,
1945
- target_test : impl Fn ( RegionVid ) -> bool ,
1934
+ to_region : RegionVid ,
1935
+ ) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
1936
+ let result = self . best_blame_constraint_ ( from_region, from_region_origin, to_region) ;
1937
+
1938
+ // We are trying to blame an outlives-static constraint added
1939
+ // by an issue with placeholder regions. We figure out why the placeholder
1940
+ // region issue happened instead.
1941
+ if let ConstraintCategory :: IllegalPlaceholder ( offending_r) = result. 0 . category {
1942
+ debug ! ( "best_blame_constraint: placeholder issue caused by {offending_r:?}" ) ;
1943
+
1944
+ if to_region == offending_r {
1945
+ // We do not want an infinite loop.
1946
+ return result;
1947
+ }
1948
+ return self . best_blame_constraint ( from_region, from_region_origin, offending_r) ;
1949
+ }
1950
+
1951
+ result
1952
+ }
1953
+
1954
+ #[ instrument( level = "debug" , skip( self ) ) ]
1955
+ pub ( crate ) fn best_blame_constraint_ (
1956
+ & self ,
1957
+ from_region : RegionVid ,
1958
+ from_region_origin : NllRegionVariableOrigin ,
1959
+ to_region : RegionVid ,
1946
1960
) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
1947
1961
// Find all paths
1948
1962
let ( path, target_region) =
1949
- self . find_constraint_paths_between_regions ( from_region, target_test ) . unwrap ( ) ;
1963
+ self . find_constraint_paths_between_regions ( from_region, |r| r == to_region ) . unwrap ( ) ;
1950
1964
debug ! (
1951
1965
"path={:#?}" ,
1952
1966
path. iter( )
0 commit comments