@@ -320,103 +320,172 @@ impl<'tcx> FulfillmentContext<'tcx> {
320
320
fn process_predicate < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
321
321
tree_cache : & mut LocalFulfilledPredicates < ' tcx > ,
322
322
pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
323
- mut backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
323
+ backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
324
324
region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
325
325
-> Result < Option < Vec < PendingPredicateObligation < ' tcx > > > ,
326
326
FulfillmentErrorCode < ' tcx > >
327
327
{
328
- match process_predicate1 ( selcx, pending_obligation, backtrace. clone ( ) , region_obligations) {
329
- Ok ( Some ( v) ) => {
330
- // FIXME(#30977) The code below is designed to detect (and
331
- // permit) DAGs, while still ensuring that the reasoning
332
- // is acyclic. However, it does a few things
333
- // suboptimally. For example, it refreshes type variables
334
- // a lot, probably more than needed, but also less than
335
- // you might want.
336
- //
337
- // - more than needed: I want to be very sure we don't
338
- // accidentally treat a cycle as a DAG, so I am
339
- // refreshing type variables as we walk the ancestors;
340
- // but we are going to repeat this a lot, which is
341
- // sort of silly, and it would be nicer to refresh
342
- // them *in place* so that later predicate processing
343
- // can benefit from the same work;
344
- // - less than you might want: we only add items in the cache here,
345
- // but maybe we learn more about type variables and could add them into
346
- // the cache later on.
347
-
348
- let tcx = selcx. tcx ( ) ;
349
-
350
- // Compute a little FnvHashSet for the ancestors. We only
351
- // do this the first time that we care.
352
- let mut cache = None ;
353
- let mut is_ancestor = |predicate : & ty:: Predicate < ' tcx > | {
354
- if cache. is_none ( ) {
355
- let mut c = FnvHashSet ( ) ;
356
- for ancestor in backtrace. by_ref ( ) {
357
- // Ugh. This just feels ridiculously
358
- // inefficient. But we need to compare
359
- // predicates without being concerned about
360
- // the vagaries of type inference, so for now
361
- // just ensure that they are always
362
- // up-to-date. (I suppose we could just use a
363
- // snapshot and check if they are unifiable?)
364
- let resolved_predicate =
365
- selcx. infcx ( ) . resolve_type_vars_if_possible (
366
- & ancestor. obligation . predicate ) ;
367
- c. insert ( resolved_predicate) ;
368
- }
369
- cache = Some ( c) ;
328
+ match process_predicate1 ( selcx, pending_obligation, region_obligations) {
329
+ Ok ( Some ( v) ) => process_child_obligations ( selcx,
330
+ tree_cache,
331
+ & pending_obligation. obligation ,
332
+ backtrace,
333
+ v) ,
334
+ Ok ( None ) => Ok ( None ) ,
335
+ Err ( e) => Err ( e)
336
+ }
337
+ }
338
+
339
+ fn process_child_obligations < ' a , ' tcx > (
340
+ selcx : & mut SelectionContext < ' a , ' tcx > ,
341
+ tree_cache : & mut LocalFulfilledPredicates < ' tcx > ,
342
+ pending_obligation : & PredicateObligation < ' tcx > ,
343
+ backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
344
+ child_obligations : Vec < PredicateObligation < ' tcx > > )
345
+ -> Result < Option < Vec < PendingPredicateObligation < ' tcx > > > ,
346
+ FulfillmentErrorCode < ' tcx > >
347
+ {
348
+ // FIXME(#30977) The code below is designed to detect (and
349
+ // permit) DAGs, while still ensuring that the reasoning
350
+ // is acyclic. However, it does a few things
351
+ // suboptimally. For example, it refreshes type variables
352
+ // a lot, probably more than needed, but also less than
353
+ // you might want.
354
+ //
355
+ // - more than needed: I want to be very sure we don't
356
+ // accidentally treat a cycle as a DAG, so I am
357
+ // refreshing type variables as we walk the ancestors;
358
+ // but we are going to repeat this a lot, which is
359
+ // sort of silly, and it would be nicer to refresh
360
+ // them *in place* so that later predicate processing
361
+ // can benefit from the same work;
362
+ // - less than you might want: we only add items in the cache here,
363
+ // but maybe we learn more about type variables and could add them into
364
+ // the cache later on.
365
+
366
+ let tcx = selcx. tcx ( ) ;
367
+
368
+ let mut ancestor_set = AncestorSet :: new ( & backtrace) ;
369
+
370
+ let pending_predicate_obligations: Vec < _ > =
371
+ child_obligations
372
+ . into_iter ( )
373
+ . filter_map ( |obligation| {
374
+ // Probably silly, but remove any inference
375
+ // variables. This is actually crucial to the ancestor
376
+ // check marked (*) below, but it's not clear that it
377
+ // makes sense to ALWAYS do it.
378
+ let obligation = selcx. infcx ( ) . resolve_type_vars_if_possible ( & obligation) ;
379
+
380
+ // Screen out obligations that we know globally
381
+ // are true.
382
+ if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( & obligation. predicate ) {
383
+ return None ;
384
+ }
385
+
386
+ // Check whether this obligation appears
387
+ // somewhere else in the tree. If not, we have to
388
+ // process it for sure.
389
+ if !tree_cache. is_duplicate_or_add ( & obligation. predicate ) {
390
+ return Some ( PendingPredicateObligation {
391
+ obligation : obligation,
392
+ stalled_on : vec ! [ ]
393
+ } ) ;
394
+ }
395
+
396
+ debug ! ( "process_child_obligations: duplicate={:?}" ,
397
+ obligation. predicate) ;
398
+
399
+ // OK, the obligation appears elsewhere in the tree.
400
+ // This is either a fatal error or else something we can
401
+ // ignore. If the obligation appears in our *ancestors*
402
+ // (rather than some more distant relative), that
403
+ // indicates a cycle. Cycles are either considered
404
+ // resolved (if this is a coinductive case) or a fatal
405
+ // error.
406
+ if let Some ( index) = ancestor_set. has ( selcx. infcx ( ) , & obligation. predicate ) {
407
+ // ~~~ (*) see above
408
+ debug ! ( "process_child_obligations: cycle index = {}" , index) ;
409
+
410
+ let backtrace = backtrace. clone ( ) ;
411
+ let cycle: Vec < _ > =
412
+ iter:: once ( & obligation)
413
+ . chain ( Some ( pending_obligation) )
414
+ . chain ( backtrace. take ( index + 1 ) . map ( |p| & p. obligation ) )
415
+ . cloned ( )
416
+ . collect ( ) ;
417
+ if coinductive_match ( selcx, & cycle) {
418
+ debug ! ( "process_child_obligations: coinductive match" ) ;
419
+ None
420
+ } else {
421
+ report_overflow_error_cycle ( selcx. infcx ( ) , & cycle) ;
370
422
}
423
+ } else {
424
+ // Not a cycle. Just ignore this obligation then,
425
+ // we're already in the process of proving it.
426
+ debug ! ( "process_child_obligations: not a cycle" ) ;
427
+ None
428
+ }
429
+ } )
430
+ . collect ( ) ;
371
431
372
- cache. as_ref ( ) . unwrap ( ) . contains ( predicate)
373
- } ;
432
+ Ok ( Some ( pending_predicate_obligations) )
433
+ }
434
+
435
+ struct AncestorSet < ' b , ' tcx : ' b > {
436
+ populated : bool ,
437
+ cache : FnvHashMap < ty:: Predicate < ' tcx > , usize > ,
438
+ backtrace : Backtrace < ' b , PendingPredicateObligation < ' tcx > > ,
439
+ }
374
440
375
- let pending_predicate_obligations: Vec < _ > =
376
- v. into_iter ( )
377
- . filter_map ( |obligation| {
378
- // Probably silly, but remove any inference
379
- // variables. This is actually crucial to the
380
- // ancestor check below, but it's not clear that
381
- // it makes sense to ALWAYS do it.
382
- let obligation = selcx. infcx ( ) . resolve_type_vars_if_possible ( & obligation) ;
383
-
384
- // Screen out obligations that we know globally
385
- // are true. This should really be the DAG check
386
- // mentioned above.
387
- if tcx. fulfilled_predicates . borrow ( ) . check_duplicate ( & obligation. predicate ) {
388
- return None ;
389
- }
390
-
391
- // Check whether this obligation appears somewhere else in the tree.
392
- if tree_cache. is_duplicate_or_add ( & obligation. predicate ) {
393
- // If the obligation appears as a parent,
394
- // allow it, because that is a cycle.
395
- // Otherwise though we can just ignore
396
- // it. Note that we have to be careful around
397
- // inference variables here -- for the
398
- // purposes of the ancestor check, we retain
399
- // the invariant that all type variables are
400
- // fully refreshed.
401
- if !is_ancestor ( & obligation. predicate ) {
402
- return None ;
403
- }
404
- }
405
-
406
- Some ( PendingPredicateObligation {
407
- obligation : obligation,
408
- stalled_on : vec ! [ ]
409
- } )
410
- } )
411
- . collect ( ) ;
412
-
413
- Ok ( Some ( pending_predicate_obligations) )
441
+ impl < ' b , ' tcx > AncestorSet < ' b , ' tcx > {
442
+ fn new ( backtrace : & Backtrace < ' b , PendingPredicateObligation < ' tcx > > ) -> Self {
443
+ AncestorSet {
444
+ populated : false ,
445
+ cache : FnvHashMap ( ) ,
446
+ backtrace : backtrace. clone ( ) ,
414
447
}
415
- Ok ( None ) => Ok ( None ) ,
416
- Err ( e) => Err ( e)
417
448
}
418
- }
419
449
450
+ /// Checks whether any of the ancestors in the backtrace are equal
451
+ /// to `predicate` (`predicate` is assumed to be fully
452
+ /// type-resolved). Returns `None` if not; otherwise, returns
453
+ /// `Some` with the index within the backtrace.
454
+ fn has < ' a > ( & mut self ,
455
+ infcx : & InferCtxt < ' a , ' tcx > ,
456
+ predicate : & ty:: Predicate < ' tcx > )
457
+ -> Option < usize > {
458
+ // the first time, we have to populate the cache
459
+ if !self . populated {
460
+ let backtrace = self . backtrace . clone ( ) ;
461
+ for ( index, ancestor) in backtrace. enumerate ( ) {
462
+ // Ugh. This just feels ridiculously
463
+ // inefficient. But we need to compare
464
+ // predicates without being concerned about
465
+ // the vagaries of type inference, so for now
466
+ // just ensure that they are always
467
+ // up-to-date. (I suppose we could just use a
468
+ // snapshot and check if they are unifiable?)
469
+ let resolved_predicate =
470
+ infcx. resolve_type_vars_if_possible (
471
+ & ancestor. obligation . predicate ) ;
472
+
473
+ // Though we try to avoid it, it can happen that a
474
+ // cycle already exists in the predecessors. This
475
+ // happens if the type variables were not fully known
476
+ // at the time that the ancestors were pushed. We'll
477
+ // just ignore such cycles for now, on the premise
478
+ // that they will repeat themselves and we'll deal
479
+ // with them properly then.
480
+ self . cache . entry ( resolved_predicate)
481
+ . or_insert ( index) ;
482
+ }
483
+ self . populated = true ;
484
+ }
485
+
486
+ self . cache . get ( predicate) . cloned ( )
487
+ }
488
+ }
420
489
421
490
/// Return the set of type variables contained in a trait ref
422
491
fn trait_ref_type_vars < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
@@ -438,7 +507,6 @@ fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>,
438
507
/// - `Err` if the predicate does not hold
439
508
fn process_predicate1 < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
440
509
pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
441
- backtrace : Backtrace < PendingPredicateObligation < ' tcx > > ,
442
510
region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > )
443
511
-> Result < Option < Vec < PredicateObligation < ' tcx > > > ,
444
512
FulfillmentErrorCode < ' tcx > >
@@ -461,16 +529,6 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
461
529
462
530
let obligation = & mut pending_obligation. obligation ;
463
531
464
- // If we exceed the recursion limit, take a moment to look for a
465
- // cycle so we can give a better error report from here, where we
466
- // have more context.
467
- let recursion_limit = selcx. tcx ( ) . sess . recursion_limit . get ( ) ;
468
- if obligation. recursion_depth >= recursion_limit {
469
- if let Some ( cycle) = scan_for_cycle ( obligation, & backtrace) {
470
- report_overflow_error_cycle ( selcx. infcx ( ) , & cycle) ;
471
- }
472
- }
473
-
474
532
if obligation. predicate . has_infer_types ( ) {
475
533
obligation. predicate = selcx. infcx ( ) . resolve_type_vars_if_possible ( & obligation. predicate ) ;
476
534
}
@@ -481,10 +539,6 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
481
539
return Ok ( Some ( vec ! [ ] ) ) ;
482
540
}
483
541
484
- if coinductive_match ( selcx, obligation, data, & backtrace) {
485
- return Ok ( Some ( vec ! [ ] ) ) ;
486
- }
487
-
488
542
let trait_obligation = obligation. with ( data. clone ( ) ) ;
489
543
match selcx. select ( & trait_obligation) {
490
544
Ok ( Some ( vtable) ) => {
@@ -609,63 +663,40 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
609
663
610
664
/// For defaulted traits, we use a co-inductive strategy to solve, so
611
665
/// that recursion is ok. This routine returns true if the top of the
612
- /// stack (`top_obligation` and `top_data `):
666
+ /// stack (`cycle[0] `):
613
667
/// - is a defaulted trait, and
614
668
/// - it also appears in the backtrace at some position `X`; and,
615
669
/// - all the predicates at positions `X..` between `X` an the top are
616
670
/// also defaulted traits.
617
671
fn coinductive_match < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
618
- top_obligation : & PredicateObligation < ' tcx > ,
619
- top_data : & ty:: PolyTraitPredicate < ' tcx > ,
620
- backtrace : & Backtrace < PendingPredicateObligation < ' tcx > > )
672
+ cycle : & [ PredicateObligation < ' tcx > ] )
621
673
-> bool
622
674
{
623
- if selcx. tcx ( ) . trait_has_default_impl ( top_data. def_id ( ) ) {
624
- debug ! ( "coinductive_match: top_data={:?}" , top_data) ;
625
- for bt_obligation in backtrace. clone ( ) {
626
- debug ! ( "coinductive_match: bt_obligation={:?}" , bt_obligation) ;
627
-
628
- // *Everything* in the backtrace must be a defaulted trait.
629
- match bt_obligation. obligation . predicate {
630
- ty:: Predicate :: Trait ( ref data) => {
631
- if !selcx. tcx ( ) . trait_has_default_impl ( data. def_id ( ) ) {
632
- debug ! ( "coinductive_match: trait does not have default impl" ) ;
633
- break ;
634
- }
635
- }
636
- _ => { break ; }
637
- }
638
-
639
- // And we must find a recursive match.
640
- if bt_obligation. obligation . predicate == top_obligation. predicate {
641
- debug ! ( "coinductive_match: found a match in the backtrace" ) ;
642
- return true ;
643
- }
644
- }
645
- }
646
-
647
- false
675
+ let len = cycle. len ( ) ;
676
+
677
+ assert_eq ! ( cycle[ 0 ] . predicate, cycle[ len - 1 ] . predicate) ;
678
+
679
+ cycle[ 0 ..len-1 ]
680
+ . iter ( )
681
+ . all ( |bt_obligation| {
682
+ let result = coinductive_obligation ( selcx, bt_obligation) ;
683
+ debug ! ( "coinductive_match: bt_obligation={:?} coinductive={}" ,
684
+ bt_obligation, result) ;
685
+ result
686
+ } )
648
687
}
649
688
650
- fn scan_for_cycle < ' a , ' tcx > ( top_obligation : & PredicateObligation < ' tcx > ,
651
- backtrace : & Backtrace < PendingPredicateObligation < ' tcx > > )
652
- -> Option < Vec < PredicateObligation < ' tcx > > >
653
- {
654
- let mut map = FnvHashMap ( ) ;
655
- let all_obligations =
656
- || iter:: once ( top_obligation)
657
- . chain ( backtrace. clone ( )
658
- . map ( |p| & p. obligation ) ) ;
659
- for ( index, bt_obligation) in all_obligations ( ) . enumerate ( ) {
660
- if let Some ( & start) = map. get ( & bt_obligation. predicate ) {
661
- // Found a cycle starting at position `start` and running
662
- // until the current position (`index`).
663
- return Some ( all_obligations ( ) . skip ( start) . take ( index - start + 1 ) . cloned ( ) . collect ( ) ) ;
664
- } else {
665
- map. insert ( bt_obligation. predicate . clone ( ) , index) ;
689
+ fn coinductive_obligation < ' a , ' tcx > ( selcx : & SelectionContext < ' a , ' tcx > ,
690
+ obligation : & PredicateObligation < ' tcx > )
691
+ -> bool {
692
+ match obligation. predicate {
693
+ ty:: Predicate :: Trait ( ref data) => {
694
+ selcx. tcx ( ) . trait_has_default_impl ( data. def_id ( ) )
695
+ }
696
+ _ => {
697
+ false
666
698
}
667
699
}
668
- None
669
700
}
670
701
671
702
fn register_region_obligation < ' tcx > ( t_a : Ty < ' tcx > ,
0 commit comments