@@ -57,12 +57,7 @@ pub struct FulfillmentContext<'tcx> {
57
57
58
58
// A list of all obligations that have been registered with this
59
59
// fulfillment context.
60
- predicates : Vec < PredicateObligation < ' tcx > > ,
61
-
62
- // Remembers the count of trait obligations that we have already
63
- // attempted to select. This is used to avoid repeating work
64
- // when `select_new_obligations` is called.
65
- attempted_mark : usize ,
60
+ predicates : Vec < PendingPredicateObligation < ' tcx > > ,
66
61
67
62
// A set of constraints that regionck must validate. Each
68
63
// constraint has the form `T:'a`, meaning "some type `T` must
@@ -100,6 +95,12 @@ pub struct RegionObligation<'tcx> {
100
95
pub cause : ObligationCause < ' tcx > ,
101
96
}
102
97
98
+ #[ derive( Clone , Debug ) ]
99
+ pub struct PendingPredicateObligation < ' tcx > {
100
+ pub obligation : PredicateObligation < ' tcx > ,
101
+ pub stalled_on : Vec < Ty < ' tcx > > ,
102
+ }
103
+
103
104
impl < ' tcx > FulfillmentContext < ' tcx > {
104
105
/// Creates a new fulfillment context.
105
106
///
@@ -122,7 +123,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
122
123
FulfillmentContext {
123
124
duplicate_set : FulfilledPredicates :: new ( ) ,
124
125
predicates : Vec :: new ( ) ,
125
- attempted_mark : 0 ,
126
126
region_obligations : NodeMap ( ) ,
127
127
errors_will_be_reported : errors_will_be_reported,
128
128
}
@@ -198,6 +198,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
198
198
}
199
199
200
200
debug ! ( "register_predicate({:?})" , obligation) ;
201
+ let obligation = PendingPredicateObligation {
202
+ obligation : obligation,
203
+ stalled_on : vec ! [ ]
204
+ } ;
201
205
self . predicates . push ( obligation) ;
202
206
}
203
207
@@ -221,7 +225,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
221
225
let errors: Vec < FulfillmentError > =
222
226
self . predicates
223
227
. iter ( )
224
- . map ( |o| FulfillmentError :: new ( ( * o ) . clone ( ) , CodeAmbiguity ) )
228
+ . map ( |o| FulfillmentError :: new ( o . obligation . clone ( ) , CodeAmbiguity ) )
225
229
. collect ( ) ;
226
230
227
231
if errors. is_empty ( ) {
@@ -231,18 +235,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
231
235
}
232
236
}
233
237
234
- /// Attempts to select obligations that were registered since the call to a selection routine.
235
- /// This is used by the type checker to eagerly attempt to resolve obligations in hopes of
236
- /// gaining type information. It'd be equally valid to use `select_where_possible` but it
237
- /// results in `O(n^2)` performance (#18208).
238
- pub fn select_new_obligations < ' a > ( & mut self ,
239
- infcx : & InferCtxt < ' a , ' tcx > )
240
- -> Result < ( ) , Vec < FulfillmentError < ' tcx > > >
241
- {
242
- let mut selcx = SelectionContext :: new ( infcx) ;
243
- self . select ( & mut selcx, true )
244
- }
245
-
246
238
pub fn select_where_possible < ' a > ( & mut self ,
247
239
infcx : & InferCtxt < ' a , ' tcx > )
248
240
-> Result < ( ) , Vec < FulfillmentError < ' tcx > > >
@@ -251,7 +243,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
251
243
self . select ( & mut selcx, false )
252
244
}
253
245
254
- pub fn pending_obligations ( & self ) -> & [ PredicateObligation < ' tcx > ] {
246
+ pub fn pending_obligations ( & self ) -> & [ PendingPredicateObligation < ' tcx > ] {
255
247
& self . predicates
256
248
}
257
249
@@ -299,36 +291,25 @@ impl<'tcx> FulfillmentContext<'tcx> {
299
291
300
292
let mut new_obligations = Vec :: new ( ) ;
301
293
302
- // If we are only attempting obligations we haven't seen yet,
303
- // then set `skip` to the number of obligations we've already
304
- // seen.
305
- let mut skip = if only_new_obligations {
306
- self . attempted_mark
307
- } else {
308
- 0
309
- } ;
310
-
311
294
// First pass: walk each obligation, retaining
312
295
// only those that we cannot yet process.
313
296
{
314
297
let region_obligations = & mut self . region_obligations ;
315
- self . predicates . retain ( |predicate| {
316
- // Hack: Retain does not pass in the index, but we want
317
- // to avoid processing the first `start_count` entries.
318
- let processed =
319
- if skip == 0 {
320
- process_predicate ( selcx , predicate ,
321
- & mut new_obligations , & mut errors , region_obligations)
322
- } else {
323
- skip -= 1 ;
324
- false
325
- } ;
326
- !processed
327
- } ) ;
298
+ let mut i = 0 ;
299
+ while i < self . predicates . len ( ) {
300
+ let processed = process_predicate ( selcx ,
301
+ & mut self . predicates [ i ] ,
302
+ & mut new_obligations ,
303
+ & mut errors ,
304
+ region_obligations) ;
305
+ if processed {
306
+ self . predicates . swap_remove ( i ) ;
307
+ } else {
308
+ i += 1 ;
309
+ }
310
+ }
328
311
}
329
312
330
- self . attempted_mark = self . predicates . len ( ) ;
331
-
332
313
if self . predicates . len ( ) == count {
333
314
// Nothing changed.
334
315
break ;
@@ -354,7 +335,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
354
335
}
355
336
356
337
fn process_predicate < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
357
- obligation : & PredicateObligation < ' tcx > ,
338
+ pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
358
339
new_obligations : & mut Vec < PredicateObligation < ' tcx > > ,
359
340
errors : & mut Vec < FulfillmentError < ' tcx > > ,
360
341
region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
@@ -367,11 +348,53 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
367
348
* type inference.
368
349
*/
369
350
351
+ // if we were stalled on some unresolved variables, first check
352
+ // whether any of them have been resolved; if not, don't bother
353
+ // doing more work yet
354
+ if !pending_obligation. stalled_on . is_empty ( ) {
355
+ if pending_obligation. stalled_on . iter ( ) . all ( |& ty| {
356
+ let resolved_ty = selcx. infcx ( ) . resolve_type_vars_if_possible ( & ty) ;
357
+ resolved_ty == ty // nothing changed here
358
+ } ) {
359
+ debug ! ( "process_predicate: pending obligation {:?} still stalled on {:?}" ,
360
+ selcx. infcx( ) . resolve_type_vars_if_possible( & pending_obligation. obligation) ,
361
+ pending_obligation. stalled_on) ;
362
+ return false ;
363
+ }
364
+ pending_obligation. stalled_on = vec ! [ ] ;
365
+ }
366
+
367
+ let obligation = & mut pending_obligation. obligation ;
370
368
match obligation. predicate {
371
369
ty:: Predicate :: Trait ( ref data) => {
372
370
let trait_obligation = obligation. with ( data. clone ( ) ) ;
373
371
match selcx. select ( & trait_obligation) {
374
372
Ok ( None ) => {
373
+ // This is a bit subtle: for the most part, the
374
+ // only reason we can fail to make progress on
375
+ // trait selection is because we don't have enough
376
+ // information about the types in the trait. One
377
+ // exception is that we sometimes haven't decided
378
+ // what kind of closure a closure is. *But*, in
379
+ // that case, it turns out, the type of the
380
+ // closure will also change, because the closure
381
+ // also includes references to its upvars as part
382
+ // of its type, and those types are resolved at
383
+ // the same time.
384
+ pending_obligation. stalled_on =
385
+ data. skip_binder ( ) // ok b/c this check doesn't care about regions
386
+ . input_types ( )
387
+ . iter ( )
388
+ . map ( |t| selcx. infcx ( ) . resolve_type_vars_if_possible ( t) )
389
+ . filter ( |t| t. has_infer_types ( ) )
390
+ . flat_map ( |t| t. walk ( ) )
391
+ . filter ( |t| t. is_ty_var ( ) )
392
+ . collect ( ) ;
393
+
394
+ debug ! ( "process_predicate: pending obligation {:?} now stalled on {:?}" ,
395
+ selcx. infcx( ) . resolve_type_vars_if_possible( obligation) ,
396
+ pending_obligation. stalled_on) ;
397
+
375
398
false
376
399
}
377
400
Ok ( Some ( s) ) => {
0 commit comments