@@ -874,6 +874,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
874874 return Ok ( result) ;
875875 }
876876
877+ // Check if this is a match for something already on the
878+ // stack. If so, we don't want to insert the result into the
879+ // main cache (it is cycle dependent) nor the provisional
880+ // cache (which is meant for things that have completed but
881+ // for a "backedge" -- this result *is* the backedge).
882+ if let Some ( cycle_result) = self . check_evaluation_cycle ( & stack) {
883+ return Ok ( cycle_result) ;
884+ }
885+
877886 let ( result, dep_node) = self . in_task ( |this| this. evaluate_stack ( & stack) ) ;
878887 let result = result?;
879888
@@ -894,6 +903,74 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
894903 Ok ( result)
895904 }
896905
906+ /// If there is any previous entry on the stack that precisely
907+ /// matches this obligation, then we can assume that the
908+ /// obligation is satisfied for now (still all other conditions
909+ /// must be met of course). One obvious case this comes up is
910+ /// marker traits like `Send`. Think of a linked list:
911+ ///
912+ /// struct List<T> { data: T, next: Option<Box<List<T>>> }
913+ ///
914+ /// `Box<List<T>>` will be `Send` if `T` is `Send` and
915+ /// `Option<Box<List<T>>>` is `Send`, and in turn
916+ /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
917+ /// `Send`.
918+ ///
919+ /// Note that we do this comparison using the `fresh_trait_ref`
920+ /// fields. Because these have all been freshened using
921+ /// `self.freshener`, we can be sure that (a) this will not
922+ /// affect the inferencer state and (b) that if we see two
923+ /// fresh regions with the same index, they refer to the same
924+ /// unbound type variable.
925+ fn check_evaluation_cycle (
926+ & mut self ,
927+ stack : & TraitObligationStack < ' _ , ' tcx > ,
928+ ) -> Option < EvaluationResult > {
929+ if let Some ( cycle_depth) = stack. iter ( )
930+ . skip ( 1 ) // skip top-most frame
931+ . find ( |prev| stack. obligation . param_env == prev. obligation . param_env &&
932+ stack. fresh_trait_ref == prev. fresh_trait_ref )
933+ . map ( |stack| stack. depth )
934+ {
935+ debug ! (
936+ "evaluate_stack({:?}) --> recursive at depth {}" ,
937+ stack. fresh_trait_ref,
938+ cycle_depth,
939+ ) ;
940+
941+ // If we have a stack like `A B C D E A`, where the top of
942+ // the stack is the final `A`, then this will iterate over
943+ // `A, E, D, C, B` -- i.e., all the participants apart
944+ // from the cycle head. We mark them as participating in a
945+ // cycle. This suppresses caching for those nodes. See
946+ // `in_cycle` field for more details.
947+ stack. update_reached_depth ( cycle_depth) ;
948+
949+ // Subtle: when checking for a coinductive cycle, we do
950+ // not compare using the "freshened trait refs" (which
951+ // have erased regions) but rather the fully explicit
952+ // trait refs. This is important because it's only a cycle
953+ // if the regions match exactly.
954+ let cycle = stack. iter ( ) . skip ( 1 ) . take_while ( |s| s. depth >= cycle_depth) ;
955+ let cycle = cycle. map ( |stack| ty:: Predicate :: Trait ( stack. obligation . predicate ) ) ;
956+ if self . coinductive_match ( cycle) {
957+ debug ! (
958+ "evaluate_stack({:?}) --> recursive, coinductive" ,
959+ stack. fresh_trait_ref
960+ ) ;
961+ Some ( EvaluatedToOk )
962+ } else {
963+ debug ! (
964+ "evaluate_stack({:?}) --> recursive, inductive" ,
965+ stack. fresh_trait_ref
966+ ) ;
967+ Some ( EvaluatedToRecur )
968+ }
969+ } else {
970+ None
971+ }
972+ }
973+
897974 fn evaluate_stack < ' o > (
898975 & mut self ,
899976 stack : & TraitObligationStack < ' o , ' tcx > ,
@@ -970,66 +1047,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
9701047 return Ok ( EvaluatedToUnknown ) ;
9711048 }
9721049
973- // If there is any previous entry on the stack that precisely
974- // matches this obligation, then we can assume that the
975- // obligation is satisfied for now (still all other conditions
976- // must be met of course). One obvious case this comes up is
977- // marker traits like `Send`. Think of a linked list:
978- //
979- // struct List<T> { data: T, next: Option<Box<List<T>>> }
980- //
981- // `Box<List<T>>` will be `Send` if `T` is `Send` and
982- // `Option<Box<List<T>>>` is `Send`, and in turn
983- // `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
984- // `Send`.
985- //
986- // Note that we do this comparison using the `fresh_trait_ref`
987- // fields. Because these have all been freshened using
988- // `self.freshener`, we can be sure that (a) this will not
989- // affect the inferencer state and (b) that if we see two
990- // fresh regions with the same index, they refer to the same
991- // unbound type variable.
992- if let Some ( cycle_depth) = stack. iter ( )
993- . skip ( 1 ) // skip top-most frame
994- . find ( |prev| stack. obligation . param_env == prev. obligation . param_env &&
995- stack. fresh_trait_ref == prev. fresh_trait_ref )
996- . map ( |stack| stack. depth )
997- {
998- debug ! ( "evaluate_stack({:?}) --> recursive" , stack. fresh_trait_ref) ;
999-
1000- // If we have a stack like `A B C D E A`, where the top of
1001- // the stack is the final `A`, then this will iterate over
1002- // `A, E, D, C, B` -- i.e., all the participants apart
1003- // from the cycle head. We mark them as participating in a
1004- // cycle. This suppresses caching for those nodes. See
1005- // `in_cycle` field for more details.
1006- for item in stack. iter ( ) . take_while ( |s| s. depth > cycle_depth) {
1007- debug ! ( "evaluate_stack: marking {:?} as cycle participant" , item. fresh_trait_ref) ;
1008- item. update_reached_depth ( cycle_depth) ;
1009- }
1010-
1011- // Subtle: when checking for a coinductive cycle, we do
1012- // not compare using the "freshened trait refs" (which
1013- // have erased regions) but rather the fully explicit
1014- // trait refs. This is important because it's only a cycle
1015- // if the regions match exactly.
1016- let cycle = stack. iter ( ) . skip ( 1 ) . take_while ( |s| s. depth >= cycle_depth) ;
1017- let cycle = cycle. map ( |stack| ty:: Predicate :: Trait ( stack. obligation . predicate ) ) ;
1018- if self . coinductive_match ( cycle) {
1019- debug ! (
1020- "evaluate_stack({:?}) --> recursive, coinductive" ,
1021- stack. fresh_trait_ref
1022- ) ;
1023- return Ok ( EvaluatedToOk ) ;
1024- } else {
1025- debug ! (
1026- "evaluate_stack({:?}) --> recursive, inductive" ,
1027- stack. fresh_trait_ref
1028- ) ;
1029- return Ok ( EvaluatedToRecur ) ;
1030- }
1031- }
1032-
10331050 match self . candidate_from_obligation ( stack) {
10341051 Ok ( Some ( c) ) => self . evaluate_candidate ( stack, & c) ,
10351052 Ok ( None ) => Ok ( EvaluatedToAmbig ) ,
@@ -3966,8 +3983,12 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
39663983 reached_depth,
39673984 ) ;
39683985 debug ! ( "update_reached_depth(reached_depth={})" , reached_depth) ;
3969- let v = self . reached_depth . get ( ) ;
3970- self . reached_depth . set ( v. min ( reached_depth) ) ;
3986+ let mut p = self ;
3987+ while reached_depth < p. depth {
3988+ debug ! ( "update_reached_depth: marking {:?} as cycle participant" , p. fresh_trait_ref) ;
3989+ p. reached_depth . set ( p. reached_depth . get ( ) . min ( reached_depth) ) ;
3990+ p = p. previous . head . unwrap ( ) ;
3991+ }
39713992 }
39723993}
39733994
0 commit comments