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