@@ -703,14 +703,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
703
703
// affect the inferencer state and (b) that if we see two
704
704
// skolemized types with the same index, they refer to the
705
705
// same unbound type variable.
706
- if
706
+ if let Some ( rec_index ) =
707
707
stack. iter ( )
708
708
. skip ( 1 ) // skip top-most frame
709
- . any ( |prev| stack. fresh_trait_ref == prev. fresh_trait_ref )
709
+ . position ( |prev| stack. fresh_trait_ref == prev. fresh_trait_ref )
710
710
{
711
711
debug ! ( "evaluate_stack({:?}) --> recursive" ,
712
712
stack. fresh_trait_ref) ;
713
- return EvaluatedToOk ;
713
+ let cycle = stack. iter ( ) . skip ( 1 ) . take ( rec_index+1 ) ;
714
+ let cycle = cycle. map ( |stack| ty:: Predicate :: Trait ( stack. obligation . predicate ) ) ;
715
+ if self . coinductive_match ( cycle) {
716
+ debug ! ( "evaluate_stack({:?}) --> recursive, coinductive" ,
717
+ stack. fresh_trait_ref) ;
718
+ return EvaluatedToOk ;
719
+ } else {
720
+ debug ! ( "evaluate_stack({:?}) --> recursive, inductive" ,
721
+ stack. fresh_trait_ref) ;
722
+ return EvaluatedToErr ;
723
+ }
714
724
}
715
725
716
726
match self . candidate_from_obligation ( stack) {
@@ -720,6 +730,33 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
720
730
}
721
731
}
722
732
733
+ /// For defaulted traits, we use a co-inductive strategy to solve, so
734
+ /// that recursion is ok. This routine returns true if the top of the
735
+ /// stack (`cycle[0]`):
736
+ /// - is a defaulted trait, and
737
+ /// - it also appears in the backtrace at some position `X`; and,
738
+ /// - all the predicates at positions `X..` between `X` an the top are
739
+ /// also defaulted traits.
740
+ pub fn coinductive_match < I > ( & mut self , cycle : I ) -> bool
741
+ where I : Iterator < Item =ty:: Predicate < ' tcx > >
742
+ {
743
+ let mut cycle = cycle;
744
+ cycle. all ( |predicate| self . coinductive_predicate ( predicate) )
745
+ }
746
+
747
+ fn coinductive_predicate ( & self , predicate : ty:: Predicate < ' tcx > ) -> bool {
748
+ let result = match predicate {
749
+ ty:: Predicate :: Trait ( ref data) => {
750
+ self . tcx ( ) . trait_has_default_impl ( data. def_id ( ) )
751
+ }
752
+ _ => {
753
+ false
754
+ }
755
+ } ;
756
+ debug ! ( "coinductive_predicate({:?}) = {:?}" , predicate, result) ;
757
+ result
758
+ }
759
+
723
760
/// Further evaluate `candidate` to decide whether all type parameters match and whether nested
724
761
/// obligations are met. Returns true if `candidate` remains viable after this further
725
762
/// scrutiny.
0 commit comments