@@ -512,13 +512,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
512
512
let cache = previous_stack. cache ;
513
513
let dfn = cache. next_dfn ( ) ;
514
514
515
- for stack_arg in previous_stack. cache . wf_tys . borrow ( ) . iter ( ) . rev ( ) {
515
+ for stack_arg in previous_stack. cache . wf_args . borrow ( ) . iter ( ) . rev ( ) {
516
516
if stack_arg. 0 != arg {
517
517
continue ;
518
518
}
519
519
debug ! ( "WellFormed({:?}) on stack" , arg) ;
520
520
if let Some ( stack) = previous_stack. head {
521
- stack. update_reached_depth ( stack_arg. 1 ) ;
521
+ // Okay, let's imagine we have two different stacks:
522
+ // `T: NonAutoTrait -> WF(T) -> T: NonAutoTrait`
523
+ // `WF(T) -> T: NonAutoTrait -> WF(T)`
524
+ // Because of this, we need to check that all
525
+ // predicates between the WF goals are coinductive.
526
+ // Otherwise, we can say that `T: NonAutoTrait` is
527
+ // true.
528
+ // Let's imagine we have a predicate stack like
529
+ // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto
530
+ // depth ^1 ^2 ^3
531
+ // and the current predicate is `WF(T)`. `wf_args`
532
+ // would contain `(T, 1)`. We want to check all
533
+ // trait predicates greater than `1`. The previous
534
+ // stack would be `T: Auto`.
535
+ let cycle = stack. iter ( ) . take_while ( |s| s. depth > stack_arg. 1 ) ;
536
+ let tcx = self . tcx ( ) ;
537
+ let cycle =
538
+ cycle. map ( |stack| stack. obligation . predicate . to_predicate ( tcx) ) ;
539
+ if self . coinductive_match ( cycle) {
540
+ stack. update_reached_depth ( stack_arg. 1 ) ;
541
+ return Ok ( EvaluatedToOk ) ;
542
+ } else {
543
+ return Ok ( EvaluatedToRecur ) ;
544
+ }
522
545
}
523
546
return Ok ( EvaluatedToOk ) ;
524
547
}
@@ -534,10 +557,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
534
557
Some ( mut obligations) => {
535
558
self . add_depth ( obligations. iter_mut ( ) , obligation. recursion_depth ) ;
536
559
537
- cache. wf_tys . borrow_mut ( ) . push ( ( arg, previous_stack. depth ( ) ) ) ;
560
+ cache. wf_args . borrow_mut ( ) . push ( ( arg, previous_stack. depth ( ) ) ) ;
538
561
let result =
539
562
self . evaluate_predicates_recursively ( previous_stack, obligations) ;
540
- cache. wf_tys . borrow_mut ( ) . pop ( ) ;
563
+ cache. wf_args . borrow_mut ( ) . pop ( ) ;
541
564
542
565
let result = result?;
543
566
@@ -2465,7 +2488,14 @@ struct ProvisionalEvaluationCache<'tcx> {
2465
2488
/// means the cached value for `F`.
2466
2489
map : RefCell < FxHashMap < ty:: PolyTraitPredicate < ' tcx > , ProvisionalEvaluation > > ,
2467
2490
2468
- wf_tys : RefCell < Vec < ( ty:: GenericArg < ' tcx > , usize ) > > ,
2491
+ /// The stack of args that we assume to be true because a `WF(arg)` predicate
2492
+ /// is on the stack above (and because of wellformedness is coinductive).
2493
+ /// In an "ideal" world, this would share a stack with trait predicates in
2494
+ /// `TraitObligationStack`. However, trait predicates are *much* hotter than
2495
+ /// `WellFormed` predicates, and it's very likely that the additional matches
2496
+ /// will have a perf effect. The value here is the well-formed `GenericArg`
2497
+ /// and the depth of the trait predicate *above* that well-formed predicate.
2498
+ wf_args : RefCell < Vec < ( ty:: GenericArg < ' tcx > , usize ) > > ,
2469
2499
}
2470
2500
2471
2501
/// A cache value for the provisional cache: contains the depth-first
@@ -2479,7 +2509,7 @@ struct ProvisionalEvaluation {
2479
2509
2480
2510
impl < ' tcx > Default for ProvisionalEvaluationCache < ' tcx > {
2481
2511
fn default ( ) -> Self {
2482
- Self { dfn : Cell :: new ( 0 ) , map : Default :: default ( ) , wf_tys : Default :: default ( ) }
2512
+ Self { dfn : Cell :: new ( 0 ) , map : Default :: default ( ) , wf_args : Default :: default ( ) }
2483
2513
}
2484
2514
}
2485
2515
0 commit comments