@@ -874,6 +874,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
874
874
return Ok ( result) ;
875
875
}
876
876
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
+
877
886
let ( result, dep_node) = self . in_task ( |this| this. evaluate_stack ( & stack) ) ;
878
887
let result = result?;
879
888
@@ -894,6 +903,74 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
894
903
Ok ( result)
895
904
}
896
905
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
+
897
974
fn evaluate_stack < ' o > (
898
975
& mut self ,
899
976
stack : & TraitObligationStack < ' o , ' tcx > ,
@@ -970,66 +1047,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
970
1047
return Ok ( EvaluatedToUnknown ) ;
971
1048
}
972
1049
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
-
1033
1050
match self . candidate_from_obligation ( stack) {
1034
1051
Ok ( Some ( c) ) => self . evaluate_candidate ( stack, & c) ,
1035
1052
Ok ( None ) => Ok ( EvaluatedToAmbig ) ,
@@ -3966,8 +3983,12 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
3966
3983
reached_depth,
3967
3984
) ;
3968
3985
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
+ }
3971
3992
}
3972
3993
}
3973
3994
0 commit comments