11use std:: fmt;
22use std:: ops:: Index ;
33
4+ use rustc_data_structures:: fx:: FxHashSet ;
45use rustc_index:: { IndexSlice , IndexVec } ;
56use rustc_infer:: infer:: NllRegionVariableOrigin ;
67use rustc_middle:: mir:: ConstraintCategory ;
@@ -134,25 +135,22 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
134135 let fr_static = universal_regions. fr_static ;
135136 let sccs = self . compute_sccs ( fr_static, definitions) ;
136137
137- // Changed to `true` if we added any constraints to `self` and need to
138- // recompute SCCs.
139- let mut added_constraints = false ;
138+ // Is this SCC already outliving static directly or transitively?
139+ let mut outlives_static = FxHashSet :: default ( ) ;
140140
141- for scc in sccs. all_sccs ( ) {
142- let annotation = sccs. annotation ( scc) ;
141+ for ( scc, annotation) in sccs. all_annotations ( ) {
142+ if scc == sccs. scc ( fr_static) {
143+ // No use adding 'static: 'static.
144+ continue ;
145+ }
143146
144147 // If this SCC participates in a universe violation
145148 // e.g. if it reaches a region with a universe smaller than
146149 // the largest region reached, add a requirement that it must
147150 // outlive `'static`. Here we get to know which reachable region
148151 // caused the violation.
149152 if let Some ( to) = annotation. universe_violation ( ) {
150- // Optimisation opportunity: this will potentially add more constraints
151- // than needed for correctness, since an SCC upstream of another with
152- // a universe violation will "infect" its downstream SCCs to also
153- // outlive static. However, some of those may be useful for error
154- // reporting.
155- added_constraints = true ;
153+ outlives_static. insert ( scc) ;
156154 self . add_placeholder_violation_constraint (
157155 annotation. representative ,
158156 annotation. representative ,
@@ -162,19 +160,29 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
162160 }
163161 }
164162
163+ // Note: it's possible to sort this iterator by SCC and get dependency order,
164+ // which makes it easy to only add only one constraint per future cycle.
165+ // However, this worsens diagnostics and requires iterating over
166+ // all successors to determine if we outlive static transitively,
167+ // a cost you pay even if you have no placeholders.
168+ let placeholders_and_sccs =
169+ definitions. iter_enumerated ( ) . filter_map ( |( rvid, definition) | {
170+ if matches ! ( definition. origin, NllRegionVariableOrigin :: Placeholder { .. } ) {
171+ Some ( ( sccs. scc ( rvid) , rvid) )
172+ } else {
173+ None
174+ }
175+ } ) ;
176+
165177 // The second kind of violation: a placeholder reaching another placeholder.
166- // OPTIMIZATION: This one is even more optimisable since it adds constraints for every
167- // placeholder in an SCC.
168- for rvid in definitions. iter_enumerated ( ) . filter_map ( |( rvid, definition) | {
169- if matches ! ( definition. origin, NllRegionVariableOrigin :: Placeholder { .. } ) {
170- Some ( rvid)
171- } else {
172- None
173- }
174- } ) {
175- let scc = sccs. scc ( rvid) ;
178+ for ( scc, rvid) in placeholders_and_sccs {
176179 let annotation = sccs. annotation ( scc) ;
177180
181+ if sccs. scc ( fr_static) == scc || outlives_static. contains ( & scc) {
182+ debug ! ( "{:?} already outlives (or is) static" , annotation. representative) ;
183+ continue ;
184+ }
185+
178186 // Unwrap safety: since this is our SCC it must contain us, which is
179187 // at worst min AND max, but it has at least one or there is a bug.
180188 let min = annotation. min_reachable_placeholder . unwrap ( ) ;
@@ -193,7 +201,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
193201 debug ! (
194202 "Placeholder {rvid:?} of SCC {scc:?} reaches other placeholder {other_placeholder:?}"
195203 ) ;
196- added_constraints = true ;
204+ outlives_static . insert ( scc ) ;
197205 self . add_placeholder_violation_constraint (
198206 annotation. representative ,
199207 rvid,
@@ -202,7 +210,8 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
202210 ) ;
203211 }
204212
205- if added_constraints {
213+ if !outlives_static. is_empty ( ) {
214+ debug ! ( "The following SCCs had :'static constraints added: {:?}" , outlives_static) ;
206215 // We changed the constraint set and so must recompute SCCs.
207216 self . compute_sccs ( fr_static, definitions)
208217 } else {
0 commit comments