@@ -42,7 +42,7 @@ use rustc_data_structures::bit_set::GrowableBitSet;
42
42
use rustc_data_structures::sync::Lock;
43
43
use rustc_target::spec::abi::Abi;
44
44
use std::cmp;
45
- use std::fmt;
45
+ use std::fmt::{self, Display} ;
46
46
use std::iter;
47
47
use std::rc::Rc;
48
48
use util::nodemap::{FxHashMap, FxHashSet};
@@ -573,7 +573,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
573
573
574
574
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
575
575
576
- let candidate = match self.candidate_from_obligation(&stack) {
576
+ // 'select' is an entry point into SelectionContext - we never call it recursively
577
+ // from within SelectionContext. Therefore, we start our recursion depth at 0
578
+ let candidate = match self.candidate_from_obligation(&stack, 0) {
577
579
Err(SelectionError::Overflow) => {
578
580
// In standard mode, overflow must have been caught and reported
579
581
// earlier.
@@ -629,7 +631,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
629
631
obligation: &PredicateObligation<'tcx>,
630
632
) -> Result<EvaluationResult, OverflowError> {
631
633
self.evaluation_probe(|this| {
632
- this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
634
+ // Like 'select', 'evaluate_obligation_recursively' is an entry point into
635
+ // SelectionContext, so our recursion depth is 0
636
+ this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation, 0)
633
637
})
634
638
}
635
639
@@ -653,14 +657,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
653
657
&mut self,
654
658
stack: TraitObligationStackList<'o, 'tcx>,
655
659
predicates: I,
660
+ recursion_depth: usize
656
661
) -> Result<EvaluationResult, OverflowError>
657
662
where
658
663
I: IntoIterator<Item = &'a PredicateObligation<'tcx>>,
659
664
'tcx: 'a,
660
665
{
661
666
let mut result = EvaluatedToOk;
662
667
for obligation in predicates {
663
- let eval = self.evaluate_predicate_recursively(stack, obligation)?;
668
+ let eval = self.evaluate_predicate_recursively(stack, obligation, recursion_depth )?;
664
669
debug!(
665
670
"evaluate_predicate_recursively({:?}) = {:?}",
666
671
obligation, eval
@@ -680,14 +685,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
680
685
&mut self,
681
686
previous_stack: TraitObligationStackList<'o, 'tcx>,
682
687
obligation: &PredicateObligation<'tcx>,
688
+ mut recursion_depth: usize
683
689
) -> Result<EvaluationResult, OverflowError> {
684
- debug!("evaluate_predicate_recursively({:?})", obligation);
690
+ debug!("evaluate_predicate_recursively({:?}, recursion_depth={:?})", obligation,
691
+ recursion_depth);
692
+
693
+ // We need to check for overflow here, since the normal
694
+ // recursion check uses the obligation from the stack.
695
+ // This is insufficient for two reasions:
696
+ // 1. That recursion depth is only incremented when a candidate is confirmed
697
+ // Since evaluation skips candidate confirmation, this will never happen
698
+ // 2. It relies on the trait obligation stack. However, it's possible for overflow
699
+ // to happen without involving the trait obligation stack. For example,
700
+ // we might end up trying to infinitely recurse with a projection predicate,
701
+ // which will never push anything onto the stack.
702
+ self.check_recursion_limit(recursion_depth, obligation)?;
703
+
704
+ // Now that we know that the recursion check has passed, increment our depth
705
+ recursion_depth += 1;
685
706
686
707
match obligation.predicate {
687
708
ty::Predicate::Trait(ref t) => {
688
709
debug_assert!(!t.has_escaping_bound_vars());
689
710
let obligation = obligation.with(t.clone());
690
- self.evaluate_trait_predicate_recursively(previous_stack, obligation)
711
+ self.evaluate_trait_predicate_recursively(previous_stack, obligation, recursion_depth )
691
712
}
692
713
693
714
ty::Predicate::Subtype(ref p) => {
@@ -696,7 +717,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
696
717
.subtype_predicate(&obligation.cause, obligation.param_env, p)
697
718
{
698
719
Some(Ok(InferOk { obligations, .. })) => {
699
- self.evaluate_predicates_recursively(previous_stack, &obligations)
720
+ self.evaluate_predicates_recursively(previous_stack, &obligations, recursion_depth )
700
721
}
701
722
Some(Err(_)) => Ok(EvaluatedToErr),
702
723
None => Ok(EvaluatedToAmbig),
@@ -711,7 +732,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
711
732
obligation.cause.span,
712
733
) {
713
734
Some(obligations) => {
714
- self.evaluate_predicates_recursively(previous_stack, obligations.iter())
735
+ self.evaluate_predicates_recursively(previous_stack, obligations.iter(), recursion_depth )
715
736
}
716
737
None => Ok(EvaluatedToAmbig),
717
738
},
@@ -737,6 +758,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
737
758
let result = self.evaluate_predicates_recursively(
738
759
previous_stack,
739
760
subobligations.iter(),
761
+ recursion_depth
740
762
);
741
763
if let Some(key) =
742
764
ProjectionCacheKey::from_poly_projection_predicate(self, data)
@@ -795,6 +817,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
795
817
&mut self,
796
818
previous_stack: TraitObligationStackList<'o, 'tcx>,
797
819
mut obligation: TraitObligation<'tcx>,
820
+ recursion_depth: usize
798
821
) -> Result<EvaluationResult, OverflowError> {
799
822
debug!("evaluate_trait_predicate_recursively({:?})", obligation);
800
823
@@ -822,7 +845,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
822
845
return Ok(result);
823
846
}
824
847
825
- let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
848
+ let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack, recursion_depth ));
826
849
let result = result?;
827
850
828
851
debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
@@ -834,6 +857,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
834
857
fn evaluate_stack<'o>(
835
858
&mut self,
836
859
stack: &TraitObligationStack<'o, 'tcx>,
860
+ recursion_depth: usize
837
861
) -> Result<EvaluationResult, OverflowError> {
838
862
// In intercrate mode, whenever any of the types are unbound,
839
863
// there can always be an impl. Even if there are no impls in
@@ -874,7 +898,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
874
898
// Heuristics: show the diagnostics when there are no candidates in crate.
875
899
if self.intercrate_ambiguity_causes.is_some() {
876
900
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
877
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
901
+ if let Ok(candidate_set) = self.assemble_candidates(stack, recursion_depth ) {
878
902
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
879
903
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
880
904
let self_ty = trait_ref.self_ty();
@@ -955,8 +979,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
955
979
}
956
980
}
957
981
958
- match self.candidate_from_obligation(stack) {
959
- Ok(Some(c)) => self.evaluate_candidate(stack, &c),
982
+ match self.candidate_from_obligation(stack, recursion_depth ) {
983
+ Ok(Some(c)) => self.evaluate_candidate(stack, &c, recursion_depth ),
960
984
Ok(None) => Ok(EvaluatedToAmbig),
961
985
Err(Overflow) => Err(OverflowError),
962
986
Err(..) => Ok(EvaluatedToErr),
@@ -995,6 +1019,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
995
1019
&mut self,
996
1020
stack: &TraitObligationStack<'o, 'tcx>,
997
1021
candidate: &SelectionCandidate<'tcx>,
1022
+ recursion_depth: usize
998
1023
) -> Result<EvaluationResult, OverflowError> {
999
1024
debug!(
1000
1025
"evaluate_candidate: depth={} candidate={:?}",
@@ -1006,6 +1031,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1006
1031
Ok(selection) => this.evaluate_predicates_recursively(
1007
1032
stack.list(),
1008
1033
selection.nested_obligations().iter(),
1034
+ recursion_depth
1009
1035
),
1010
1036
Err(..) => Ok(EvaluatedToErr),
1011
1037
}
@@ -1080,6 +1106,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1080
1106
.insert(trait_ref, WithDepNode::new(dep_node, result));
1081
1107
}
1082
1108
1109
+ // The weird return type of this function allows it to be used with the 'try' (?)
1110
+ // operator within certain functions
1111
+ fn check_recursion_limit<T: Display + TypeFoldable<'tcx>>(&self, recursion_depth: usize, obligation: &Obligation<'tcx, T>,
1112
+ ) -> Result<(), OverflowError> {
1113
+ let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
1114
+ if recursion_depth >= recursion_limit {
1115
+ match self.query_mode {
1116
+ TraitQueryMode::Standard => {
1117
+ self.infcx().report_overflow_error(obligation, true);
1118
+ }
1119
+ TraitQueryMode::Canonical => {
1120
+ return Err(OverflowError);
1121
+ }
1122
+ }
1123
+ }
1124
+ Ok(())
1125
+ }
1126
+
1083
1127
///////////////////////////////////////////////////////////////////////////
1084
1128
// CANDIDATE ASSEMBLY
1085
1129
//
@@ -1093,20 +1137,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1093
1137
fn candidate_from_obligation<'o>(
1094
1138
&mut self,
1095
1139
stack: &TraitObligationStack<'o, 'tcx>,
1140
+ recursion_depth: usize
1096
1141
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
1097
1142
// Watch out for overflow. This intentionally bypasses (and does
1098
1143
// not update) the cache.
1099
- let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
1100
- if stack.obligation.recursion_depth >= recursion_limit {
1101
- match self.query_mode {
1102
- TraitQueryMode::Standard => {
1103
- self.infcx().report_overflow_error(&stack.obligation, true);
1104
- }
1105
- TraitQueryMode::Canonical => {
1106
- return Err(Overflow);
1107
- }
1108
- }
1109
- }
1144
+ self.check_recursion_limit(stack.obligation.recursion_depth, &stack.obligation)?;
1110
1145
1111
1146
// Check the cache. Note that we freshen the trait-ref
1112
1147
// separately rather than using `stack.fresh_trait_ref` --
@@ -1128,7 +1163,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1128
1163
1129
1164
// If no match, compute result and insert into cache.
1130
1165
let (candidate, dep_node) =
1131
- self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
1166
+ self.in_task(|this| this.candidate_from_obligation_no_cache(stack, recursion_depth ));
1132
1167
1133
1168
debug!(
1134
1169
"CACHE MISS: SELECT({:?})={:?}",
@@ -1172,6 +1207,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1172
1207
fn candidate_from_obligation_no_cache<'o>(
1173
1208
&mut self,
1174
1209
stack: &TraitObligationStack<'o, 'tcx>,
1210
+ recursion_depth: usize
1175
1211
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
1176
1212
if stack.obligation.predicate.references_error() {
1177
1213
// If we encounter a `Error`, we generally prefer the
@@ -1189,13 +1225,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1189
1225
if self.intercrate_ambiguity_causes.is_some() {
1190
1226
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
1191
1227
// Heuristics: show the diagnostics when there are no candidates in crate.
1192
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
1228
+ if let Ok(candidate_set) = self.assemble_candidates(stack, recursion_depth ) {
1193
1229
let mut no_candidates_apply = true;
1194
1230
{
1195
1231
let evaluated_candidates = candidate_set
1196
1232
.vec
1197
1233
.iter()
1198
- .map(|c| self.evaluate_candidate(stack, &c));
1234
+ .map(|c| self.evaluate_candidate(stack, &c, recursion_depth ));
1199
1235
1200
1236
for ec in evaluated_candidates {
1201
1237
match ec {
@@ -1241,7 +1277,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1241
1277
return Ok(None);
1242
1278
}
1243
1279
1244
- let candidate_set = self.assemble_candidates(stack)?;
1280
+ let candidate_set = self.assemble_candidates(stack, recursion_depth )?;
1245
1281
1246
1282
if candidate_set.ambiguous {
1247
1283
debug!("candidate set contains ambig");
@@ -1288,7 +1324,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1288
1324
// is needed for specialization. Propagate overflow if it occurs.
1289
1325
let mut candidates = candidates
1290
1326
.into_iter()
1291
- .map(|c| match self.evaluate_candidate(stack, &c) {
1327
+ .map(|c| match self.evaluate_candidate(stack, &c, recursion_depth ) {
1292
1328
Ok(eval) if eval.may_apply() => Ok(Some(EvaluatedCandidate {
1293
1329
candidate: c,
1294
1330
evaluation: eval,
@@ -1526,6 +1562,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1526
1562
fn assemble_candidates<'o>(
1527
1563
&mut self,
1528
1564
stack: &TraitObligationStack<'o, 'tcx>,
1565
+ recursion_depth: usize
1529
1566
) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> {
1530
1567
let TraitObligationStack { obligation, .. } = *stack;
1531
1568
let ref obligation = Obligation {
@@ -1601,7 +1638,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1601
1638
}
1602
1639
1603
1640
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
1604
- self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
1641
+ self.assemble_candidates_from_caller_bounds(stack, &mut candidates, recursion_depth )?;
1605
1642
// Auto implementations have lower priority, so we only
1606
1643
// consider triggering a default if there is no other impl that can apply.
1607
1644
if candidates.vec.is_empty() {
@@ -1734,6 +1771,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1734
1771
&mut self,
1735
1772
stack: &TraitObligationStack<'o, 'tcx>,
1736
1773
candidates: &mut SelectionCandidateSet<'tcx>,
1774
+ recursion_depth: usize
1737
1775
) -> Result<(), SelectionError<'tcx>> {
1738
1776
debug!(
1739
1777
"assemble_candidates_from_caller_bounds({:?})",
@@ -1755,7 +1793,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1755
1793
// keep only those bounds which may apply, and propagate overflow if it occurs
1756
1794
let mut param_candidates = vec![];
1757
1795
for bound in matching_bounds {
1758
- let wc = self.evaluate_where_clause(stack, bound.clone())?;
1796
+ let wc = self.evaluate_where_clause(stack, bound.clone(), recursion_depth )?;
1759
1797
if wc.may_apply() {
1760
1798
param_candidates.push(ParamCandidate(bound));
1761
1799
}
@@ -1770,11 +1808,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1770
1808
&mut self,
1771
1809
stack: &TraitObligationStack<'o, 'tcx>,
1772
1810
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
1811
+ recursion_depth: usize
1773
1812
) -> Result<EvaluationResult, OverflowError> {
1774
1813
self.evaluation_probe(|this| {
1775
1814
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
1776
1815
Ok(obligations) => {
1777
- this.evaluate_predicates_recursively(stack.list(), obligations.iter())
1816
+ this.evaluate_predicates_recursively(stack.list(), obligations.iter(), recursion_depth )
1778
1817
}
1779
1818
Err(()) => Ok(EvaluatedToErr),
1780
1819
}
0 commit comments