Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4d71fe7

Browse files
authoredMar 1, 2024
Rollup merge of #121497 - lcnr:coherence-suggest-increasing-recursion-limit, r=compiler-errors
`-Znext-solver=coherence`: suggest increasing recursion limit r? `@compiler-errors`
2 parents b8cdcfa + 8c5e83d commit 4d71fe7

29 files changed

+342
-256
lines changed
 

‎compiler/rustc_infer/src/traits/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,18 @@ pub struct FulfillmentError<'tcx> {
135135

136136
#[derive(Clone)]
137137
pub enum FulfillmentErrorCode<'tcx> {
138-
/// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
138+
/// Inherently impossible to fulfill; this trait is implemented if and only
139+
/// if it is already implemented.
139140
Cycle(Vec<PredicateObligation<'tcx>>),
140141
SelectionError(SelectionError<'tcx>),
141142
ProjectionError(MismatchedProjectionTypes<'tcx>),
142143
SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
143144
ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
144145
Ambiguity {
145-
/// Overflow reported from the new solver `-Znext-solver`, which will
146-
/// be reported as an regular error as opposed to a fatal error.
147-
overflow: bool,
146+
/// Overflow is only `Some(suggest_recursion_limit)` when using the next generation
147+
/// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by
148+
/// emitting a fatal error instead.
149+
overflow: Option<bool>,
148150
},
149151
}
150152

‎compiler/rustc_infer/src/traits/structural_impls.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
4747
ConstEquateError(ref a, ref b) => {
4848
write!(f, "CodeConstEquateError({a:?}, {b:?})")
4949
}
50-
Ambiguity { overflow: false } => write!(f, "Ambiguity"),
51-
Ambiguity { overflow: true } => write!(f, "Overflow"),
50+
Ambiguity { overflow: None } => write!(f, "Ambiguity"),
51+
Ambiguity { overflow: Some(suggest_increasing_limit) } => {
52+
write!(f, "Overflow({suggest_increasing_limit})")
53+
}
5254
Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"),
5355
}
5456
}

‎compiler/rustc_middle/src/traits/solve.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ pub enum Certainty {
6060

6161
impl Certainty {
6262
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
63-
pub const OVERFLOW: Certainty = Certainty::Maybe(MaybeCause::Overflow);
6463

6564
/// Use this function to merge the certainty of multiple nested subgoals.
6665
///
@@ -79,16 +78,13 @@ impl Certainty {
7978
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
8079
(Certainty::Yes, Certainty::Maybe(_)) => other,
8180
(Certainty::Maybe(_), Certainty::Yes) => self,
82-
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
83-
Certainty::Maybe(MaybeCause::Ambiguity)
84-
}
85-
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow))
86-
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity))
87-
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
88-
Certainty::Maybe(MaybeCause::Overflow)
89-
}
81+
(Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
9082
}
9183
}
84+
85+
pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
86+
Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
87+
}
9288
}
9389

9490
/// Why we failed to evaluate a goal.
@@ -99,7 +95,21 @@ pub enum MaybeCause {
9995
/// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
10096
Ambiguity,
10197
/// We gave up due to an overflow, most often by hitting the recursion limit.
102-
Overflow,
98+
Overflow { suggest_increasing_limit: bool },
99+
}
100+
101+
impl MaybeCause {
102+
fn unify_with(self, other: MaybeCause) -> MaybeCause {
103+
match (self, other) {
104+
(MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
105+
(MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
106+
(MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
107+
(
108+
MaybeCause::Overflow { suggest_increasing_limit: a },
109+
MaybeCause::Overflow { suggest_increasing_limit: b },
110+
) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
111+
}
112+
}
103113
}
104114

105115
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]

‎compiler/rustc_trait_selection/src/solve/alias_relate.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3636
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
3737

3838
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
39-
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
39+
return self
40+
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
4041
};
4142

4243
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
43-
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
44+
return self
45+
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
4446
};
4547

4648
let variance = match direction {

‎compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_infer::infer::{
77
BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
88
};
99
use rustc_infer::traits::query::NoSolution;
10+
use rustc_infer::traits::solve::MaybeCause;
1011
use rustc_infer::traits::ObligationCause;
1112
use rustc_middle::infer::canonical::CanonicalVarInfos;
1213
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
@@ -29,7 +30,7 @@ use std::ops::ControlFlow;
2930
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
3031

3132
use super::inspect::ProofTreeBuilder;
32-
use super::{search_graph, GoalEvaluationKind};
33+
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
3334
use super::{search_graph::SearchGraph, Goal};
3435
use super::{GoalSource, SolverMode};
3536
pub use select::InferCtxtSelectExt;
@@ -154,10 +155,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
154155
self.search_graph.solver_mode()
155156
}
156157

157-
pub(super) fn local_overflow_limit(&self) -> usize {
158-
self.search_graph.local_overflow_limit()
159-
}
160-
161158
/// Creates a root evaluation context and search graph. This should only be
162159
/// used from outside of any evaluation, and other methods should be preferred
163160
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
@@ -167,7 +164,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
167164
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
168165
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
169166
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
170-
let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode);
167+
let mut search_graph = search_graph::SearchGraph::new(mode);
171168

172169
let mut ecx = EvalCtxt {
173170
search_graph: &mut search_graph,
@@ -388,16 +385,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
388385
&& source != GoalSource::ImplWhereBound
389386
};
390387

391-
if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
392-
(Certainty::OVERFLOW, false)
393-
} else {
394-
let has_changed = !response.value.var_values.is_identity_modulo_regions()
395-
|| !response.value.external_constraints.opaque_types.is_empty();
396-
397-
let certainty =
398-
self.instantiate_and_apply_query_response(param_env, original_values, response);
399-
(certainty, has_changed)
388+
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty
389+
&& !keep_overflow_constraints()
390+
{
391+
return (response.value.certainty, false);
400392
}
393+
394+
let has_changed = !response.value.var_values.is_identity_modulo_regions()
395+
|| !response.value.external_constraints.opaque_types.is_empty();
396+
397+
let certainty =
398+
self.instantiate_and_apply_query_response(param_env, original_values, response);
399+
(certainty, has_changed)
401400
}
402401

403402
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
@@ -466,8 +465,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
466465
let inspect = self.inspect.new_evaluate_added_goals();
467466
let inspect = core::mem::replace(&mut self.inspect, inspect);
468467

469-
let mut response = Ok(Certainty::OVERFLOW);
470-
for _ in 0..self.local_overflow_limit() {
468+
let mut response = Ok(Certainty::overflow(false));
469+
for _ in 0..FIXPOINT_STEP_LIMIT {
471470
// FIXME: This match is a bit ugly, it might be nice to change the inspect
472471
// stuff to use a closure instead. which should hopefully simplify this a bit.
473472
match self.evaluate_added_goals_step() {

‎compiler/rustc_trait_selection/src/solve/fulfill.rs

Lines changed: 147 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use super::{Certainty, InferCtxtEvalExt};
2424
/// It is also likely that we want to use slightly different datastructures
2525
/// here as this will have to deal with far more root goals than `evaluate_all`.
2626
pub struct FulfillmentCtxt<'tcx> {
27-
obligations: Vec<PredicateObligation<'tcx>>,
27+
obligations: ObligationStorage<'tcx>,
2828

2929
/// The snapshot in which this context was created. Using the context
3030
/// outside of this snapshot leads to subtle bugs if the snapshot
@@ -33,14 +33,68 @@ pub struct FulfillmentCtxt<'tcx> {
3333
usable_in_snapshot: usize,
3434
}
3535

36+
#[derive(Default)]
37+
struct ObligationStorage<'tcx> {
38+
/// Obligations which resulted in an overflow in fulfillment itself.
39+
///
40+
/// We cannot eagerly return these as error so we instead store them here
41+
/// to avoid recomputing them each time `select_where_possible` is called.
42+
/// This also allows us to return the correct `FulfillmentError` for them.
43+
overflowed: Vec<PredicateObligation<'tcx>>,
44+
pending: Vec<PredicateObligation<'tcx>>,
45+
}
46+
47+
impl<'tcx> ObligationStorage<'tcx> {
48+
fn register(&mut self, obligation: PredicateObligation<'tcx>) {
49+
self.pending.push(obligation);
50+
}
51+
52+
fn clone_pending(&self) -> Vec<PredicateObligation<'tcx>> {
53+
let mut obligations = self.pending.clone();
54+
obligations.extend(self.overflowed.iter().cloned());
55+
obligations
56+
}
57+
58+
fn take_pending(&mut self) -> Vec<PredicateObligation<'tcx>> {
59+
let mut obligations = mem::take(&mut self.pending);
60+
obligations.extend(self.overflowed.drain(..));
61+
obligations
62+
}
63+
64+
fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> {
65+
mem::take(&mut self.pending).into_iter()
66+
}
67+
68+
fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
69+
infcx.probe(|_| {
70+
// IMPORTANT: we must not use solve any inference variables in the obligations
71+
// as this is all happening inside of a probe. We use a probe to make sure
72+
// we get all obligations involved in the overflow. We pretty much check: if
73+
// we were to do another step of `select_where_possible`, which goals would
74+
// change.
75+
self.overflowed.extend(self.pending.extract_if(|o| {
76+
let goal = o.clone().into();
77+
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::Never).0;
78+
match result {
79+
Ok((has_changed, _)) => has_changed,
80+
_ => false,
81+
}
82+
}));
83+
})
84+
}
85+
}
86+
3687
impl<'tcx> FulfillmentCtxt<'tcx> {
3788
pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
3889
assert!(
3990
infcx.next_trait_solver(),
4091
"new trait solver fulfillment context created when \
4192
infcx is set up for old trait solver"
4293
);
43-
FulfillmentCtxt { obligations: Vec::new(), usable_in_snapshot: infcx.num_open_snapshots() }
94+
FulfillmentCtxt {
95+
obligations: Default::default(),
96+
usable_in_snapshot: infcx.num_open_snapshots(),
97+
}
4498
}
4599

46100
fn inspect_evaluated_obligation(
@@ -67,120 +121,52 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
67121
obligation: PredicateObligation<'tcx>,
68122
) {
69123
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
70-
self.obligations.push(obligation);
124+
self.obligations.register(obligation);
71125
}
72126

73127
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
74-
self.obligations
128+
let mut errors: Vec<_> = self
129+
.obligations
130+
.pending
75131
.drain(..)
76-
.map(|obligation| {
77-
let code = infcx.probe(|_| {
78-
match infcx
79-
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled)
80-
.0
81-
{
82-
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
83-
FulfillmentErrorCode::Ambiguity { overflow: false }
84-
}
85-
Ok((_, Certainty::Maybe(MaybeCause::Overflow))) => {
86-
FulfillmentErrorCode::Ambiguity { overflow: true }
87-
}
88-
Ok((_, Certainty::Yes)) => {
89-
bug!("did not expect successful goal when collecting ambiguity errors")
90-
}
91-
Err(_) => {
92-
bug!("did not expect selection error when collecting ambiguity errors")
93-
}
94-
}
95-
});
132+
.map(|obligation| fulfillment_error_for_stalled(infcx, obligation))
133+
.collect();
96134

97-
FulfillmentError {
98-
obligation: obligation.clone(),
99-
code,
100-
root_obligation: obligation,
101-
}
102-
})
103-
.collect()
135+
errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError {
136+
root_obligation: obligation.clone(),
137+
code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
138+
obligation,
139+
}));
140+
141+
errors
104142
}
105143

106144
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
107145
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
108146
let mut errors = Vec::new();
109147
for i in 0.. {
110148
if !infcx.tcx.recursion_limit().value_within_limit(i) {
111-
// Only return true errors that we have accumulated while processing;
112-
// keep ambiguities around, *including overflows*, because they shouldn't
113-
// be considered true errors.
149+
self.obligations.on_fulfillment_overflow(infcx);
150+
// Only return true errors that we have accumulated while processing.
114151
return errors;
115152
}
116153

117154
let mut has_changed = false;
118-
for obligation in mem::take(&mut self.obligations) {
155+
for obligation in self.obligations.unstalled_for_select() {
119156
let goal = obligation.clone().into();
120157
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0;
121158
self.inspect_evaluated_obligation(infcx, &obligation, &result);
122159
let (changed, certainty) = match result {
123160
Ok(result) => result,
124161
Err(NoSolution) => {
125-
errors.push(FulfillmentError {
126-
obligation: obligation.clone(),
127-
code: match goal.predicate.kind().skip_binder() {
128-
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
129-
FulfillmentErrorCode::ProjectionError(
130-
// FIXME: This could be a `Sorts` if the term is a type
131-
MismatchedProjectionTypes { err: TypeError::Mismatch },
132-
)
133-
}
134-
ty::PredicateKind::NormalizesTo(..) => {
135-
FulfillmentErrorCode::ProjectionError(
136-
MismatchedProjectionTypes { err: TypeError::Mismatch },
137-
)
138-
}
139-
ty::PredicateKind::AliasRelate(_, _, _) => {
140-
FulfillmentErrorCode::ProjectionError(
141-
MismatchedProjectionTypes { err: TypeError::Mismatch },
142-
)
143-
}
144-
ty::PredicateKind::Subtype(pred) => {
145-
let (a, b) = infcx.enter_forall_and_leak_universe(
146-
goal.predicate.kind().rebind((pred.a, pred.b)),
147-
);
148-
let expected_found = ExpectedFound::new(true, a, b);
149-
FulfillmentErrorCode::SubtypeError(
150-
expected_found,
151-
TypeError::Sorts(expected_found),
152-
)
153-
}
154-
ty::PredicateKind::Coerce(pred) => {
155-
let (a, b) = infcx.enter_forall_and_leak_universe(
156-
goal.predicate.kind().rebind((pred.a, pred.b)),
157-
);
158-
let expected_found = ExpectedFound::new(false, a, b);
159-
FulfillmentErrorCode::SubtypeError(
160-
expected_found,
161-
TypeError::Sorts(expected_found),
162-
)
163-
}
164-
ty::PredicateKind::Clause(_)
165-
| ty::PredicateKind::ObjectSafe(_)
166-
| ty::PredicateKind::Ambiguous => {
167-
FulfillmentErrorCode::SelectionError(
168-
SelectionError::Unimplemented,
169-
)
170-
}
171-
ty::PredicateKind::ConstEquate(..) => {
172-
bug!("unexpected goal: {goal:?}")
173-
}
174-
},
175-
root_obligation: obligation,
176-
});
162+
errors.push(fulfillment_error_for_no_solution(infcx, obligation));
177163
continue;
178164
}
179165
};
180166
has_changed |= changed;
181167
match certainty {
182168
Certainty::Yes => {}
183-
Certainty::Maybe(_) => self.obligations.push(obligation),
169+
Certainty::Maybe(_) => self.obligations.register(obligation),
184170
}
185171
}
186172

@@ -193,13 +179,84 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
193179
}
194180

195181
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
196-
self.obligations.clone()
182+
self.obligations.clone_pending()
197183
}
198184

199185
fn drain_unstalled_obligations(
200186
&mut self,
201187
_: &InferCtxt<'tcx>,
202188
) -> Vec<PredicateObligation<'tcx>> {
203-
std::mem::take(&mut self.obligations)
189+
self.obligations.take_pending()
204190
}
205191
}
192+
193+
fn fulfillment_error_for_no_solution<'tcx>(
194+
infcx: &InferCtxt<'tcx>,
195+
obligation: PredicateObligation<'tcx>,
196+
) -> FulfillmentError<'tcx> {
197+
let code = match obligation.predicate.kind().skip_binder() {
198+
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
199+
FulfillmentErrorCode::ProjectionError(
200+
// FIXME: This could be a `Sorts` if the term is a type
201+
MismatchedProjectionTypes { err: TypeError::Mismatch },
202+
)
203+
}
204+
ty::PredicateKind::NormalizesTo(..) => {
205+
FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
206+
err: TypeError::Mismatch,
207+
})
208+
}
209+
ty::PredicateKind::AliasRelate(_, _, _) => {
210+
FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
211+
err: TypeError::Mismatch,
212+
})
213+
}
214+
ty::PredicateKind::Subtype(pred) => {
215+
let (a, b) = infcx.enter_forall_and_leak_universe(
216+
obligation.predicate.kind().rebind((pred.a, pred.b)),
217+
);
218+
let expected_found = ExpectedFound::new(true, a, b);
219+
FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
220+
}
221+
ty::PredicateKind::Coerce(pred) => {
222+
let (a, b) = infcx.enter_forall_and_leak_universe(
223+
obligation.predicate.kind().rebind((pred.a, pred.b)),
224+
);
225+
let expected_found = ExpectedFound::new(false, a, b);
226+
FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
227+
}
228+
ty::PredicateKind::Clause(_)
229+
| ty::PredicateKind::ObjectSafe(_)
230+
| ty::PredicateKind::Ambiguous => {
231+
FulfillmentErrorCode::SelectionError(SelectionError::Unimplemented)
232+
}
233+
ty::PredicateKind::ConstEquate(..) => {
234+
bug!("unexpected goal: {obligation:?}")
235+
}
236+
};
237+
FulfillmentError { root_obligation: obligation.clone(), code, obligation }
238+
}
239+
240+
fn fulfillment_error_for_stalled<'tcx>(
241+
infcx: &InferCtxt<'tcx>,
242+
obligation: PredicateObligation<'tcx>,
243+
) -> FulfillmentError<'tcx> {
244+
let code = infcx.probe(|_| {
245+
match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 {
246+
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
247+
FulfillmentErrorCode::Ambiguity { overflow: None }
248+
}
249+
Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => {
250+
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }
251+
}
252+
Ok((_, Certainty::Yes)) => {
253+
bug!("did not expect successful goal when collecting ambiguity errors")
254+
}
255+
Err(_) => {
256+
bug!("did not expect selection error when collecting ambiguity errors")
257+
}
258+
}
259+
});
260+
261+
FulfillmentError { obligation: obligation.clone(), code, root_obligation: obligation }
262+
}

‎compiler/rustc_trait_selection/src/solve/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ pub use fulfill::FulfillmentCtxt;
4242
pub(crate) use normalize::deeply_normalize_for_diagnostics;
4343
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
4444

45+
/// How many fixpoint iterations we should attempt inside of the solver before bailing
46+
/// with overflow.
47+
///
48+
/// We previously used `tcx.recursion_limit().0.checked_ilog2().unwrap_or(0)` for this.
49+
/// However, it feels unlikely that uncreasing the recursion limit by a power of two
50+
/// to get one more itereation is every useful or desirable. We now instead used a constant
51+
/// here. If there ever ends up some use-cases where a bigger number of fixpoint iterations
52+
/// is required, we can add a new attribute for that or revert this to be dependant on the
53+
/// recursion limit again. However, this feels very unlikely.
54+
const FIXPOINT_STEP_LIMIT: usize = 8;
55+
4556
#[derive(Debug, Clone, Copy)]
4657
enum SolverMode {
4758
/// Ordinary trait solving, using everywhere except for coherence.

‎compiler/rustc_trait_selection/src/solve/search_graph.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::solve::FIXPOINT_STEP_LIMIT;
2+
13
use super::inspect;
24
use super::inspect::ProofTreeBuilder;
35
use super::SolverMode;
@@ -99,7 +101,6 @@ impl<'tcx> ProvisionalCacheEntry<'tcx> {
99101

100102
pub(super) struct SearchGraph<'tcx> {
101103
mode: SolverMode,
102-
local_overflow_limit: usize,
103104
/// The stack of goals currently being computed.
104105
///
105106
/// An element is *deeper* in the stack if its index is *lower*.
@@ -116,10 +117,9 @@ pub(super) struct SearchGraph<'tcx> {
116117
}
117118

118119
impl<'tcx> SearchGraph<'tcx> {
119-
pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
120+
pub(super) fn new(mode: SolverMode) -> SearchGraph<'tcx> {
120121
Self {
121122
mode,
122-
local_overflow_limit: tcx.recursion_limit().0.checked_ilog2().unwrap_or(0) as usize,
123123
stack: Default::default(),
124124
provisional_cache: Default::default(),
125125
cycle_participants: Default::default(),
@@ -130,10 +130,6 @@ impl<'tcx> SearchGraph<'tcx> {
130130
self.mode
131131
}
132132

133-
pub(super) fn local_overflow_limit(&self) -> usize {
134-
self.local_overflow_limit
135-
}
136-
137133
/// Update the stack and reached depths on cache hits.
138134
#[instrument(level = "debug", skip(self))]
139135
fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
@@ -277,7 +273,7 @@ impl<'tcx> SearchGraph<'tcx> {
277273
}
278274

279275
inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow);
280-
return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
276+
return Self::response_no_constraints(tcx, input, Certainty::overflow(true));
281277
};
282278

283279
// Try to fetch the goal from the global cache.
@@ -370,7 +366,7 @@ impl<'tcx> SearchGraph<'tcx> {
370366
} else if is_coinductive_cycle {
371367
Self::response_no_constraints(tcx, input, Certainty::Yes)
372368
} else {
373-
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW)
369+
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
374370
};
375371
} else {
376372
// No entry, we push this goal on the stack and try to prove it.
@@ -398,7 +394,7 @@ impl<'tcx> SearchGraph<'tcx> {
398394
// of this we continuously recompute the cycle until the result
399395
// of the previous iteration is equal to the final result, at which
400396
// point we are done.
401-
for _ in 0..self.local_overflow_limit() {
397+
for _ in 0..FIXPOINT_STEP_LIMIT {
402398
let result = prove_goal(self, inspect);
403399
let stack_entry = self.pop_stack();
404400
debug_assert_eq!(stack_entry.input, input);
@@ -431,7 +427,8 @@ impl<'tcx> SearchGraph<'tcx> {
431427
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
432428
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
433429
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
434-
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW) == result
430+
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
431+
== result
435432
} else {
436433
false
437434
};
@@ -452,7 +449,7 @@ impl<'tcx> SearchGraph<'tcx> {
452449
debug!("canonical cycle overflow");
453450
let current_entry = self.pop_stack();
454451
debug_assert!(current_entry.has_been_used.is_empty());
455-
let result = Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
452+
let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false));
456453
(current_entry, result)
457454
});
458455

‎compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 78 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
2222
use rustc_hir::def::DefKind;
2323
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
2424
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
25-
use rustc_infer::traits::{util, TraitEngine, TraitEngineExt};
25+
use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineExt};
2626
use rustc_middle::traits::query::NoSolution;
2727
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
2828
use rustc_middle::traits::specialization_graph::OverlapMode;
@@ -35,6 +35,8 @@ use rustc_span::DUMMY_SP;
3535
use std::fmt::Debug;
3636
use std::ops::ControlFlow;
3737

38+
use super::error_reporting::suggest_new_overflow_limit;
39+
3840
/// Whether we do the orphan check relative to this crate or
3941
/// to some remote crate.
4042
#[derive(Copy, Clone, Debug)]
@@ -56,6 +58,9 @@ pub struct OverlapResult<'tcx> {
5658
/// `true` if the overlap might've been permitted before the shift
5759
/// to universes.
5860
pub involves_placeholder: bool,
61+
62+
/// Used in the new solver to suggest increasing the recursion limit.
63+
pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
5964
}
6065

6166
pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
@@ -65,6 +70,18 @@ pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
6570
);
6671
}
6772

73+
pub fn suggest_increasing_recursion_limit<'tcx, G: EmissionGuarantee>(
74+
tcx: TyCtxt<'tcx>,
75+
err: &mut Diag<'_, G>,
76+
overflowing_predicates: &[ty::Predicate<'tcx>],
77+
) {
78+
for pred in overflowing_predicates {
79+
err.note(format!("overflow evaluating the requirement `{}`", pred));
80+
}
81+
82+
suggest_new_overflow_limit(tcx, err);
83+
}
84+
6885
#[derive(Debug, Clone, Copy)]
6986
enum TrackAmbiguityCauses {
7087
Yes,
@@ -221,11 +238,13 @@ fn overlap<'tcx>(
221238
),
222239
);
223240

241+
let mut overflowing_predicates = Vec::new();
224242
if overlap_mode.use_implicit_negative() {
225-
if let Some(_failing_obligation) =
226-
impl_intersection_has_impossible_obligation(selcx, &obligations)
227-
{
228-
return None;
243+
match impl_intersection_has_impossible_obligation(selcx, &obligations) {
244+
IntersectionHasImpossibleObligations::Yes => return None,
245+
IntersectionHasImpossibleObligations::No { overflowing_predicates: p } => {
246+
overflowing_predicates = p
247+
}
229248
}
230249
}
231250

@@ -261,7 +280,12 @@ fn overlap<'tcx>(
261280
impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
262281
}
263282

264-
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
283+
Some(OverlapResult {
284+
impl_header,
285+
intercrate_ambiguity_causes,
286+
involves_placeholder,
287+
overflowing_predicates,
288+
})
265289
}
266290

267291
#[instrument(level = "debug", skip(infcx), ret)]
@@ -287,6 +311,19 @@ fn equate_impl_headers<'tcx>(
287311
result.map(|infer_ok| infer_ok.obligations).ok()
288312
}
289313

314+
/// The result of [fn impl_intersection_has_impossible_obligation].
315+
enum IntersectionHasImpossibleObligations<'tcx> {
316+
Yes,
317+
No {
318+
/// With `-Znext-solver=coherence`, some obligations may
319+
/// fail if only the user increased the recursion limit.
320+
///
321+
/// We return those obligations here and mention them in the
322+
/// error message.
323+
overflowing_predicates: Vec<ty::Predicate<'tcx>>,
324+
},
325+
}
326+
290327
/// Check if both impls can be satisfied by a common type by considering whether
291328
/// any of either impl's obligations is not known to hold.
292329
///
@@ -308,7 +345,7 @@ fn equate_impl_headers<'tcx>(
308345
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
309346
selcx: &mut SelectionContext<'cx, 'tcx>,
310347
obligations: &'a [PredicateObligation<'tcx>],
311-
) -> Option<PredicateObligation<'tcx>> {
348+
) -> IntersectionHasImpossibleObligations<'tcx> {
312349
let infcx = selcx.infcx;
313350

314351
if infcx.next_trait_solver() {
@@ -317,28 +354,42 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
317354

318355
// We only care about the obligations that are *definitely* true errors.
319356
// Ambiguities do not prove the disjointness of two impls.
320-
let mut errors = fulfill_cx.select_where_possible(infcx);
321-
errors.pop().map(|err| err.obligation)
357+
let errors = fulfill_cx.select_where_possible(infcx);
358+
if errors.is_empty() {
359+
let overflow_errors = fulfill_cx.collect_remaining_errors(infcx);
360+
let overflowing_predicates = overflow_errors
361+
.into_iter()
362+
.filter(|e| match e.code {
363+
FulfillmentErrorCode::Ambiguity { overflow: Some(true) } => true,
364+
_ => false,
365+
})
366+
.map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
367+
.collect();
368+
IntersectionHasImpossibleObligations::No { overflowing_predicates }
369+
} else {
370+
IntersectionHasImpossibleObligations::Yes
371+
}
322372
} else {
323-
obligations
324-
.iter()
325-
.find(|obligation| {
326-
// We use `evaluate_root_obligation` to correctly track intercrate
327-
// ambiguity clauses. We cannot use this in the new solver.
328-
let evaluation_result = selcx.evaluate_root_obligation(obligation);
329-
330-
match evaluation_result {
331-
Ok(result) => !result.may_apply(),
332-
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
333-
// since there can be instantiations of this goal that don't overflow and result in
334-
// success. This isn't much of a problem in the old solver, since we treat overflow
335-
// fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
336-
// but in the new solver, this is very important for correctness, since overflow
337-
// *must* be treated as ambiguity for completeness.
338-
Err(_overflow) => false,
373+
for obligation in obligations {
374+
// We use `evaluate_root_obligation` to correctly track intercrate
375+
// ambiguity clauses.
376+
let evaluation_result = selcx.evaluate_root_obligation(obligation);
377+
378+
match evaluation_result {
379+
Ok(result) => {
380+
if !result.may_apply() {
381+
return IntersectionHasImpossibleObligations::Yes;
382+
}
339383
}
340-
})
341-
.cloned()
384+
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
385+
// since there can be instantiations of this goal that don't overflow and result in
386+
// success. While this isn't much of a problem in the old solver, since we treat overflow
387+
// fatally, this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>.
388+
Err(_overflow) => {}
389+
}
390+
}
391+
392+
IntersectionHasImpossibleObligations::No { overflowing_predicates: Vec::new() }
342393
}
343394
}
344395

‎compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ use crate::traits::{
2020
SelectionError, SignatureMismatch, TraitNotObjectSafe,
2121
};
2222
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
23-
use rustc_errors::{
24-
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
25-
MultiSpan, StashKey, StringPart,
26-
};
23+
use rustc_errors::codes::*;
24+
use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
25+
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey};
2726
use rustc_hir as hir;
2827
use rustc_hir::def::{DefKind, Namespace, Res};
2928
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -62,6 +61,22 @@ pub enum OverflowCause<'tcx> {
6261
TraitSolver(ty::Predicate<'tcx>),
6362
}
6463

64+
pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
65+
tcx: TyCtxt<'tcx>,
66+
err: &mut Diag<'_, G>,
67+
) {
68+
let suggested_limit = match tcx.recursion_limit() {
69+
Limit(0) => Limit(2),
70+
limit => limit * 2,
71+
};
72+
err.help(format!(
73+
"consider increasing the recursion limit by adding a \
74+
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
75+
suggested_limit,
76+
tcx.crate_name(LOCAL_CRATE),
77+
));
78+
}
79+
6580
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
6681
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
6782
fn report_fulfillment_errors(
@@ -263,7 +278,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
263278
};
264279

265280
if suggest_increasing_limit {
266-
self.suggest_new_overflow_limit(&mut err);
281+
suggest_new_overflow_limit(self.tcx, &mut err);
267282
}
268283

269284
err
@@ -303,19 +318,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
303318
);
304319
}
305320

306-
fn suggest_new_overflow_limit(&self, err: &mut Diag<'_>) {
307-
let suggested_limit = match self.tcx.recursion_limit() {
308-
Limit(0) => Limit(2),
309-
limit => limit * 2,
310-
};
311-
err.help(format!(
312-
"consider increasing the recursion limit by adding a \
313-
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
314-
suggested_limit,
315-
self.tcx.crate_name(LOCAL_CRATE),
316-
));
317-
}
318-
319321
/// Reports that a cycle was detected which led to overflow and halts
320322
/// compilation. This is equivalent to `report_overflow_obligation` except
321323
/// that we can give a more helpful error message (and, in particular,
@@ -335,12 +337,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
335337
);
336338
}
337339

338-
fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
340+
fn report_overflow_no_abort(
341+
&self,
342+
obligation: PredicateObligation<'tcx>,
343+
suggest_increasing_limit: bool,
344+
) -> ErrorGuaranteed {
339345
let obligation = self.resolve_vars_if_possible(obligation);
340346
let mut err = self.build_overflow_error(
341347
OverflowCause::TraitSolver(obligation.predicate),
342348
obligation.cause.span,
343-
true,
349+
suggest_increasing_limit,
344350
);
345351
self.note_obligation_cause(&mut err, &obligation);
346352
self.point_at_returns_when_relevant(&mut err, &obligation);
@@ -1422,11 +1428,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
14221428
FulfillmentErrorCode::ProjectionError(ref e) => {
14231429
self.report_projection_error(&error.obligation, e)
14241430
}
1425-
FulfillmentErrorCode::Ambiguity { overflow: false } => {
1431+
FulfillmentErrorCode::Ambiguity { overflow: None } => {
14261432
self.maybe_report_ambiguity(&error.obligation)
14271433
}
1428-
FulfillmentErrorCode::Ambiguity { overflow: true } => {
1429-
self.report_overflow_no_abort(error.obligation.clone())
1434+
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
1435+
self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
14301436
}
14311437
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
14321438
.report_mismatched_types(

‎compiler/rustc_trait_selection/src/traits/fulfill.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
138138
_infcx: &InferCtxt<'tcx>,
139139
) -> Vec<FulfillmentError<'tcx>> {
140140
self.predicates
141-
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: false })
141+
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: None })
142142
.into_iter()
143143
.map(to_fulfillment_error)
144144
.collect()

‎compiler/rustc_trait_selection/src/traits/specialize/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub struct OverlapError<'tcx> {
3939
pub self_ty: Option<Ty<'tcx>>,
4040
pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
4141
pub involves_placeholder: bool,
42+
pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
4243
}
4344

4445
/// Given the generic parameters for the requested impl, translate it to the generic parameters
@@ -435,6 +436,14 @@ fn report_conflicting_impls<'tcx>(
435436
if overlap.involves_placeholder {
436437
coherence::add_placeholder_note(err);
437438
}
439+
440+
if !overlap.overflowing_predicates.is_empty() {
441+
coherence::suggest_increasing_recursion_limit(
442+
tcx,
443+
err,
444+
&overlap.overflowing_predicates,
445+
);
446+
}
438447
}
439448

440449
let msg = DelayDm(|| {

‎compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ impl<'tcx> Children {
103103
self_ty: self_ty.has_concrete_skeleton().then_some(self_ty),
104104
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
105105
involves_placeholder: overlap.involves_placeholder,
106+
overflowing_predicates: overlap.overflowing_predicates,
106107
}
107108
};
108109

‎tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-form
44
LL | for<'a> &'a mut Self:;
55
| ^^^^^^^^^^^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`)
87
note: required by a bound in `Bar`
98
--> $DIR/issue-95230.rs:9:13
109
|

‎tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ error[E0275]: overflow evaluating the requirement `Loop == _`
33
|
44
LL | impl Loop {}
55
| ^^^^
6-
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)
86

97
error[E0392]: type parameter `T` is never used
108
--> $DIR/inherent-impls-overflow.rs:13:12

‎tests/ui/traits/next-solver/alias-bound-unsound.stderr

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `String: Copy`
44
LL | type Item = String where String: Copy;
55
| ^^^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
87
note: the requirement `String: Copy` appears on the `impl`'s associated type `Item` but not on the corresponding trait's associated type
98
--> $DIR/alias-bound-unsound.rs:8:10
109
|
@@ -18,40 +17,31 @@ error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item`
1817
|
1918
LL | drop(<() as Foo>::copy_me(&x));
2019
| ^^
21-
|
22-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
2320

2421
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
2522
--> $DIR/alias-bound-unsound.rs:24:10
2623
|
2724
LL | drop(<() as Foo>::copy_me(&x));
2825
| ^^^^^^^^^^^^^^^^^^^^^^^^
29-
|
30-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
3126

3227
error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed`
3328
--> $DIR/alias-bound-unsound.rs:24:31
3429
|
3530
LL | drop(<() as Foo>::copy_me(&x));
3631
| ^^
37-
|
38-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
3932

4033
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item well-formed`
4134
--> $DIR/alias-bound-unsound.rs:24:10
4235
|
4336
LL | drop(<() as Foo>::copy_me(&x));
4437
| ^^^^^^^^^^^^^^^^^^^^^^^^
45-
|
46-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
4738

4839
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
4940
--> $DIR/alias-bound-unsound.rs:24:10
5041
|
5142
LL | drop(<() as Foo>::copy_me(&x));
5243
| ^^^^^^^^^^^^^^^^^^^^^^^^
5344
|
54-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
5545
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
5646

5747
error: aborting due to 6 previous errors

‎tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
55
| ------------------------------------- first implementation here
66
LL | impl<T: ?Sized + TwoW> Trait for T {}
77
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
8+
|
9+
= note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>: TwoW`
10+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
811

912
error: aborting due to 1 previous error
1013

‎tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ LL | impl<T: Copy> Trait for T {}
66
LL | struct LocalTy;
77
LL | impl Trait for <LocalTy as Overflow>::Assoc {}
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
9+
|
10+
= note: overflow evaluating the requirement `_ == <LocalTy as Overflow>::Assoc`
11+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`trait_ref_is_knowable_norm_overflow`)
912

1013
error[E0275]: overflow evaluating the requirement `<T as Overflow>::Assoc: Sized`
1114
--> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18

‎tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait`
44
LL | impls::<W<_>>();
55
| ^^^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`fixpoint_exponential_growth`)
87
note: required by a bound in `impls`
98
--> $DIR/fixpoint-exponential-growth.rs:30:13
109
|

‎tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): Trait`
44
LL | impls_trait::<()>();
55
| ^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`double_cycle_inductive_coinductive`)
87
note: required by a bound in `impls_trait`
98
--> $DIR/double-cycle-inductive-coinductive.rs:17:19
109
|
@@ -17,7 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): TraitRev`
1716
LL | impls_trait_rev::<()>();
1817
| ^^
1918
|
20-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`double_cycle_inductive_coinductive`)
2119
note: required by a bound in `impls_trait_rev`
2220
--> $DIR/double-cycle-inductive-coinductive.rs:29:23
2321
|

‎tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait`
44
LL | impls_trait::<W<_>>();
55
| ^^^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_fixpoint_hang`)
87
note: required by a bound in `impls_trait`
98
--> $DIR/inductive-fixpoint-hang.rs:28:19
109
|

‎tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): A`
44
LL | impls_a::<()>();
55
| ^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_not_on_stack`)
87
note: required by a bound in `impls_a`
98
--> $DIR/inductive-not-on-stack.rs:25:15
109
|
@@ -17,7 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): AR`
1716
LL | impls_ar::<()>();
1817
| ^^
1918
|
20-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_not_on_stack`)
2119
note: required by a bound in `impls_ar`
2220
--> $DIR/inductive-not-on-stack.rs:38:16
2321
|

‎tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): A`
44
LL | impls_a::<()>();
55
| ^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mixed_cycles_1`)
87
note: required by a bound in `impls_a`
98
--> $DIR/mixed-cycles-1.rs:34:15
109
|

‎tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): A`
44
LL | impls_a::<()>();
55
| ^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mixed_cycles_2`)
87
note: required by a bound in `impls_a`
98
--> $DIR/mixed-cycles-2.rs:27:15
109
|

‎tests/ui/traits/next-solver/normalize-param-env-2.stderr

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
44
LL | Self::Assoc: A<T>,
55
| ^^^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`)
87
note: the requirement `<() as A<T>>::Assoc: A<T>` appears on the `impl`'s method `f` but not on the corresponding trait's method
98
--> $DIR/normalize-param-env-2.rs:12:8
109
|
@@ -19,32 +18,25 @@ error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
1918
|
2019
LL | Self::Assoc: A<T>,
2120
| ^^^^
22-
|
23-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`)
2421

2522
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc well-formed`
2623
--> $DIR/normalize-param-env-2.rs:24:22
2724
|
2825
LL | Self::Assoc: A<T>,
2926
| ^^^^
30-
|
31-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`)
3227

3328
error[E0275]: overflow evaluating the requirement `(): A<T>`
3429
--> $DIR/normalize-param-env-2.rs:27:10
3530
|
3631
LL | <() as A<T>>::f();
3732
| ^^
38-
|
39-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`)
4033

4134
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
4235
--> $DIR/normalize-param-env-2.rs:27:9
4336
|
4437
LL | <() as A<T>>::f();
4538
| ^^^^^^^^^^^^^^^^^
4639
|
47-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`)
4840
note: required by a bound in `A::f`
4941
--> $DIR/normalize-param-env-2.rs:14:22
5042
|

‎tests/ui/traits/next-solver/normalize-param-env-4.next.stderr

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,19 @@ error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: Trait`
33
|
44
LL | <T as Trait>::Assoc: Trait,
55
| ^^^^^
6-
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_4`)
86

97
error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc well-formed`
108
--> $DIR/normalize-param-env-4.rs:18:26
119
|
1210
LL | <T as Trait>::Assoc: Trait,
1311
| ^^^^^
14-
|
15-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_4`)
1612

1713
error[E0275]: overflow evaluating the requirement `T: Trait`
1814
--> $DIR/normalize-param-env-4.rs:31:19
1915
|
2016
LL | impls_trait::<T>();
2117
| ^
2218
|
23-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_4`)
2419
note: required by a bound in `impls_trait`
2520
--> $DIR/normalize-param-env-4.rs:14:19
2621
|

‎tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait`
44
LL | impls::<W<_>>();
55
| ^^^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`exponential_trait_goals`)
87
note: required by a bound in `impls`
98
--> $DIR/exponential-trait-goals.rs:14:13
109
|
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
//~ ERROR overflow evaluating the requirement `Self well-formed`
2-
//~| ERROR overflow evaluating the requirement `Self: Trait`
3-
41
// This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE.
52
//@ compile-flags: -Znext-solver --crate-type=lib
6-
//@ check-fail
3+
//@ check-pass
74

85
#![recursion_limit = "0"]
96
trait Trait {}
107
impl Trait for u32 {}
11-
//~^ ERROR overflow evaluating the requirement `u32: Trait`
12-
//~| ERROR overflow evaluating the requirement `u32 well-formed`

‎tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.