@@ -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
@@ -862,7 +923,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
862
923
863
924
// Otherwise, there can be no placeholder in `b` with a too high
864
925
// universe index to name from `a`.
865
- a_universe. can_name ( b_annotation. max_placeholder_universe_reached )
926
+ if let ReachablePlaceholder :: Placeholder { universe, .. } =
927
+ b_annotation. max_universe_placeholder_reached
928
+ {
929
+ a_universe. can_name ( universe)
930
+ } else {
931
+ true
932
+ }
866
933
}
867
934
868
935
/// Once regions have been propagated, this method is used to see
@@ -1700,65 +1767,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1700
1767
}
1701
1768
}
1702
1769
1703
- /// We have a constraint `fr1: fr2` that is not satisfied, where
1704
- /// `fr2` represents some universal region. Here, `r` is some
1705
- /// region where we know that `fr1: r` and this function has the
1706
- /// job of determining whether `r` is "to blame" for the fact that
1707
- /// `fr1: fr2` is required.
1708
- ///
1709
- /// This is true under two conditions:
1710
- ///
1711
- /// - `r == fr2`
1712
- /// - `fr2` is `'static` and `r` is some placeholder in a universe
1713
- /// that cannot be named by `fr1`; in that case, we will require
1714
- /// that `fr1: 'static` because it is the only way to `fr1: r` to
1715
- /// be satisfied. (See `add_incompatible_universe`.)
1716
- pub ( crate ) fn provides_universal_region (
1717
- & self ,
1718
- r : RegionVid ,
1719
- fr1 : RegionVid ,
1720
- fr2 : RegionVid ,
1721
- ) -> bool {
1722
- debug ! ( "provides_universal_region(r={:?}, fr1={:?}, fr2={:?})" , r, fr1, fr2) ;
1723
- let result = {
1724
- r == fr2 || {
1725
- fr2 == self . universal_regions . fr_static && self . cannot_name_placeholder ( fr1, r)
1726
- }
1727
- } ;
1728
- debug ! ( "provides_universal_region: result = {:?}" , result) ;
1729
- result
1730
- }
1731
-
1732
- /// If `r2` represents a placeholder region, then this returns
1733
- /// `true` if `r1` cannot name that placeholder in its
1734
- /// value; otherwise, returns `false`.
1735
- pub ( crate ) fn cannot_name_placeholder ( & self , r1 : RegionVid , r2 : RegionVid ) -> bool {
1736
- match self . definitions [ r2] . origin {
1737
- NllRegionVariableOrigin :: Placeholder ( placeholder) => {
1738
- let r1_universe = self . definitions [ r1] . universe ;
1739
- debug ! (
1740
- "cannot_name_value_of: universe1={r1_universe:?} placeholder={:?}" ,
1741
- placeholder
1742
- ) ;
1743
- r1_universe. cannot_name ( placeholder. universe )
1744
- }
1745
-
1746
- NllRegionVariableOrigin :: FreeRegion | NllRegionVariableOrigin :: Existential { .. } => {
1747
- false
1748
- }
1749
- }
1750
- }
1751
-
1752
1770
/// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
1753
1771
pub ( crate ) fn find_outlives_blame_span (
1754
1772
& self ,
1755
1773
fr1 : RegionVid ,
1756
1774
fr1_origin : NllRegionVariableOrigin ,
1757
1775
fr2 : RegionVid ,
1758
1776
) -> ( ConstraintCategory < ' tcx > , ObligationCause < ' tcx > ) {
1759
- let BlameConstraint { category, cause, .. } = self
1760
- . best_blame_constraint ( fr1, fr1_origin, |r| self . provides_universal_region ( r, fr1, fr2) )
1761
- . 0 ;
1777
+ let BlameConstraint { category, cause, .. } =
1778
+ self . best_blame_constraint ( fr1, fr1_origin, fr2) . 0 ;
1762
1779
( category, cause)
1763
1780
}
1764
1781
@@ -1840,10 +1857,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1840
1857
1841
1858
// This loop can be hot.
1842
1859
for constraint in outgoing_edges_from_graph {
1843
- if matches ! ( constraint. category, ConstraintCategory :: IllegalUniverse ) {
1844
- debug ! ( "Ignoring illegal universe constraint: {constraint:?}" ) ;
1845
- continue ;
1846
- }
1847
1860
handle_constraint ( constraint) ;
1848
1861
}
1849
1862
@@ -1878,30 +1891,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1878
1891
trace ! ( ?r, liveness_constraints=?self . liveness_constraints. pretty_print_live_points( r) ) ;
1879
1892
self . liveness_constraints . is_live_at ( r, location)
1880
1893
} )
1881
- . or_else ( || {
1882
- // If we fail to find that, we may find some `r` such that
1883
- // `fr1: r` and `r` is a placeholder from some universe
1884
- // `fr1` cannot name. This would force `fr1` to be
1885
- // `'static`.
1886
- self . find_constraint_paths_between_regions ( fr1, |r| {
1887
- self . cannot_name_placeholder ( fr1, r)
1888
- } )
1889
- } )
1890
- . or_else ( || {
1891
- // If we fail to find THAT, it may be that `fr1` is a
1892
- // placeholder that cannot "fit" into its SCC. In that
1893
- // case, there should be some `r` where `fr1: r` and `fr1` is a
1894
- // placeholder that `r` cannot name. We can blame that
1895
- // edge.
1896
- //
1897
- // Remember that if `R1: R2`, then the universe of R1
1898
- // must be able to name the universe of R2, because R2 will
1899
- // be at least `'empty(Universe(R2))`, and `R1` must be at
1900
- // larger than that.
1901
- self . find_constraint_paths_between_regions ( fr1, |r| {
1902
- self . cannot_name_placeholder ( r, fr1)
1903
- } )
1904
- } )
1905
1894
. map ( |( _path, r) | r)
1906
1895
. unwrap ( )
1907
1896
}
@@ -1934,21 +1923,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1934
1923
}
1935
1924
1936
1925
/// Tries to find the best constraint to blame for the fact that
1937
- /// `R : from_region`, where `R` is some region that meets
1938
- /// `target_test`. This works by following the constraint graph,
1926
+ /// `to_region : from_region`.
1927
+ /// This works by following the constraint graph,
1939
1928
/// creating a constraint path that forces `R` to outlive
1940
1929
/// `from_region`, and then finding the best choices within that
1941
1930
/// path to blame.
1942
- #[ instrument( level = "debug" , skip( self , target_test ) ) ]
1931
+ #[ instrument( level = "debug" , skip( self ) ) ]
1943
1932
pub ( crate ) fn best_blame_constraint (
1944
1933
& self ,
1945
1934
from_region : RegionVid ,
1946
1935
from_region_origin : NllRegionVariableOrigin ,
1947
- target_test : impl Fn ( RegionVid ) -> bool ,
1936
+ to_region : RegionVid ,
1937
+ ) -> ( 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
+ }
1952
+
1953
+ result
1954
+ }
1955
+
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 ,
1948
1962
) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
1949
1963
// Find all paths
1950
1964
let ( path, target_region) =
1951
- self . find_constraint_paths_between_regions ( from_region, target_test ) . unwrap ( ) ;
1965
+ self . find_constraint_paths_between_regions ( from_region, |r| r == to_region ) . unwrap ( ) ;
1952
1966
debug ! (
1953
1967
"path={:#?}" ,
1954
1968
path. iter( )
0 commit comments