From 6d54672acf431ceae0b057f45e0351e84793d9f2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 11 Dec 2018 14:18:30 -0500 Subject: [PATCH 01/10] Fix stack overflow when finding blanket impls Currently, SelectionContext tries to prevent stack overflow by keeping track of the current recursion depth. However, this depth tracking is only used when performing normal section (which includes confirmation). No such tracking is performed for evaluate_obligation_recursively, which can allow a stack overflow to occur. To fix this, this commit tracks the current predicate evaluation depth. This is done separately from the existing obligation depth tracking: an obligation overflow can occur across multiple calls to 'select' (e.g. when fulfilling a trait), while a predicate evaluation overflow can only happen as a result of a deep recursive call stack. Fixes #56701 --- src/librustc/traits/select.rs | 101 ++++++++++++++++++++++---------- src/test/rustdoc/issue-56701.rs | 34 +++++++++++ 2 files changed, 104 insertions(+), 31 deletions(-) create mode 100644 src/test/rustdoc/issue-56701.rs diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 373ec2d5e490f..ea5f199de2950 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -42,7 +42,7 @@ use rustc_data_structures::bit_set::GrowableBitSet; use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; use std::cmp; -use std::fmt; +use std::fmt::{self, Display}; use std::iter; use std::rc::Rc; use util::nodemap::{FxHashMap, FxHashSet}; @@ -573,7 +573,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let stack = self.push_stack(TraitObligationStackList::empty(), obligation); - let candidate = match self.candidate_from_obligation(&stack) { + // 'select' is an entry point into SelectionContext - we never call it recursively + // from within SelectionContext. Therefore, we start our recursion depth at 0 + let candidate = match self.candidate_from_obligation(&stack, 0) { Err(SelectionError::Overflow) => { // In standard mode, overflow must have been caught and reported // earlier. @@ -629,7 +631,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { self.evaluation_probe(|this| { - this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + // Like 'select', 'evaluate_obligation_recursively' is an entry point into + // SelectionContext, so our recursion depth is 0 + this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation, 0) }) } @@ -653,6 +657,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: TraitObligationStackList<'o, 'tcx>, predicates: I, + recursion_depth: usize ) -> Result where I: IntoIterator>, @@ -660,7 +665,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { let mut result = EvaluatedToOk; for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation)?; + let eval = self.evaluate_predicate_recursively(stack, obligation, recursion_depth)?; debug!( "evaluate_predicate_recursively({:?}) = {:?}", obligation, eval @@ -680,14 +685,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>, + mut recursion_depth: usize ) -> Result { - debug!("evaluate_predicate_recursively({:?})", obligation); + debug!("evaluate_predicate_recursively({:?}, recursion_depth={:?})", obligation, + recursion_depth); + + // We need to check for overflow here, since the normal + // recursion check uses the obligation from the stack. + // This is insufficient for two reasions: + // 1. That recursion depth is only incremented when a candidate is confirmed + // Since evaluation skips candidate confirmation, this will never happen + // 2. It relies on the trait obligation stack. However, it's possible for overflow + // to happen without involving the trait obligation stack. For example, + // we might end up trying to infinitely recurse with a projection predicate, + // which will never push anything onto the stack. + self.check_recursion_limit(recursion_depth, obligation)?; + + // Now that we know that the recursion check has passed, increment our depth + recursion_depth += 1; match obligation.predicate { ty::Predicate::Trait(ref t) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(t.clone()); - self.evaluate_trait_predicate_recursively(previous_stack, obligation) + self.evaluate_trait_predicate_recursively(previous_stack, obligation, recursion_depth) } ty::Predicate::Subtype(ref p) => { @@ -696,7 +717,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { obligations, .. })) => { - self.evaluate_predicates_recursively(previous_stack, &obligations) + self.evaluate_predicates_recursively(previous_stack, &obligations, recursion_depth) } Some(Err(_)) => Ok(EvaluatedToErr), None => Ok(EvaluatedToAmbig), @@ -711,7 +732,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.cause.span, ) { Some(obligations) => { - self.evaluate_predicates_recursively(previous_stack, obligations.iter()) + self.evaluate_predicates_recursively(previous_stack, obligations.iter(), recursion_depth) } None => Ok(EvaluatedToAmbig), }, @@ -737,6 +758,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let result = self.evaluate_predicates_recursively( previous_stack, subobligations.iter(), + recursion_depth ); if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate(self, data) @@ -795,6 +817,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, + recursion_depth: usize ) -> Result { debug!("evaluate_trait_predicate_recursively({:?})", obligation); @@ -822,7 +845,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(result); } - let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); + let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack, recursion_depth)); let result = result?; debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); @@ -834,6 +857,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_stack<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, + recursion_depth: usize ) -> Result { // In intercrate mode, whenever any of the types are unbound, // 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> { // Heuristics: show the diagnostics when there are no candidates in crate. if self.intercrate_ambiguity_causes.is_some() { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - if let Ok(candidate_set) = self.assemble_candidates(stack) { + if let Ok(candidate_set) = self.assemble_candidates(stack, recursion_depth) { if !candidate_set.ambiguous && candidate_set.vec.is_empty() { let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; let self_ty = trait_ref.self_ty(); @@ -955,8 +979,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), + match self.candidate_from_obligation(stack, recursion_depth) { + Ok(Some(c)) => self.evaluate_candidate(stack, &c, recursion_depth), Ok(None) => Ok(EvaluatedToAmbig), Err(Overflow) => Err(OverflowError), Err(..) => Ok(EvaluatedToErr), @@ -995,6 +1019,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, + recursion_depth: usize ) -> Result { debug!( "evaluate_candidate: depth={} candidate={:?}", @@ -1006,6 +1031,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(selection) => this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().iter(), + recursion_depth ), Err(..) => Ok(EvaluatedToErr), } @@ -1080,6 +1106,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .insert(trait_ref, WithDepNode::new(dep_node, result)); } + // The weird return type of this function allows it to be used with the 'try' (?) + // operator within certain functions + fn check_recursion_limit>(&self, recursion_depth: usize, obligation: &Obligation<'tcx, T>, + ) -> Result<(), OverflowError> { + let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); + if recursion_depth >= recursion_limit { + match self.query_mode { + TraitQueryMode::Standard => { + self.infcx().report_overflow_error(obligation, true); + } + TraitQueryMode::Canonical => { + return Err(OverflowError); + } + } + } + Ok(()) + } + /////////////////////////////////////////////////////////////////////////// // CANDIDATE ASSEMBLY // @@ -1093,20 +1137,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn candidate_from_obligation<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, + recursion_depth: usize ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. - let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); - if stack.obligation.recursion_depth >= recursion_limit { - match self.query_mode { - TraitQueryMode::Standard => { - self.infcx().report_overflow_error(&stack.obligation, true); - } - TraitQueryMode::Canonical => { - return Err(Overflow); - } - } - } + self.check_recursion_limit(stack.obligation.recursion_depth, &stack.obligation)?; // Check the cache. Note that we freshen the trait-ref // separately rather than using `stack.fresh_trait_ref` -- @@ -1128,7 +1163,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // If no match, compute result and insert into cache. let (candidate, dep_node) = - self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); + self.in_task(|this| this.candidate_from_obligation_no_cache(stack, recursion_depth)); debug!( "CACHE MISS: SELECT({:?})={:?}", @@ -1172,6 +1207,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn candidate_from_obligation_no_cache<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, + recursion_depth: usize ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if stack.obligation.predicate.references_error() { // If we encounter a `Error`, we generally prefer the @@ -1189,13 +1225,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if self.intercrate_ambiguity_causes.is_some() { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { + if let Ok(candidate_set) = self.assemble_candidates(stack, recursion_depth) { let mut no_candidates_apply = true; { let evaluated_candidates = candidate_set .vec .iter() - .map(|c| self.evaluate_candidate(stack, &c)); + .map(|c| self.evaluate_candidate(stack, &c, recursion_depth)); for ec in evaluated_candidates { match ec { @@ -1241,7 +1277,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(None); } - let candidate_set = self.assemble_candidates(stack)?; + let candidate_set = self.assemble_candidates(stack, recursion_depth)?; if candidate_set.ambiguous { debug!("candidate set contains ambig"); @@ -1288,7 +1324,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // is needed for specialization. Propagate overflow if it occurs. let mut candidates = candidates .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { + .map(|c| match self.evaluate_candidate(stack, &c, recursion_depth) { Ok(eval) if eval.may_apply() => Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval, @@ -1526,6 +1562,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, + recursion_depth: usize ) -> Result, SelectionError<'tcx>> { let TraitObligationStack { obligation, .. } = *stack; let ref obligation = Obligation { @@ -1601,7 +1638,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } self.assemble_candidates_from_projected_tys(obligation, &mut candidates); - self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; + self.assemble_candidates_from_caller_bounds(stack, &mut candidates, recursion_depth)?; // Auto implementations have lower priority, so we only // consider triggering a default if there is no other impl that can apply. if candidates.vec.is_empty() { @@ -1734,6 +1771,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, + recursion_depth: usize ) -> Result<(), SelectionError<'tcx>> { debug!( "assemble_candidates_from_caller_bounds({:?})", @@ -1755,7 +1793,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // keep only those bounds which may apply, and propagate overflow if it occurs let mut param_candidates = vec![]; for bound in matching_bounds { - let wc = self.evaluate_where_clause(stack, bound.clone())?; + let wc = self.evaluate_where_clause(stack, bound.clone(), recursion_depth)?; if wc.may_apply() { param_candidates.push(ParamCandidate(bound)); } @@ -1770,11 +1808,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, + recursion_depth: usize ) -> Result { self.evaluation_probe(|this| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.iter()) + this.evaluate_predicates_recursively(stack.list(), obligations.iter(), recursion_depth) } Err(()) => Ok(EvaluatedToErr), } diff --git a/src/test/rustdoc/issue-56701.rs b/src/test/rustdoc/issue-56701.rs new file mode 100644 index 0000000000000..6fb30a4ff4c30 --- /dev/null +++ b/src/test/rustdoc/issue-56701.rs @@ -0,0 +1,34 @@ +// This shouldn't cause a stack overflow when rustdoc is run + +use std::ops::Deref; +use std::ops::DerefMut; + +pub trait SimpleTrait { + type SimpleT; +} + +impl> SimpleTrait for Outer { + type SimpleT = Inner::SimpleT; +} + +pub trait AnotherTrait { + type AnotherT; +} + +impl>> AnotherTrait for Simple { + type AnotherT = T; +} + +pub struct Unrelated>>(UnrelatedT); + +impl>> Deref for Unrelated { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + + +pub fn main() { } + From c55c312c1721c80289915d8741d7f05d7c33de70 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 11 Dec 2018 14:48:12 -0500 Subject: [PATCH 02/10] Fix tidy errors --- src/librustc/traits/select.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index ea5f199de2950..54e015d1b37a5 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -657,7 +657,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: TraitObligationStackList<'o, 'tcx>, predicates: I, - recursion_depth: usize + recursion_depth: usize ) -> Result where I: IntoIterator>, @@ -708,7 +708,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::Trait(ref t) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(t.clone()); - self.evaluate_trait_predicate_recursively(previous_stack, obligation, recursion_depth) + self.evaluate_trait_predicate_recursively(previous_stack, obligation, + recursion_depth) } ty::Predicate::Subtype(ref p) => { @@ -717,7 +718,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { obligations, .. })) => { - self.evaluate_predicates_recursively(previous_stack, &obligations, recursion_depth) + self.evaluate_predicates_recursively(previous_stack, &obligations, + recursion_depth) } Some(Err(_)) => Ok(EvaluatedToErr), None => Ok(EvaluatedToAmbig), @@ -732,7 +734,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.cause.span, ) { Some(obligations) => { - self.evaluate_predicates_recursively(previous_stack, obligations.iter(), recursion_depth) + self.evaluate_predicates_recursively(previous_stack, obligations.iter(), + recursion_depth) } None => Ok(EvaluatedToAmbig), }, @@ -1108,7 +1111,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // The weird return type of this function allows it to be used with the 'try' (?) // operator within certain functions - fn check_recursion_limit>(&self, recursion_depth: usize, obligation: &Obligation<'tcx, T>, + fn check_recursion_limit>(&self, recursion_depth: usize, + obligation: &Obligation<'tcx, T>, ) -> Result<(), OverflowError> { let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); if recursion_depth >= recursion_limit { @@ -1813,7 +1817,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.evaluation_probe(|this| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.iter(), recursion_depth) + this.evaluate_predicates_recursively(stack.list(), obligations.iter(), + recursion_depth) } Err(()) => Ok(EvaluatedToErr), } From 54fd8caddc980a6ad47069d9674b4f59b1cd7da0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 19 Dec 2018 23:38:00 -0500 Subject: [PATCH 03/10] Remove extra recursion_depth tracking --- src/librustc/traits/select.rs | 104 ++++++++++++++-------------------- 1 file changed, 41 insertions(+), 63 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 54e015d1b37a5..7931943c90959 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -42,7 +42,7 @@ use rustc_data_structures::bit_set::GrowableBitSet; use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; use std::cmp; -use std::fmt::{self, Display}; +use std::fmt; use std::iter; use std::rc::Rc; use util::nodemap::{FxHashMap, FxHashSet}; @@ -573,9 +573,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let stack = self.push_stack(TraitObligationStackList::empty(), obligation); - // 'select' is an entry point into SelectionContext - we never call it recursively - // from within SelectionContext. Therefore, we start our recursion depth at 0 - let candidate = match self.candidate_from_obligation(&stack, 0) { + let candidate = match self.candidate_from_obligation(&stack) { Err(SelectionError::Overflow) => { // In standard mode, overflow must have been caught and reported // earlier. @@ -631,9 +629,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { self.evaluation_probe(|this| { - // Like 'select', 'evaluate_obligation_recursively' is an entry point into - // SelectionContext, so our recursion depth is 0 - this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation, 0) + this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation.clone()) }) } @@ -657,15 +653,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: TraitObligationStackList<'o, 'tcx>, predicates: I, - recursion_depth: usize ) -> Result where - I: IntoIterator>, + I: IntoIterator>, 'tcx: 'a, { let mut result = EvaluatedToOk; for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation, recursion_depth)?; + let eval = self.evaluate_predicate_recursively(stack, obligation)?; debug!( "evaluate_predicate_recursively({:?}) = {:?}", obligation, eval @@ -684,32 +679,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: &PredicateObligation<'tcx>, - mut recursion_depth: usize + obligation: PredicateObligation<'tcx>, ) -> Result { - debug!("evaluate_predicate_recursively({:?}, recursion_depth={:?})", obligation, - recursion_depth); - - // We need to check for overflow here, since the normal - // recursion check uses the obligation from the stack. - // This is insufficient for two reasions: - // 1. That recursion depth is only incremented when a candidate is confirmed - // Since evaluation skips candidate confirmation, this will never happen - // 2. It relies on the trait obligation stack. However, it's possible for overflow - // to happen without involving the trait obligation stack. For example, - // we might end up trying to infinitely recurse with a projection predicate, - // which will never push anything onto the stack. - self.check_recursion_limit(recursion_depth, obligation)?; - - // Now that we know that the recursion check has passed, increment our depth - recursion_depth += 1; + debug!("evaluate_predicate_recursively({:?})", obligation); + self.check_recursion_limit(obligation)?; match obligation.predicate { ty::Predicate::Trait(ref t) => { debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(t.clone()); - self.evaluate_trait_predicate_recursively(previous_stack, obligation, - recursion_depth) + let mut obligation = obligation.with(t.clone()); + obligation.recursion_depth += 1 + self.evaluate_trait_predicate_recursively(previous_stack, obligation) } ty::Predicate::Subtype(ref p) => { @@ -718,8 +698,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { obligations, .. })) => { - self.evaluate_predicates_recursively(previous_stack, &obligations, - recursion_depth) + for o in obligations.iter_mut() { + o.recursion_depth += 1 + } + self.evaluate_predicates_recursively(previous_stack, obligation.into_iter()) } Some(Err(_)) => Ok(EvaluatedToErr), None => Ok(EvaluatedToAmbig), @@ -734,8 +716,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.cause.span, ) { Some(obligations) => { - self.evaluate_predicates_recursively(previous_stack, obligations.iter(), - recursion_depth) + for o in obligations.iter_mut() { + o.recursion_depth += 1 + } + self.evaluate_predicates_recursively(previous_stack, obligations.iter()) } None => Ok(EvaluatedToAmbig), }, @@ -758,10 +742,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let project_obligation = obligation.with(data.clone()); match project::poly_project_and_unify_type(self, &project_obligation) { Ok(Some(subobligations)) => { + for o in subobligations.iter_mut() { + o.recursion_depth += 1 + } let result = self.evaluate_predicates_recursively( previous_stack, - subobligations.iter(), - recursion_depth + subobligations.into_iter(), ); if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate(self, data) @@ -820,7 +806,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, - recursion_depth: usize ) -> Result { debug!("evaluate_trait_predicate_recursively({:?})", obligation); @@ -848,7 +833,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(result); } - let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack, recursion_depth)); + let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); let result = result?; debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); @@ -860,7 +845,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_stack<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, - recursion_depth: usize ) -> Result { // In intercrate mode, whenever any of the types are unbound, // there can always be an impl. Even if there are no impls in @@ -901,7 +885,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Heuristics: show the diagnostics when there are no candidates in crate. if self.intercrate_ambiguity_causes.is_some() { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - if let Ok(candidate_set) = self.assemble_candidates(stack, recursion_depth) { + if let Ok(candidate_set) = self.assemble_candidates(stack) { if !candidate_set.ambiguous && candidate_set.vec.is_empty() { let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; let self_ty = trait_ref.self_ty(); @@ -982,8 +966,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - match self.candidate_from_obligation(stack, recursion_depth) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c, recursion_depth), + match self.candidate_from_obligation(stack) { + Ok(Some(c)) => self.evaluate_candidate(stack, &c), Ok(None) => Ok(EvaluatedToAmbig), Err(Overflow) => Err(OverflowError), Err(..) => Ok(EvaluatedToErr), @@ -1022,7 +1006,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, - recursion_depth: usize ) -> Result { debug!( "evaluate_candidate: depth={} candidate={:?}", @@ -1034,7 +1017,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(selection) => this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().iter(), - recursion_depth ), Err(..) => Ok(EvaluatedToErr), } @@ -1109,13 +1091,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .insert(trait_ref, WithDepNode::new(dep_node, result)); } + // Check that the recursion limit has not been exceeded. + // // The weird return type of this function allows it to be used with the 'try' (?) // operator within certain functions - fn check_recursion_limit>(&self, recursion_depth: usize, - obligation: &Obligation<'tcx, T>, + fn check_recursion_limit>(&self, obligation: &Obligation<'tcx, T>, ) -> Result<(), OverflowError> { let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); - if recursion_depth >= recursion_limit { + if obligaton.recursion_depth >= recursion_limit { match self.query_mode { TraitQueryMode::Standard => { self.infcx().report_overflow_error(obligation, true); @@ -1141,11 +1124,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn candidate_from_obligation<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, - recursion_depth: usize ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. - self.check_recursion_limit(stack.obligation.recursion_depth, &stack.obligation)?; + self.check_recursion_limit(&stack.obligation)?; + // Check the cache. Note that we freshen the trait-ref // separately rather than using `stack.fresh_trait_ref` -- @@ -1167,7 +1150,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // If no match, compute result and insert into cache. let (candidate, dep_node) = - self.in_task(|this| this.candidate_from_obligation_no_cache(stack, recursion_depth)); + self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); debug!( "CACHE MISS: SELECT({:?})={:?}", @@ -1211,7 +1194,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn candidate_from_obligation_no_cache<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, - recursion_depth: usize ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if stack.obligation.predicate.references_error() { // If we encounter a `Error`, we generally prefer the @@ -1229,13 +1211,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if self.intercrate_ambiguity_causes.is_some() { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack, recursion_depth) { + if let Ok(candidate_set) = self.assemble_candidates(stack) { let mut no_candidates_apply = true; { let evaluated_candidates = candidate_set .vec .iter() - .map(|c| self.evaluate_candidate(stack, &c, recursion_depth)); + .map(|c| self.evaluate_candidate(stack, &c)); for ec in evaluated_candidates { match ec { @@ -1281,7 +1263,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(None); } - let candidate_set = self.assemble_candidates(stack, recursion_depth)?; + let candidate_set = self.assemble_candidates(stack)?; if candidate_set.ambiguous { debug!("candidate set contains ambig"); @@ -1328,7 +1310,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // is needed for specialization. Propagate overflow if it occurs. let mut candidates = candidates .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c, recursion_depth) { + .map(|c| match self.evaluate_candidate(stack, &c) { Ok(eval) if eval.may_apply() => Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval, @@ -1566,7 +1548,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, - recursion_depth: usize ) -> Result, SelectionError<'tcx>> { let TraitObligationStack { obligation, .. } = *stack; let ref obligation = Obligation { @@ -1642,7 +1623,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } self.assemble_candidates_from_projected_tys(obligation, &mut candidates); - self.assemble_candidates_from_caller_bounds(stack, &mut candidates, recursion_depth)?; + self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; // Auto implementations have lower priority, so we only // consider triggering a default if there is no other impl that can apply. if candidates.vec.is_empty() { @@ -1775,7 +1756,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, - recursion_depth: usize ) -> Result<(), SelectionError<'tcx>> { debug!( "assemble_candidates_from_caller_bounds({:?})", @@ -1797,7 +1777,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // keep only those bounds which may apply, and propagate overflow if it occurs let mut param_candidates = vec![]; for bound in matching_bounds { - let wc = self.evaluate_where_clause(stack, bound.clone(), recursion_depth)?; + let wc = self.evaluate_where_clause(stack, bound.clone())?; if wc.may_apply() { param_candidates.push(ParamCandidate(bound)); } @@ -1812,13 +1792,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - recursion_depth: usize ) -> Result { self.evaluation_probe(|this| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.iter(), - recursion_depth) + this.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => Ok(EvaluatedToErr), } From 03cd934ba9f7ceb1a1b048b6ed9caa0956a1bd8d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 20 Dec 2018 04:02:12 -0500 Subject: [PATCH 04/10] Ensure that we properly increment obligation depth --- src/librustc/traits/select.rs | 45 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7931943c90959..2eb717c7c7f5f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -42,7 +42,7 @@ use rustc_data_structures::bit_set::GrowableBitSet; use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; use std::cmp; -use std::fmt; +use std::fmt::{self, Display}; use std::iter; use std::rc::Rc; use util::nodemap::{FxHashMap, FxHashSet}; @@ -660,7 +660,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { let mut result = EvaluatedToOk; for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation)?; + let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; debug!( "evaluate_predicate_recursively({:?}) = {:?}", obligation, eval @@ -682,13 +682,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: PredicateObligation<'tcx>, ) -> Result { debug!("evaluate_predicate_recursively({:?})", obligation); - self.check_recursion_limit(obligation)?; + self.check_recursion_limit(&obligation)?; match obligation.predicate { ty::Predicate::Trait(ref t) => { debug_assert!(!t.has_escaping_bound_vars()); let mut obligation = obligation.with(t.clone()); - obligation.recursion_depth += 1 + obligation.recursion_depth += 1; self.evaluate_trait_predicate_recursively(previous_stack, obligation) } @@ -697,11 +697,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match self.infcx .subtype_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { obligations, .. })) => { - for o in obligations.iter_mut() { - o.recursion_depth += 1 - } - self.evaluate_predicates_recursively(previous_stack, obligation.into_iter()) + Some(Ok(InferOk { mut obligations, .. })) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) } Some(Err(_)) => Ok(EvaluatedToErr), None => Ok(EvaluatedToAmbig), @@ -715,11 +713,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty, obligation.cause.span, ) { - Some(obligations) => { - for o in obligations.iter_mut() { - o.recursion_depth += 1 - } - self.evaluate_predicates_recursively(previous_stack, obligations.iter()) + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) } None => Ok(EvaluatedToAmbig), }, @@ -741,10 +737,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::Projection(ref data) => { let project_obligation = obligation.with(data.clone()); match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Some(subobligations)) => { - for o in subobligations.iter_mut() { - o.recursion_depth += 1 - } + Ok(Some(mut subobligations)) => { + self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); let result = self.evaluate_predicates_recursively( previous_stack, subobligations.into_iter(), @@ -1016,7 +1010,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match this.confirm_candidate(stack.obligation, candidate) { Ok(selection) => this.evaluate_predicates_recursively( stack.list(), - selection.nested_obligations().iter(), + selection.nested_obligations().into_iter(), ), Err(..) => Ok(EvaluatedToErr), } @@ -1091,6 +1085,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .insert(trait_ref, WithDepNode::new(dep_node, result)); } + // Due to caching of projection results, it's possible for a subobligation + // to have a *lower* recursion_depth than the obligation used to create it. + // To ensure that obligation_depth never decreasees, we force all subobligations + // to have at least the depth of the original obligation. + fn add_depth>>(&self, it: I, + min_depth: usize) { + it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); + } + // Check that the recursion limit has not been exceeded. // // The weird return type of this function allows it to be used with the 'try' (?) @@ -1098,7 +1101,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn check_recursion_limit>(&self, obligation: &Obligation<'tcx, T>, ) -> Result<(), OverflowError> { let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); - if obligaton.recursion_depth >= recursion_limit { + if obligation.recursion_depth >= recursion_limit { match self.query_mode { TraitQueryMode::Standard => { self.infcx().report_overflow_error(obligation, true); @@ -1796,7 +1799,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.evaluation_probe(|this| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.iter()) + this.evaluate_predicates_recursively(stack.list(), obligations.into_iter()) } Err(()) => Ok(EvaluatedToErr), } From 1f08280555aa07a3070806049b0e270dde6fc483 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 20 Dec 2018 04:03:40 -0500 Subject: [PATCH 05/10] More tidy fixes --- src/librustc/traits/select.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2eb717c7c7f5f..0c0d68c9b36b1 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -629,7 +629,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { self.evaluation_probe(|this| { - this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation.clone()) + this.evaluate_predicate_recursively(TraitObligationStackList::empty(), + obligation.clone()) }) } @@ -699,7 +700,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { Some(Ok(InferOk { mut obligations, .. })) => { self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + self.evaluate_predicates_recursively(previous_stack,obligations.into_iter()) } Some(Err(_)) => Ok(EvaluatedToErr), None => Ok(EvaluatedToAmbig), @@ -1098,7 +1099,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // // The weird return type of this function allows it to be used with the 'try' (?) // operator within certain functions - fn check_recursion_limit>(&self, obligation: &Obligation<'tcx, T>, + fn check_recursion_limit>(&self,obligation:&Obligation<'tcx, T>, ) -> Result<(), OverflowError> { let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); if obligation.recursion_depth >= recursion_limit { From b1a8da6e6170ce3749d917e614bb28ad8dcb9ac0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 2 Jan 2019 21:19:03 -0500 Subject: [PATCH 06/10] Improve error generation, fixup recursion limits --- src/librustc/traits/select.rs | 34 +++++++++++++++---- src/test/run-pass/weird-exprs.rs | 2 +- .../ui/did_you_mean/recursion_limit.stderr | 8 +---- src/test/ui/error-codes/E0055.rs | 4 +-- src/test/ui/error-codes/E0055.stderr | 2 +- src/test/ui/error-codes/E0275.stderr | 34 +------------------ src/test/ui/issues/issue-20413.stderr | 34 +------------------ 7 files changed, 35 insertions(+), 83 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 0c0d68c9b36b1..75ed8ddcefea4 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -682,8 +682,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: PredicateObligation<'tcx>, ) -> Result { - debug!("evaluate_predicate_recursively({:?})", obligation); - self.check_recursion_limit(&obligation)?; + debug!("evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})", + previous_stack.head(), obligation); + + // Previous_stack stores a TraitObligatiom, while 'obligation' is + // a PredicateObligation. These are distinct types, so we can't + // use any Option combinator method that would force them to be + // the same + match previous_stack.head() { + Some(h) => self.check_recursion_limit(&obligation, h.obligation)?, + None => self.check_recursion_limit(&obligation, &obligation)? + } + + //self.check_recursion_limit(&obligation, previous_stack.head() + // .map_or(&obligation, |s| s.obligation))?; match obligation.predicate { ty::Predicate::Trait(ref t) => { @@ -1011,7 +1023,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match this.confirm_candidate(stack.obligation, candidate) { Ok(selection) => this.evaluate_predicates_recursively( stack.list(), - selection.nested_obligations().into_iter(), + selection.nested_obligations().into_iter().map(|o| { + //o.recursion_depth = 0; + o + }) ), Err(..) => Ok(EvaluatedToErr), } @@ -1099,13 +1114,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // // The weird return type of this function allows it to be used with the 'try' (?) // operator within certain functions - fn check_recursion_limit>(&self,obligation:&Obligation<'tcx, T>, + fn check_recursion_limit, V: Display + TypeFoldable<'tcx>>( + &self, + obligation: &Obligation<'tcx, T>, + error_obligation: &Obligation<'tcx, V> ) -> Result<(), OverflowError> { let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); if obligation.recursion_depth >= recursion_limit { match self.query_mode { TraitQueryMode::Standard => { - self.infcx().report_overflow_error(obligation, true); + self.infcx().report_overflow_error(error_obligation, true); } TraitQueryMode::Canonical => { return Err(OverflowError); @@ -1131,7 +1149,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. - self.check_recursion_limit(&stack.obligation)?; + self.check_recursion_limit(&stack.obligation, &stack.obligation)?; // Check the cache. Note that we freshen the trait-ref @@ -3826,6 +3844,10 @@ impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> { TraitObligationStackList { head: Some(r) } } + + fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { + self.head + } } impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> { diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index 6d0c5c11732f2..7ce7e29e87235 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -4,7 +4,7 @@ #![allow(unused_parens)] // compile-flags: -Z borrowck=compare -#![recursion_limit = "128"] +#![recursion_limit = "256"] use std::cell::Cell; use std::mem::swap; diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index 08947fd7fdcba..292a80faa7420 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,16 +1,10 @@ -error[E0275]: overflow evaluating the requirement `K: std::marker::Send` +error[E0275]: overflow evaluating the requirement `E: std::marker::Send` --> $DIR/recursion_limit.rs:34:5 | LL | is_send::(); //~ ERROR overflow evaluating the requirement | ^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="20"]` attribute to your crate - = note: required because it appears within the type `J` - = note: required because it appears within the type `I` - = note: required because it appears within the type `H` - = note: required because it appears within the type `G` - = note: required because it appears within the type `F` - = note: required because it appears within the type `E` = note: required because it appears within the type `D` = note: required because it appears within the type `C` = note: required because it appears within the type `B` diff --git a/src/test/ui/error-codes/E0055.rs b/src/test/ui/error-codes/E0055.rs index a3ade92d24f4c..b525575d98d46 100644 --- a/src/test/ui/error-codes/E0055.rs +++ b/src/test/ui/error-codes/E0055.rs @@ -1,4 +1,4 @@ -#![recursion_limit="2"] +#![recursion_limit="5"] struct Foo; impl Foo { @@ -7,7 +7,7 @@ impl Foo { fn main() { let foo = Foo; - let ref_foo = &&Foo; + let ref_foo = &&&&&Foo; ref_foo.foo(); //~^ ERROR E0055 } diff --git a/src/test/ui/error-codes/E0055.stderr b/src/test/ui/error-codes/E0055.stderr index cd2bd923d5a0f..d06566ffbe9a9 100644 --- a/src/test/ui/error-codes/E0055.stderr +++ b/src/test/ui/error-codes/E0055.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | ref_foo.foo(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="4"]` attribute to your crate + = help: consider adding a `#![recursion_limit="10"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index 817b4828cc4ab..df3b362f82401 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -1,42 +1,10 @@ -error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: std::marker::Sized` --> $DIR/E0275.rs:5:1 | LL | impl Foo for T where Bar: Foo {} //~ ERROR E0275 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="128"]` attribute to your crate - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index 20e57583f1daa..043df0e392b45 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -6,7 +6,7 @@ LL | struct NoData; | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` -error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: std::marker::Sized` --> $DIR/issue-20413.rs:8:1 | LL | / impl Foo for T where NoData: Foo { @@ -18,38 +18,6 @@ LL | | } | |_^ | = help: consider adding a `#![recursion_limit="128"]` attribute to your crate - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` From 9a64d79365fb0eaa52afb0be9265c86d9fe3e490 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 2 Jan 2019 21:21:47 -0500 Subject: [PATCH 07/10] Cleanup code --- src/librustc/traits/select.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 75ed8ddcefea4..e5eb8e24a427d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -694,9 +694,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)? } - //self.check_recursion_limit(&obligation, previous_stack.head() - // .map_or(&obligation, |s| s.obligation))?; - match obligation.predicate { ty::Predicate::Trait(ref t) => { debug_assert!(!t.has_escaping_bound_vars()); @@ -1023,10 +1020,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match this.confirm_candidate(stack.obligation, candidate) { Ok(selection) => this.evaluate_predicates_recursively( stack.list(), - selection.nested_obligations().into_iter().map(|o| { - //o.recursion_depth = 0; - o - }) + selection.nested_obligations().into_iter() ), Err(..) => Ok(EvaluatedToErr), } From dadd7bb6f46b1d646abedcb327b4da111caf042e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 3 Jan 2019 01:30:30 -0500 Subject: [PATCH 08/10] Fix diagnostic error --- src/librustc_typeck/diagnostics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 5910a8b3110d0..0645db66c69f6 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -516,7 +516,7 @@ recursion limit (which can be set via the `recursion_limit` attribute). For a somewhat artificial example: ```compile_fail,E0055 -#![recursion_limit="2"] +#![recursion_limit="5"] struct Foo; @@ -526,9 +526,9 @@ impl Foo { fn main() { let foo = Foo; - let ref_foo = &&Foo; + let ref_foo = &&&&&Foo; - // error, reached the recursion limit while auto-dereferencing `&&Foo` + // error, reached the recursion limit while auto-dereferencing `&&&&&Foo` ref_foo.foo(); } ``` From 726bdec60f8ef8c9dbb57a87cc5f2a03763b1f70 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 3 Jan 2019 22:15:38 -0500 Subject: [PATCH 09/10] Improve comment --- src/librustc/traits/select.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e5eb8e24a427d..8b9863fa27879 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1095,8 +1095,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .insert(trait_ref, WithDepNode::new(dep_node, result)); } - // Due to caching of projection results, it's possible for a subobligation + // For various reasons, it's possible for a subobligation // to have a *lower* recursion_depth than the obligation used to create it. + // Projection sub-obligations may be returned from the projection cache, + // which results in obligations with an 'old' recursion_depth. + // Additionally, methods like ty::wf::obligations and + // InferCtxt.subtype_predicate produce subobligations without + // taking in a 'parent' depth, causing the generated subobligations + // to have a recursion_depth of 0 + // // To ensure that obligation_depth never decreasees, we force all subobligations // to have at least the depth of the original obligation. fn add_depth>>(&self, it: I, From 9b68dcd32a1be5d219a6bcedc2c9fc63d6d463a4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 16 Jan 2019 12:55:22 -0500 Subject: [PATCH 10/10] Don't explicitly increment the depth for new trait predicates --- src/librustc/traits/select.rs | 3 +- .../ui/did_you_mean/recursion_limit.stderr | 7 +++- src/test/ui/error-codes/E0275.stderr | 33 ++++++++++++++++++- src/test/ui/issues/issue-20413.stderr | 33 ++++++++++++++++++- 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 8b9863fa27879..718f7a6d8573b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -697,8 +697,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match obligation.predicate { ty::Predicate::Trait(ref t) => { debug_assert!(!t.has_escaping_bound_vars()); - let mut obligation = obligation.with(t.clone()); - obligation.recursion_depth += 1; + let obligation = obligation.with(t.clone()); self.evaluate_trait_predicate_recursively(previous_stack, obligation) } diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index 292a80faa7420..0738c3f65b95f 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,10 +1,15 @@ -error[E0275]: overflow evaluating the requirement `E: std::marker::Send` +error[E0275]: overflow evaluating the requirement `J: std::marker::Send` --> $DIR/recursion_limit.rs:34:5 | LL | is_send::(); //~ ERROR overflow evaluating the requirement | ^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="20"]` attribute to your crate + = note: required because it appears within the type `I` + = note: required because it appears within the type `H` + = note: required because it appears within the type `G` + = note: required because it appears within the type `F` + = note: required because it appears within the type `E` = note: required because it appears within the type `D` = note: required because it appears within the type `C` = note: required because it appears within the type `B` diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index df3b362f82401..f2b0f392bc8bc 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -1,10 +1,41 @@ -error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/E0275.rs:5:1 | LL | impl Foo for T where Bar: Foo {} //~ ERROR E0275 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index 043df0e392b45..1c353fec8aabf 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -6,7 +6,7 @@ LL | struct NoData; | = help: consider removing `T` or using a marker such as `std::marker::PhantomData` -error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:1 | LL | / impl Foo for T where NoData: Foo { @@ -18,6 +18,37 @@ LL | | } | |_^ | = help: consider adding a `#![recursion_limit="128"]` attribute to your crate + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`