@@ -57,12 +57,7 @@ pub struct FulfillmentContext<'tcx> {
5757
5858 // A list of all obligations that have been registered with this
5959 // 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 > > ,
6661
6762 // A set of constraints that regionck must validate. Each
6863 // constraint has the form `T:'a`, meaning "some type `T` must
@@ -100,6 +95,12 @@ pub struct RegionObligation<'tcx> {
10095 pub cause : ObligationCause < ' tcx > ,
10196}
10297
98+ #[ derive( Clone , Debug ) ]
99+ pub struct PendingPredicateObligation < ' tcx > {
100+ pub obligation : PredicateObligation < ' tcx > ,
101+ pub stalled_on : Vec < Ty < ' tcx > > ,
102+ }
103+
103104impl < ' tcx > FulfillmentContext < ' tcx > {
104105 /// Creates a new fulfillment context.
105106 ///
@@ -122,7 +123,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
122123 FulfillmentContext {
123124 duplicate_set : FulfilledPredicates :: new ( ) ,
124125 predicates : Vec :: new ( ) ,
125- attempted_mark : 0 ,
126126 region_obligations : NodeMap ( ) ,
127127 errors_will_be_reported : errors_will_be_reported,
128128 }
@@ -198,6 +198,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
198198 }
199199
200200 debug ! ( "register_predicate({:?})" , obligation) ;
201+ let obligation = PendingPredicateObligation {
202+ obligation : obligation,
203+ stalled_on : vec ! [ ]
204+ } ;
201205 self . predicates . push ( obligation) ;
202206 }
203207
@@ -221,7 +225,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
221225 let errors: Vec < FulfillmentError > =
222226 self . predicates
223227 . iter ( )
224- . map ( |o| FulfillmentError :: new ( ( * o ) . clone ( ) , CodeAmbiguity ) )
228+ . map ( |o| FulfillmentError :: new ( o . obligation . clone ( ) , CodeAmbiguity ) )
225229 . collect ( ) ;
226230
227231 if errors. is_empty ( ) {
@@ -231,18 +235,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
231235 }
232236 }
233237
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-
246238 pub fn select_where_possible < ' a > ( & mut self ,
247239 infcx : & InferCtxt < ' a , ' tcx > )
248240 -> Result < ( ) , Vec < FulfillmentError < ' tcx > > >
@@ -251,7 +243,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
251243 self . select ( & mut selcx, false )
252244 }
253245
254- pub fn pending_obligations ( & self ) -> & [ PredicateObligation < ' tcx > ] {
246+ pub fn pending_obligations ( & self ) -> & [ PendingPredicateObligation < ' tcx > ] {
255247 & self . predicates
256248 }
257249
@@ -299,36 +291,25 @@ impl<'tcx> FulfillmentContext<'tcx> {
299291
300292 let mut new_obligations = Vec :: new ( ) ;
301293
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-
311294 // First pass: walk each obligation, retaining
312295 // only those that we cannot yet process.
313296 {
314297 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+ }
328311 }
329312
330- self . attempted_mark = self . predicates . len ( ) ;
331-
332313 if self . predicates . len ( ) == count {
333314 // Nothing changed.
334315 break ;
@@ -354,7 +335,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
354335}
355336
356337fn process_predicate < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
357- obligation : & PredicateObligation < ' tcx > ,
338+ pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
358339 new_obligations : & mut Vec < PredicateObligation < ' tcx > > ,
359340 errors : & mut Vec < FulfillmentError < ' tcx > > ,
360341 region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
@@ -367,11 +348,53 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
367348 * type inference.
368349 */
369350
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 ;
370368 match obligation. predicate {
371369 ty:: Predicate :: Trait ( ref data) => {
372370 let trait_obligation = obligation. with ( data. clone ( ) ) ;
373371 match selcx. select ( & trait_obligation) {
374372 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+
375398 false
376399 }
377400 Ok ( Some ( s) ) => {
0 commit comments