@@ -55,13 +55,25 @@ enum RepresentativeOrigin {
5555 Placeholder ,
5656 FreeRegion ,
5757}
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+ }
5869/// An annotation for region graph SCCs that tracks
5970/// the values of its elements.
6071#[ derive( Copy , Debug , Clone ) ]
6172pub struct RegionTracker {
6273 /// 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 ,
6577
6678 /// The smallest universe index reachable form the nodes of this SCC.
6779 min_reachable_universe : UniverseIndex ,
@@ -121,13 +133,16 @@ impl RegionTracker {
121133
122134 let rvid_is_placeholder = representative_origin == Placeholder ;
123135
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+ } ;
126141
127142 let representative_if_placeholder = if rvid_is_placeholder { Some ( rvid) } else { None } ;
128143
129144 Self {
130- max_placeholder_universe_reached : placeholder_universe ,
145+ max_universe_placeholder_reached ,
131146 min_reachable_universe : definition. universe ,
132147 representative : rvid,
133148 representative_origin,
@@ -192,21 +207,67 @@ impl RegionTracker {
192207 fn merge_min_max_seen ( & mut self , other : & Self ) {
193208 self . merge_reachable_placeholders ( other) ;
194209
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 ,
198213 ) ;
199214
200215 self . min_reachable_universe =
201216 std:: cmp:: min ( self . min_reachable_universe , other. min_reachable_universe ) ;
202217 }
203218
204- /// Returns `true` if the annotated SCC reaches a placeholder
219+ /// Returns an offending region if the annotated SCC reaches a placeholder
205220 /// 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
210271 }
211272}
212273
@@ -862,7 +923,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
862923
863924 // Otherwise, there can be no placeholder in `b` with a too high
864925 // 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+ }
866933 }
867934
868935 /// Once regions have been propagated, this method is used to see
@@ -1700,65 +1767,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
17001767 }
17011768 }
17021769
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-
17521770 /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
17531771 pub ( crate ) fn find_outlives_blame_span (
17541772 & self ,
17551773 fr1 : RegionVid ,
17561774 fr1_origin : NllRegionVariableOrigin ,
17571775 fr2 : RegionVid ,
17581776 ) -> ( 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 ;
17621779 ( category, cause)
17631780 }
17641781
@@ -1840,10 +1857,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18401857
18411858 // This loop can be hot.
18421859 for constraint in outgoing_edges_from_graph {
1843- if matches ! ( constraint. category, ConstraintCategory :: IllegalUniverse ) {
1844- debug ! ( "Ignoring illegal universe constraint: {constraint:?}" ) ;
1845- continue ;
1846- }
18471860 handle_constraint ( constraint) ;
18481861 }
18491862
@@ -1878,30 +1891,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
18781891 trace ! ( ?r, liveness_constraints=?self . liveness_constraints. pretty_print_live_points( r) ) ;
18791892 self . liveness_constraints . is_live_at ( r, location)
18801893 } )
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- } )
19051894 . map ( |( _path, r) | r)
19061895 . unwrap ( )
19071896 }
@@ -1934,21 +1923,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
19341923 }
19351924
19361925 /// 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,
19391928 /// creating a constraint path that forces `R` to outlive
19401929 /// `from_region`, and then finding the best choices within that
19411930 /// path to blame.
1942- #[ instrument( level = "debug" , skip( self , target_test ) ) ]
1931+ #[ instrument( level = "debug" , skip( self ) ) ]
19431932 pub ( crate ) fn best_blame_constraint (
19441933 & self ,
19451934 from_region : RegionVid ,
19461935 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 ,
19481962 ) -> ( BlameConstraint < ' tcx > , Vec < ExtraConstraintInfo > ) {
19491963 // Find all paths
19501964 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 ( ) ;
19521966 debug ! (
19531967 "path={:#?}" ,
19541968 path. iter( )
0 commit comments