10
10
11
11
use middle:: infer:: InferCtxt ;
12
12
use middle:: ty:: { self , Ty , TypeFoldable } ;
13
+ use rustc_data_structures:: obligation_forest:: { Backtrace , ObligationForest , Error } ;
13
14
14
15
use syntax:: ast;
15
16
use util:: common:: ErrorReported ;
@@ -20,6 +21,7 @@ use super::CodeProjectionError;
20
21
use super :: CodeSelectionError ;
21
22
use super :: is_object_safe;
22
23
use super :: FulfillmentError ;
24
+ use super :: FulfillmentErrorCode ;
23
25
use super :: ObligationCause ;
24
26
use super :: PredicateObligation ;
25
27
use super :: project;
@@ -57,7 +59,7 @@ pub struct FulfillmentContext<'tcx> {
57
59
58
60
// A list of all obligations that have been registered with this
59
61
// fulfillment context.
60
- predicates : Vec < PendingPredicateObligation < ' tcx > > ,
62
+ predicates : ObligationForest < PendingPredicateObligation < ' tcx > > ,
61
63
62
64
// A set of constraints that regionck must validate. Each
63
65
// constraint has the form `T:'a`, meaning "some type `T` must
@@ -122,7 +124,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
122
124
pub fn new ( errors_will_be_reported : bool ) -> FulfillmentContext < ' tcx > {
123
125
FulfillmentContext {
124
126
duplicate_set : FulfilledPredicates :: new ( ) ,
125
- predicates : Vec :: new ( ) ,
127
+ predicates : ObligationForest :: new ( ) ,
126
128
region_obligations : NodeMap ( ) ,
127
129
errors_will_be_reported : errors_will_be_reported,
128
130
}
@@ -202,7 +204,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
202
204
obligation : obligation,
203
205
stalled_on : vec ! [ ]
204
206
} ;
205
- self . predicates . push ( obligation) ;
207
+ self . predicates . push_root ( obligation) ;
206
208
}
207
209
208
210
pub fn region_obligations ( & self ,
@@ -220,14 +222,11 @@ impl<'tcx> FulfillmentContext<'tcx> {
220
222
-> Result < ( ) , Vec < FulfillmentError < ' tcx > > >
221
223
{
222
224
try!( self . select_where_possible ( infcx) ) ;
223
-
224
- // Anything left is ambiguous.
225
- let errors: Vec < FulfillmentError > =
226
- self . predicates
227
- . iter ( )
228
- . map ( |o| FulfillmentError :: new ( o. obligation . clone ( ) , CodeAmbiguity ) )
229
- . collect ( ) ;
230
-
225
+ let errors: Vec < _ > =
226
+ self . predicates . to_errors ( CodeAmbiguity )
227
+ . into_iter ( )
228
+ . map ( |e| to_fulfillment_error ( e) )
229
+ . collect ( ) ;
231
230
if errors. is_empty ( ) {
232
231
Ok ( ( ) )
233
232
} else {
@@ -240,11 +239,11 @@ impl<'tcx> FulfillmentContext<'tcx> {
240
239
-> Result < ( ) , Vec < FulfillmentError < ' tcx > > >
241
240
{
242
241
let mut selcx = SelectionContext :: new ( infcx) ;
243
- self . select ( & mut selcx, false )
242
+ self . select ( & mut selcx)
244
243
}
245
244
246
- pub fn pending_obligations ( & self ) -> & [ PendingPredicateObligation < ' tcx > ] {
247
- & self . predicates
245
+ pub fn pending_obligations ( & self ) -> Vec < PendingPredicateObligation < ' tcx > > {
246
+ self . predicates . pending_obligations ( )
248
247
}
249
248
250
249
fn is_duplicate_or_add ( & mut self ,
@@ -273,58 +272,43 @@ impl<'tcx> FulfillmentContext<'tcx> {
273
272
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
274
273
/// only attempts to select obligations that haven't been seen before.
275
274
fn select < ' a > ( & mut self ,
276
- selcx : & mut SelectionContext < ' a , ' tcx > ,
277
- only_new_obligations : bool )
275
+ selcx : & mut SelectionContext < ' a , ' tcx > )
278
276
-> Result < ( ) , Vec < FulfillmentError < ' tcx > > >
279
277
{
280
- debug ! ( "select({} obligations, only_new_obligations={}) start" ,
281
- self . predicates. len( ) ,
282
- only_new_obligations) ;
278
+ debug ! ( "select(obligation-forest-size={})" , self . predicates. len( ) ) ;
283
279
284
280
let mut errors = Vec :: new ( ) ;
285
281
286
282
loop {
287
- let count = self . predicates . len ( ) ;
283
+ debug ! ( "select_where_possible: starting another iteration" ) ;
288
284
289
- debug ! ( "select_where_possible({} obligations) iteration" ,
290
- count) ;
285
+ // Process pending obligations.
286
+ let outcome = {
287
+ let region_obligations = & mut self . region_obligations ;
288
+ self . predicates . process_obligations (
289
+ |obligation, backtrace| process_predicate ( selcx,
290
+ obligation,
291
+ backtrace,
292
+ region_obligations) )
293
+ } ;
291
294
292
- let mut new_obligations = Vec :: new ( ) ;
295
+ debug ! ( "select_where_possible: outcome={:?}" , outcome ) ;
293
296
294
- // First pass: walk each obligation, retaining
295
- // only those that we cannot yet process.
296
- {
297
- let region_obligations = & mut self . region_obligations ;
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
297
}
311
298
}
312
299
313
- if self . predicates . len ( ) == count {
314
- // Nothing changed.
315
- break ;
316
- }
300
+ errors. extend(
301
+ outcome. errors. into_iter( )
302
+ . map( |e| to_fulfillment_error( e) ) ) ;
317
303
318
- // Now go through all the successful ones,
319
- // registering any nested obligations for the future.
320
- for new_obligation in new_obligations {
321
- self . register_predicate_obligation ( selcx. infcx ( ) , new_obligation) ;
304
+ // If nothing new was added, no need to keep looping.
305
+ if outcome. stalled {
306
+ break ;
322
307
}
323
308
}
324
309
325
- debug ! ( "select({} obligations, {} errors) done" ,
326
- self . predicates. len( ) ,
327
- errors. len( ) ) ;
310
+ debug ! ( "select({} predicates remaining, {} errors) done" ,
311
+ self . predicates. len( ) , errors. len( ) ) ;
328
312
329
313
if errors. is_empty ( ) {
330
314
Ok ( ( ) )
@@ -334,20 +318,37 @@ impl<'tcx> FulfillmentContext<'tcx> {
334
318
}
335
319
}
336
320
321
+ /// Like `process_predicate1`, but wrap result into a pending predicate.
337
322
fn process_predicate < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
338
323
pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
339
- new_obligations : & mut Vec < PredicateObligation < ' tcx > > ,
340
- errors : & mut Vec < FulfillmentError < ' tcx > > ,
324
+ backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
341
325
region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
342
- -> bool
326
+ -> Result < Option < Vec < PendingPredicateObligation < ' tcx > > > ,
327
+ FulfillmentErrorCode < ' tcx > >
343
328
{
344
- /*!
345
- * Processes a predicate obligation and modifies the appropriate
346
- * output array with the successful/error result. Returns `false`
347
- * if the predicate could not be processed due to insufficient
348
- * type inference.
349
- */
329
+ match process_predicate1 ( selcx, pending_obligation, backtrace, region_obligations) {
330
+ Ok ( Some ( v) ) => Ok ( Some ( v. into_iter ( )
331
+ . map ( |o| PendingPredicateObligation {
332
+ obligation : o,
333
+ stalled_on : vec ! [ ]
334
+ } )
335
+ . collect ( ) ) ) ,
336
+ Ok ( None ) => Ok ( None ) ,
337
+ Err ( e) => Err ( e)
338
+ }
339
+ }
350
340
341
+ /// Processes a predicate obligation and returns either:
342
+ /// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true
343
+ /// - `Ok(None)` if we don't have enough info to be sure
344
+ /// - `Err` if the predicate does not hold
345
+ fn process_predicate1 < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
346
+ pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
347
+ backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
348
+ region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
349
+ -> Result < Option < Vec < PredicateObligation < ' tcx > > > ,
350
+ FulfillmentErrorCode < ' tcx > >
351
+ {
351
352
// if we were stalled on some unresolved variables, first check
352
353
// whether any of them have been resolved; if not, don't bother
353
354
// doing more work yet
@@ -359,16 +360,19 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
359
360
debug ! ( "process_predicate: pending obligation {:?} still stalled on {:?}" ,
360
361
selcx. infcx( ) . resolve_type_vars_if_possible( & pending_obligation. obligation) ,
361
362
pending_obligation. stalled_on) ;
362
- return false ;
363
+ return Ok ( None ) ;
363
364
}
364
365
pending_obligation. stalled_on = vec ! [ ] ;
365
366
}
366
367
367
- let obligation = & mut pending_obligation. obligation ;
368
+ let obligation = & pending_obligation. obligation ;
368
369
match obligation. predicate {
369
370
ty:: Predicate :: Trait ( ref data) => {
370
371
let trait_obligation = obligation. with ( data. clone ( ) ) ;
371
372
match selcx. select ( & trait_obligation) {
373
+ Ok ( Some ( vtable) ) => {
374
+ Ok ( Some ( vtable. nested_obligations ( ) ) )
375
+ }
372
376
Ok ( None ) => {
373
377
// This is a bit subtle: for the most part, the
374
378
// only reason we can fail to make progress on
@@ -395,50 +399,26 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
395
399
selcx. infcx( ) . resolve_type_vars_if_possible( obligation) ,
396
400
pending_obligation. stalled_on) ;
397
401
398
- false
399
- }
400
- Ok ( Some ( s) ) => {
401
- new_obligations. append ( & mut s. nested_obligations ( ) ) ;
402
- true
402
+ Ok ( None )
403
403
}
404
404
Err ( selection_err) => {
405
- debug ! ( "predicate: {:?} error: {:?}" ,
406
- obligation,
407
- selection_err) ;
408
- errors. push (
409
- FulfillmentError :: new (
410
- obligation. clone ( ) ,
411
- CodeSelectionError ( selection_err) ) ) ;
412
- true
405
+ Err ( CodeSelectionError ( selection_err) )
413
406
}
414
407
}
415
408
}
416
409
417
410
ty:: Predicate :: Equate ( ref binder) => {
418
411
match selcx. infcx ( ) . equality_predicate ( obligation. cause . span , binder) {
419
- Ok ( ( ) ) => { }
420
- Err ( _) => {
421
- errors. push (
422
- FulfillmentError :: new (
423
- obligation. clone ( ) ,
424
- CodeSelectionError ( Unimplemented ) ) ) ;
425
- }
412
+ Ok ( ( ) ) => Ok ( Some ( Vec :: new ( ) ) ) ,
413
+ Err ( _) => Err ( CodeSelectionError ( Unimplemented ) ) ,
426
414
}
427
- true
428
415
}
429
416
430
417
ty:: Predicate :: RegionOutlives ( ref binder) => {
431
418
match selcx. infcx ( ) . region_outlives_predicate ( obligation. cause . span , binder) {
432
- Ok ( ( ) ) => { }
433
- Err ( _) => {
434
- errors. push (
435
- FulfillmentError :: new (
436
- obligation. clone ( ) ,
437
- CodeSelectionError ( Unimplemented ) ) ) ;
438
- }
419
+ Ok ( ( ) ) => Ok ( Some ( Vec :: new ( ) ) ) ,
420
+ Err ( _) => Err ( CodeSelectionError ( Unimplemented ) ) ,
439
421
}
440
-
441
- true
442
422
}
443
423
444
424
ty:: Predicate :: TypeOutlives ( ref binder) => {
@@ -454,17 +434,15 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
454
434
// If so, this obligation is an error (for now). Eventually we should be
455
435
// able to support additional cases here, like `for<'a> &'a str: 'a`.
456
436
None => {
457
- errors. push (
458
- FulfillmentError :: new (
459
- obligation. clone ( ) ,
460
- CodeSelectionError ( Unimplemented ) ) )
437
+ Err ( CodeSelectionError ( Unimplemented ) )
461
438
}
462
439
// Otherwise, we have something of the form
463
440
// `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
464
441
Some ( t_a) => {
465
442
register_region_obligation ( t_a, ty:: ReStatic ,
466
443
obligation. cause . clone ( ) ,
467
444
region_obligations) ;
445
+ Ok ( Some ( vec ! [ ] ) )
468
446
}
469
447
}
470
448
}
@@ -473,55 +451,30 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
473
451
register_region_obligation ( t_a, r_b,
474
452
obligation. cause . clone ( ) ,
475
453
region_obligations) ;
454
+ Ok ( Some ( vec ! [ ] ) )
476
455
}
477
456
}
478
- true
479
457
}
480
458
481
459
ty:: Predicate :: Projection ( ref data) => {
482
460
let project_obligation = obligation. with ( data. clone ( ) ) ;
483
- let result = project:: poly_project_and_unify_type ( selcx, & project_obligation) ;
484
- debug ! ( "process_predicate: poly_project_and_unify_type({:?}) returned {:?}" ,
485
- project_obligation,
486
- result) ;
487
- match result {
488
- Ok ( Some ( obligations) ) => {
489
- new_obligations. extend ( obligations) ;
490
- true
491
- }
492
- Ok ( None ) => {
493
- false
494
- }
495
- Err ( err) => {
496
- errors. push (
497
- FulfillmentError :: new (
498
- obligation. clone ( ) ,
499
- CodeProjectionError ( err) ) ) ;
500
- true
501
- }
461
+ match project:: poly_project_and_unify_type ( selcx, & project_obligation) {
462
+ Ok ( v) => Ok ( v) ,
463
+ Err ( e) => Err ( CodeProjectionError ( e) )
502
464
}
503
465
}
504
466
505
467
ty:: Predicate :: ObjectSafe ( trait_def_id) => {
506
468
if !is_object_safe ( selcx. tcx ( ) , trait_def_id) {
507
- errors . push ( FulfillmentError :: new (
508
- obligation . clone ( ) ,
509
- CodeSelectionError ( Unimplemented ) ) ) ;
469
+ Err ( CodeSelectionError ( Unimplemented ) )
470
+ } else {
471
+ Ok ( Some ( Vec :: new ( ) ) )
510
472
}
511
- true
512
473
}
513
474
514
475
ty:: Predicate :: WellFormed ( ty) => {
515
- match ty:: wf:: obligations ( selcx. infcx ( ) , obligation. cause . body_id ,
516
- ty, obligation. cause . span ) {
517
- Some ( obligations) => {
518
- new_obligations. extend ( obligations) ;
519
- true
520
- }
521
- None => {
522
- false
523
- }
524
- }
476
+ Ok ( ty:: wf:: obligations ( selcx. infcx ( ) , obligation. cause . body_id ,
477
+ ty, obligation. cause . span ) )
525
478
}
526
479
}
527
480
}
@@ -559,3 +512,11 @@ impl<'tcx> FulfilledPredicates<'tcx> {
559
512
!self . set . insert ( key. clone ( ) )
560
513
}
561
514
}
515
+
516
+ fn to_fulfillment_error < ' tcx > (
517
+ error : Error < PendingPredicateObligation < ' tcx > , FulfillmentErrorCode < ' tcx > > )
518
+ -> FulfillmentError < ' tcx >
519
+ {
520
+ let obligation = error. backtrace . into_iter ( ) . next ( ) . unwrap ( ) . obligation ;
521
+ FulfillmentError :: new ( obligation, error. error )
522
+ }
0 commit comments