@@ -24,10 +24,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
24
24
/// coherence and elsewhere -- see #56105 and #59490 for more details. The
25
25
/// eventual fate of the leak checker is not yet settled.
26
26
///
27
- /// The leak checker works by searching for the following error patterns :
27
+ /// The leak checker works by searching for the following error pattern :
28
28
///
29
- /// * P1: P2, where P1 != P2
30
- /// * P1: R, where R is in some universe that cannot name P1
29
+ /// * P: R, where R is in some universe that cannot name P
31
30
///
32
31
/// The idea here is that each of these patterns represents something that
33
32
/// the region solver would eventually report as an error, so we can detect
@@ -45,16 +44,16 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
45
44
/// For each SCC S, we compute:
46
45
///
47
46
/// * what placeholder P it must be equal to, if any
48
- /// * if there are multiple placeholders that must be equal, report an error because `P1: P2`
47
+ /// * if there are multiple placeholders that must be equal, we pick the one with the higher
48
+ /// universe. It will eventually be an error in the next step if the placeholders are in
49
+ /// different universes.
49
50
/// * the minimum universe of its constituents
50
51
///
51
52
/// Then we walk the SCCs in dependency order and compute
52
53
///
53
- /// * what placeholder they must outlive transitively
54
- /// * if they must also be equal to a placeholder, report an error because `P1: P2`
55
54
/// * minimum universe U of all SCCs they must outlive
56
- /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
57
- /// indicates `P: R` and `R` is in an incompatible universe
55
+ /// * if the SCC must also be equal to a placeholder P, and U cannot name P, report an error,
56
+ /// as that indicates `P: R` and `R` is in a universe that cannot name P
58
57
///
59
58
/// To improve performance and for the old trait solver caching to be sound, this takes
60
59
/// an optional snapshot in which case we only look at region constraints added in that
@@ -69,6 +68,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
69
68
///
70
69
/// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n
71
70
/// * R: P1, R: P2, as above
71
+ /// * P1: P2, when P2 lives in a universe that *can* name P1.
72
72
#[ instrument( level = "debug" , skip( self , tcx, only_consider_snapshot) , ret) ]
73
73
pub fn leak_check (
74
74
& mut self ,
@@ -83,26 +83,18 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
83
83
84
84
let mini_graph = & MiniGraph :: new ( tcx, & self , only_consider_snapshot) ;
85
85
86
- let mut leak_check = LeakCheck :: new ( tcx, outer_universe, max_universe, mini_graph, self ) ;
87
- leak_check. assign_placeholder_values ( ) ?;
88
- leak_check. propagate_scc_value ( ) ?;
89
- Ok ( ( ) )
86
+ let mut leak_check = LeakCheck :: new ( mini_graph, self ) ;
87
+ leak_check. assign_placeholder_values ( ) ;
88
+ leak_check. propagate_scc_value ( )
90
89
}
91
90
}
92
91
93
92
struct LeakCheck < ' me , ' tcx > {
94
- tcx : TyCtxt < ' tcx > ,
95
- outer_universe : ty:: UniverseIndex ,
96
93
mini_graph : & ' me MiniGraph < ' tcx > ,
97
94
rcc : & ' me RegionConstraintCollector < ' me , ' tcx > ,
98
95
99
96
// Initially, for each SCC S, stores a placeholder `P` such that `S = P`
100
97
// must hold.
101
- //
102
- // Later, during the [`LeakCheck::propagate_scc_value`] function, this array
103
- // is repurposed to store some placeholder `P` such that the weaker
104
- // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1
105
- // = P`.)
106
98
scc_placeholders : IndexVec < LeakCheckScc , Option < ty:: PlaceholderRegion > > ,
107
99
108
100
// For each SCC S, track the minimum universe that flows into it. Note that
@@ -119,16 +111,11 @@ struct LeakCheck<'me, 'tcx> {
119
111
120
112
impl < ' me , ' tcx > LeakCheck < ' me , ' tcx > {
121
113
fn new (
122
- tcx : TyCtxt < ' tcx > ,
123
- outer_universe : ty:: UniverseIndex ,
124
- max_universe : ty:: UniverseIndex ,
125
114
mini_graph : & ' me MiniGraph < ' tcx > ,
126
115
rcc : & ' me RegionConstraintCollector < ' me , ' tcx > ,
127
116
) -> Self {
128
- let dummy_scc_universe = SccUniverse { universe : max_universe , region : None } ;
117
+ let dummy_scc_universe = SccUniverse { universe : ty :: UniverseIndex :: MAX , region : None } ;
129
118
Self {
130
- tcx,
131
- outer_universe,
132
119
mini_graph,
133
120
rcc,
134
121
scc_placeholders : IndexVec :: from_elem_n ( None , mini_graph. sccs . num_sccs ( ) ) ,
@@ -138,7 +125,7 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
138
125
139
126
/// Compute what placeholders (if any) each SCC must be equal to.
140
127
/// Also compute the minimum universe of all the regions in each SCC.
141
- fn assign_placeholder_values ( & mut self ) -> RelateResult < ' tcx , ( ) > {
128
+ fn assign_placeholder_values ( & mut self ) {
142
129
// First walk: find each placeholder that is from a newly created universe.
143
130
for ( region, leak_check_node) in & self . mini_graph . nodes {
144
131
let scc = self . mini_graph . sccs . scc ( * leak_check_node) ;
@@ -152,34 +139,14 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
152
139
self . scc_universes [ scc] . take_min ( universe, * region) ;
153
140
154
141
// Detect those SCCs that directly contain a placeholder
155
- if let ty:: RePlaceholder ( placeholder) = * * region {
156
- if self . outer_universe . cannot_name ( placeholder. universe ) {
157
- self . assign_scc_value ( scc, placeholder) ?;
158
- }
142
+ if let ty:: RePlaceholder ( p1) = * * region {
143
+ let max_placeholder = match self . scc_placeholders [ scc] {
144
+ Some ( p2) => std:: cmp:: max_by_key ( p1, p2, |p| p. universe ) ,
145
+ None => p1,
146
+ } ;
147
+ self . scc_placeholders [ scc] = Some ( max_placeholder) ;
159
148
}
160
149
}
161
-
162
- Ok ( ( ) )
163
- }
164
-
165
- // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
166
- // This may create an error.
167
- fn assign_scc_value (
168
- & mut self ,
169
- scc : LeakCheckScc ,
170
- placeholder : ty:: PlaceholderRegion ,
171
- ) -> RelateResult < ' tcx , ( ) > {
172
- match self . scc_placeholders [ scc] {
173
- Some ( p) => {
174
- assert_ne ! ( p, placeholder) ;
175
- return Err ( self . placeholder_error ( p, placeholder) ) ;
176
- }
177
- None => {
178
- self . scc_placeholders [ scc] = Some ( placeholder) ;
179
- }
180
- } ;
181
-
182
- Ok ( ( ) )
183
150
}
184
151
185
152
/// For each SCC S, iterate over each successor S1 where `S: S1`:
@@ -201,8 +168,6 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
201
168
//
202
169
// For each successor `scc2` where `scc1: scc2`:
203
170
//
204
- // * `scc_placeholder[scc2]` stores some placeholder `P` where
205
- // `scc2: P` (if any)
206
171
// * `scc_universes[scc2]` contains the minimum universe of the
207
172
// constituents of `scc2` and any of its successors
208
173
for scc1 in self . mini_graph . sccs . all_sccs ( ) {
@@ -214,19 +179,12 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
214
179
// Walk over each `scc2` such that `scc1: scc2` and compute:
215
180
//
216
181
// * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
217
- // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
218
- // we pick one arbitrarily)
219
182
let mut scc1_universe = self . scc_universes [ scc1] ;
220
- let mut succ_bound = None ;
221
183
for & scc2 in self . mini_graph . sccs . successors ( scc1) {
222
184
let SccUniverse { universe : scc2_universe, region : scc2_region } =
223
185
self . scc_universes [ scc2] ;
224
186
225
187
scc1_universe. take_min ( scc2_universe, scc2_region. unwrap ( ) ) ;
226
-
227
- if let Some ( b) = self . scc_placeholders [ scc2] {
228
- succ_bound = Some ( b) ;
229
- }
230
188
}
231
189
232
190
// Update minimum universe of scc1.
@@ -245,32 +203,11 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
245
203
if scc1_universe. universe . cannot_name ( scc1_placeholder. universe ) {
246
204
return Err ( self . error ( scc1_placeholder, scc1_universe. region . unwrap ( ) ) ) ;
247
205
}
248
-
249
- // Check if we have some placeholder where `S: P2`
250
- // (transitively). In that case, since `S = P1`, that implies
251
- // `P1: P2`, which is an error condition.
252
- if let Some ( scc2_placeholder) = succ_bound {
253
- assert_ne ! ( scc1_placeholder, scc2_placeholder) ;
254
- return Err ( self . placeholder_error ( scc1_placeholder, scc2_placeholder) ) ;
255
- }
256
- } else {
257
- // Otherwise, we can reach a placeholder if some successor can.
258
- self . scc_placeholders [ scc1] = succ_bound;
259
206
}
260
-
261
- // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
262
207
}
263
208
Ok ( ( ) )
264
209
}
265
210
266
- fn placeholder_error (
267
- & self ,
268
- placeholder1 : ty:: PlaceholderRegion ,
269
- placeholder2 : ty:: PlaceholderRegion ,
270
- ) -> TypeError < ' tcx > {
271
- self . error ( placeholder1, ty:: Region :: new_placeholder ( self . tcx , placeholder2) )
272
- }
273
-
274
211
fn error (
275
212
& self ,
276
213
placeholder : ty:: PlaceholderRegion ,
0 commit comments