@@ -54,13 +54,25 @@ enum RepresentativeOrigin {
5454 Placeholder ,
5555 FreeRegion ,
5656}
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+ }
5768/// An annotation for region graph SCCs that tracks
5869/// the values of its elements.
5970#[ derive( Copy , Debug , Clone ) ]
6071pub struct RegionTracker {
6172 /// 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 ,
6476
6577 /// The smallest universe index reachable form the nodes of this SCC.
6678 min_reachable_universe : UniverseIndex ,
@@ -120,13 +132,16 @@ impl RegionTracker {
120132
121133 let rvid_is_placeholder = representative_origin == Placeholder ;
122134
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+ } ;
125140
126141 let representative_if_placeholder = if rvid_is_placeholder { Some ( rvid) } else { None } ;
127142
128143 Self {
129- max_placeholder_universe_reached : placeholder_universe ,
144+ max_universe_placeholder_reached ,
130145 min_reachable_universe : definition. universe ,
131146 representative : rvid,
132147 representative_origin,
@@ -191,21 +206,67 @@ impl RegionTracker {
191206 fn merge_min_max_seen ( & mut self , other : & Self ) {
192207 self . merge_reachable_placeholders ( other) ;
193208
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 ,
197212 ) ;
198213
199214 self . min_reachable_universe =
200215 std:: cmp:: min ( self . min_reachable_universe , other. min_reachable_universe ) ;
201216 }
202217
203- /// Returns `true` if the annotated SCC reaches a placeholder
218+ /// Returns an offending region if the annotated SCC reaches a placeholder
204219 /// 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
209270 }
210271}
211272
@@ -859,7 +920,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
859920
860921 // Otherwise, there can be no placeholder in `b` with a too high
861922 // 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+ }
863930 }
864931
865932 /// Once regions have been propagated, this method is used to see
@@ -1697,65 +1764,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16971764 }
16981765 }
16991766
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-
17491767 /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
17501768 pub ( crate ) fn find_outlives_blame_span (
17511769 & self ,
17521770 fr1 : RegionVid ,
17531771 fr1_origin : NllRegionVariableOrigin ,
17541772 fr2 : RegionVid ,
17551773 ) -> ( 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 ;
17591776 ( category, cause)
17601777 }
17611778
@@ -1837,10 +1854,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18371854
18381855 // This loop can be hot.
18391856 for constraint in outgoing_edges_from_graph {
1840- if matches ! ( constraint. category, ConstraintCategory :: IllegalUniverse ) {
1841- debug ! ( "Ignoring illegal universe constraint: {constraint:?}" ) ;
1842- continue ;
1843- }
18441857 handle_constraint ( constraint) ;
18451858 }
18461859
@@ -1875,30 +1888,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18751888 trace ! ( ?r, liveness_constraints=?self . liveness_constraints. pretty_print_live_points( r) ) ;
18761889 self . liveness_constraints . is_live_at ( r, location)
18771890 } )
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- } )
19021891 . map ( |( _path, r) | r)
19031892 . unwrap ( )
19041893 }
@@ -1931,21 +1920,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
19311920 }
19321921
19331922 /// 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,
19361925 /// creating a constraint path that forces `R` to outlive
19371926 /// `from_region`, and then finding the best choices within that
19381927 /// path to blame.
1939- #[ instrument( level = "debug" , skip( self , target_test ) ) ]
1928+ #[ instrument( level = "debug" , skip( self ) ) ]
19401929 pub ( crate ) fn best_blame_constraint (
19411930 & self ,
19421931 from_region : RegionVid ,
19431932 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 ,
19451959 ) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
19461960 // Find all paths
19471961 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 ( ) ;
19491963 debug ! (
19501964 "path={:#?}" ,
19511965 path. iter( )
0 commit comments