1
1
use std:: fmt;
2
2
use std:: ops:: Index ;
3
3
4
+ use rustc_data_structures:: fx:: FxHashSet ;
4
5
use rustc_index:: { IndexSlice , IndexVec } ;
5
6
use rustc_infer:: infer:: NllRegionVariableOrigin ;
6
7
use rustc_middle:: mir:: ConstraintCategory ;
@@ -134,25 +135,22 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
134
135
let fr_static = universal_regions. fr_static ;
135
136
let sccs = self . compute_sccs ( fr_static, definitions) ;
136
137
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 ( ) ;
140
140
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
+ }
143
146
144
147
// If this SCC participates in a universe violation
145
148
// e.g. if it reaches a region with a universe smaller than
146
149
// the largest region reached, add a requirement that it must
147
150
// outlive `'static`. Here we get to know which reachable region
148
151
// caused the violation.
149
152
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) ;
156
154
self . add_placeholder_violation_constraint (
157
155
annotation. representative ,
158
156
annotation. representative ,
@@ -162,19 +160,29 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
162
160
}
163
161
}
164
162
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
+
165
177
// 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 {
176
179
let annotation = sccs. annotation ( scc) ;
177
180
181
+ if sccs. scc ( fr_static) == scc || outlives_static. contains ( & scc) {
182
+ debug ! ( "{:?} already outlives (or is) static" , annotation. representative) ;
183
+ continue ;
184
+ }
185
+
178
186
// Unwrap safety: since this is our SCC it must contain us, which is
179
187
// at worst min AND max, but it has at least one or there is a bug.
180
188
let min = annotation. min_reachable_placeholder . unwrap ( ) ;
@@ -193,7 +201,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
193
201
debug ! (
194
202
"Placeholder {rvid:?} of SCC {scc:?} reaches other placeholder {other_placeholder:?}"
195
203
) ;
196
- added_constraints = true ;
204
+ outlives_static . insert ( scc ) ;
197
205
self . add_placeholder_violation_constraint (
198
206
annotation. representative ,
199
207
rvid,
@@ -202,7 +210,8 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
202
210
) ;
203
211
}
204
212
205
- if added_constraints {
213
+ if !outlives_static. is_empty ( ) {
214
+ debug ! ( "The following SCCs had :'static constraints added: {:?}" , outlives_static) ;
206
215
// We changed the constraint set and so must recompute SCCs.
207
216
self . compute_sccs ( fr_static, definitions)
208
217
} else {
0 commit comments