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 da01707

Browse files
committedFeb 27, 2025·
change definitely non-productive cycles to error
1 parent 35fbaf1 commit da01707

File tree

19 files changed

+229
-204
lines changed

19 files changed

+229
-204
lines changed
 

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

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,33 @@ where
271271
/// and will need to clearly document it in the rustc-dev-guide before
272272
/// stabilization.
273273
pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
274-
match (self.current_goal_kind, source) {
275-
(_, GoalSource::NormalizeGoal(step_kind)) => step_kind,
276-
(CurrentGoalKind::CoinductiveTrait, GoalSource::ImplWhereBound) => {
277-
PathKind::Coinductive
274+
match source {
275+
// We treat these goals as unknown for now. It is likely that most, if not all
276+
// miscellaneous nested goals will be converted to `GoalSource::MiscKnownInductive`
277+
// over time.
278+
GoalSource::Misc => PathKind::Unknown,
279+
GoalSource::NormalizeGoal(path_kind) => path_kind,
280+
GoalSource::ImplWhereBound => {
281+
// We currently only consider a cycle coinductive if it steps
282+
// into a where-clause of a coinductive trait.
283+
//
284+
// We probably want to make all traits coinductive in the future,
285+
// so we treat cycles involving their where-clauses as ambiguous.
286+
if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind {
287+
PathKind::Coinductive
288+
} else {
289+
PathKind::Unknown
290+
}
278291
}
279-
_ => PathKind::Inductive,
292+
// A step which is clearly unproductive. Cycles exclusively involving such steps
293+
// result in `Err(NoSolution)`.
294+
GoalSource::MiscKnownInductive | GoalSource::InstantiateHigherRanked => {
295+
PathKind::Inductive
296+
}
297+
// These goal sources are likely unproductive and can be changed to
298+
// `PathKind::Inductive`. Keeping them as unknown until we're confident
299+
// about this and have an example where it is necessary.
300+
GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
280301
}
281302
}
282303

@@ -606,7 +627,7 @@ where
606627

607628
let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw(
608629
GoalEvaluationKind::Nested,
609-
GoalSource::Misc,
630+
GoalSource::normalizes_to(),
610631
unconstrained_goal,
611632
)?;
612633
// Add the nested goals from normalization to our own nested goals.
@@ -683,7 +704,7 @@ where
683704
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
684705
goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(
685706
self,
686-
GoalSource::Misc,
707+
GoalSource::normalizes_to(),
687708
goal.param_env,
688709
));
689710
self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
@@ -939,7 +960,16 @@ where
939960
rhs: T,
940961
) -> Result<(), NoSolution> {
941962
let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
942-
self.add_goals(GoalSource::Misc, goals);
963+
if cfg!(debug_assertions) {
964+
for g in goals.iter() {
965+
match g.predicate.kind().skip_binder() {
966+
ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {}
967+
p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
968+
}
969+
}
970+
}
971+
// Normalization is always unproductive.
972+
self.add_goals(GoalSource::MiscKnownInductive, goals);
943973
Ok(())
944974
}
945975

‎compiler/rustc_next_trait_solver/src/solve/inspect/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
421421
self.add_goal(
422422
delegate,
423423
max_input_universe,
424-
GoalSource::Misc,
424+
GoalSource::normalizes_to(),
425425
goal.with(delegate.cx(), goal.predicate),
426426
);
427427
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ where
313313
ty::AliasRelationDirection::Equate,
314314
),
315315
);
316-
self.add_goal(GoalSource::Misc, alias_relate_goal);
316+
// Normalization is always unproductive.
317+
self.add_goal(GoalSource::MiscKnownInductive, alias_relate_goal);
317318
self.try_evaluate_added_goals()?;
318319
Ok(self.resolve_vars_if_possible(normalized_term))
319320
} else {

‎compiler/rustc_next_trait_solver/src/solve/project_goals.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ where
2424
ty::AliasRelationDirection::Equate,
2525
),
2626
);
27-
self.add_goal(GoalSource::Misc, goal);
27+
// Normalization is always unproductive.
28+
self.add_goal(GoalSource::MiscKnownInductive, goal);
2829
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
2930
}
3031
}

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::marker::PhantomData;
33

44
use rustc_type_ir::Interner;
55
use rustc_type_ir::search_graph::{self, PathKind};
6-
use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult};
6+
use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult};
77

88
use super::inspect::ProofTreeBuilder;
99
use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints};
@@ -47,7 +47,8 @@ where
4747
) -> QueryResult<I> {
4848
match kind {
4949
PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
50-
PathKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)),
50+
PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)),
51+
PathKind::Inductive => Err(NoSolution),
5152
}
5253
}
5354

@@ -57,12 +58,7 @@ where
5758
input: CanonicalInput<I>,
5859
result: QueryResult<I>,
5960
) -> bool {
60-
match kind {
61-
PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes) == result,
62-
PathKind::Inductive => {
63-
response_no_constraints(cx, input, Certainty::overflow(false)) == result
64-
}
65-
}
61+
Self::initial_provisional_result(cx, kind, input) == result
6662
}
6763

6864
fn on_stack_overflow(

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,9 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
440440
match (child_mode, nested_goal.source()) {
441441
(
442442
ChildMode::Trait(_) | ChildMode::Host(_),
443-
GoalSource::Misc | GoalSource::NormalizeGoal(_),
443+
GoalSource::Misc
444+
| GoalSource::MiscKnownInductive
445+
| GoalSource::NormalizeGoal(_),
444446
) => {
445447
continue;
446448
}

‎compiler/rustc_type_ir/src/search_graph/mod.rs

Lines changed: 103 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
/// behavior as long as the resulting behavior is still correct.
1414
use std::cmp::Ordering;
1515
use std::collections::BTreeMap;
16+
use std::collections::hash_map::Entry;
1617
use std::fmt::Debug;
1718
use std::hash::Hash;
1819
use std::marker::PhantomData;
1920

2021
use derive_where::derive_where;
2122
use rustc_index::{Idx, IndexVec};
2223
#[cfg(feature = "nightly")]
23-
use rustc_macros::HashStable_NoContext;
24+
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
2425
use tracing::debug;
2526

2627
use crate::data_structures::HashMap;
@@ -111,21 +112,29 @@ pub trait Delegate {
111112
/// In the initial iteration of a cycle, we do not yet have a provisional
112113
/// result. In the case we return an initial provisional result depending
113114
/// on the kind of cycle.
114-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
115-
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
115+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
116+
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
116117
pub enum PathKind {
117-
Coinductive,
118+
/// A path consisting of only inductive/unproductive steps.
118119
Inductive,
120+
/// A path which is not be coinductive right now but we may want
121+
/// to change of them to be so in the future. We return an ambiguous
122+
/// result in this case to prevent people from relying on this.
123+
Unknown,
124+
/// A path with at least one coinductive step. Such cycles hold.
125+
Coinductive,
119126
}
127+
120128
impl PathKind {
121129
/// Returns the path kind when merging `self` with `rest`.
122130
///
123131
/// Given an inductive path `self` and a coinductive path `rest`,
124132
/// the path `self -> rest` would be coinductive.
125133
fn extend(self, rest: PathKind) -> PathKind {
126-
match self {
127-
PathKind::Coinductive => PathKind::Coinductive,
128-
PathKind::Inductive => rest,
134+
match (self, rest) {
135+
(PathKind::Coinductive, _) | (_, PathKind::Coinductive) => PathKind::Coinductive,
136+
(PathKind::Unknown, _) | (_, PathKind::Unknown) => PathKind::Unknown,
137+
(PathKind::Inductive, PathKind::Inductive) => PathKind::Inductive,
129138
}
130139
}
131140
}
@@ -159,9 +168,6 @@ impl UsageKind {
159168
}
160169
}
161170
}
162-
fn and_merge(&mut self, other: impl Into<Self>) {
163-
*self = self.merge(other);
164-
}
165171
}
166172

167173
/// For each goal we track whether the paths from this goal
@@ -297,14 +303,68 @@ impl CycleHeads {
297303

298304
let path_from_entry = match step_kind {
299305
PathKind::Coinductive => AllPathsToHeadCoinductive::Yes,
300-
PathKind::Inductive => path_from_entry,
306+
PathKind::Unknown | PathKind::Inductive => path_from_entry,
301307
};
302308

303309
self.insert(head, path_from_entry);
304310
}
305311
}
306312
}
307313

314+
bitflags::bitflags! {
315+
/// Tracks how nested goals have been accessed. This is necessary to disable
316+
/// global cache entries if computing them would otherwise result in a cycle or
317+
/// access a provisional cache entry.
318+
#[derive(Debug, Clone, Copy)]
319+
pub struct PathsToNested: u8 {
320+
/// The initial value when adding a goal to its own nested goals.
321+
const EMPTY = 1 << 0;
322+
const INDUCTIVE = 1 << 1;
323+
const UNKNOWN = 1 << 2;
324+
const COINDUCTIVE = 1 << 3;
325+
}
326+
}
327+
impl From<PathKind> for PathsToNested {
328+
fn from(path: PathKind) -> PathsToNested {
329+
match path {
330+
PathKind::Inductive => PathsToNested::INDUCTIVE,
331+
PathKind::Unknown => PathsToNested::UNKNOWN,
332+
PathKind::Coinductive => PathsToNested::COINDUCTIVE,
333+
}
334+
}
335+
}
336+
impl PathsToNested {
337+
#[must_use]
338+
fn extend_with(mut self, path: PathKind) -> Self {
339+
match path {
340+
PathKind::Inductive => {
341+
if self.intersects(PathsToNested::EMPTY) {
342+
self.remove(PathsToNested::EMPTY);
343+
self.insert(PathsToNested::INDUCTIVE);
344+
}
345+
}
346+
PathKind::Unknown => {
347+
if self.intersects(PathsToNested::EMPTY | PathsToNested::INDUCTIVE) {
348+
self.remove(PathsToNested::EMPTY | PathsToNested::INDUCTIVE);
349+
self.insert(PathsToNested::UNKNOWN);
350+
}
351+
}
352+
PathKind::Coinductive => {
353+
if self.intersects(
354+
PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
355+
) {
356+
self.remove(
357+
PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
358+
);
359+
self.insert(PathsToNested::COINDUCTIVE);
360+
}
361+
}
362+
}
363+
364+
self
365+
}
366+
}
367+
308368
/// The nested goals of each stack entry and the path from the
309369
/// stack entry to that nested goal.
310370
///
@@ -322,15 +382,18 @@ impl CycleHeads {
322382
/// results from a the cycle BAB depending on the cycle root.
323383
#[derive_where(Debug, Default, Clone; X: Cx)]
324384
struct NestedGoals<X: Cx> {
325-
nested_goals: HashMap<X::Input, UsageKind>,
385+
nested_goals: HashMap<X::Input, PathsToNested>,
326386
}
327387
impl<X: Cx> NestedGoals<X> {
328388
fn is_empty(&self) -> bool {
329389
self.nested_goals.is_empty()
330390
}
331391

332-
fn insert(&mut self, input: X::Input, path_from_entry: UsageKind) {
333-
self.nested_goals.entry(input).or_insert(path_from_entry).and_merge(path_from_entry);
392+
fn insert(&mut self, input: X::Input, paths_to_nested: PathsToNested) {
393+
match self.nested_goals.entry(input) {
394+
Entry::Occupied(mut entry) => *entry.get_mut() |= paths_to_nested,
395+
Entry::Vacant(entry) => drop(entry.insert(paths_to_nested)),
396+
}
334397
}
335398

336399
/// Adds the nested goals of a nested goal, given that the path `step_kind` from this goal
@@ -341,18 +404,15 @@ impl<X: Cx> NestedGoals<X> {
341404
/// the same as for the child.
342405
fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals<X>) {
343406
#[allow(rustc::potential_query_instability)]
344-
for (input, path_from_entry) in nested_goals.iter() {
345-
let path_from_entry = match step_kind {
346-
PathKind::Coinductive => UsageKind::Single(PathKind::Coinductive),
347-
PathKind::Inductive => path_from_entry,
348-
};
349-
self.insert(input, path_from_entry);
407+
for (input, paths_to_nested) in nested_goals.iter() {
408+
let paths_to_nested = paths_to_nested.extend_with(step_kind);
409+
self.insert(input, paths_to_nested);
350410
}
351411
}
352412

353413
#[cfg_attr(feature = "nightly", rustc_lint_query_instability)]
354414
#[allow(rustc::potential_query_instability)]
355-
fn iter(&self) -> impl Iterator<Item = (X::Input, UsageKind)> {
415+
fn iter(&self) -> impl Iterator<Item = (X::Input, PathsToNested)> + '_ {
356416
self.nested_goals.iter().map(|(i, p)| (*i, *p))
357417
}
358418

@@ -490,7 +550,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
490550
// goals as this change may cause them to now depend on additional
491551
// goals, resulting in new cycles. See the dev-guide for examples.
492552
if parent_depends_on_cycle {
493-
parent.nested_goals.insert(parent.input, UsageKind::Single(PathKind::Inductive))
553+
parent.nested_goals.insert(parent.input, PathsToNested::EMPTY);
494554
}
495555
}
496556
}
@@ -666,7 +726,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
666726
//
667727
// We must therefore not use the global cache entry for `B` in that case.
668728
// See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs
669-
last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive));
729+
last.nested_goals.insert(last.input, PathsToNested::EMPTY);
670730
}
671731

672732
debug!("encountered stack overflow");
@@ -749,16 +809,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
749809

750810
// We now care about the path from the next highest cycle head to the
751811
// provisional cache entry.
752-
match path_from_head {
753-
PathKind::Coinductive => {}
754-
PathKind::Inductive => {
755-
*path_from_head = Self::cycle_path_kind(
756-
&self.stack,
757-
stack_entry.step_kind_from_parent,
758-
head,
759-
)
760-
}
761-
}
812+
*path_from_head = path_from_head.extend(Self::cycle_path_kind(
813+
&self.stack,
814+
stack_entry.step_kind_from_parent,
815+
head,
816+
));
762817
// Mutate the result of the provisional cache entry in case we did
763818
// not reach a fixpoint.
764819
*result = mutate_result(input, *result);
@@ -858,7 +913,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
858913
for &ProvisionalCacheEntry {
859914
encountered_overflow,
860915
ref heads,
861-
path_from_head,
916+
path_from_head: head_to_provisional,
862917
result: _,
863918
} in entries.iter()
864919
{
@@ -870,24 +925,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
870925

871926
// A provisional cache entry only applies if the path from its highest head
872927
// matches the path when encountering the goal.
928+
//
929+
// We check if any of the paths taken while computing the global goal
930+
// would end up with an applicable provisional cache entry.
873931
let head = heads.highest_cycle_head();
874-
let full_path = match Self::cycle_path_kind(stack, step_kind_from_parent, head) {
875-
PathKind::Coinductive => UsageKind::Single(PathKind::Coinductive),
876-
PathKind::Inductive => path_from_global_entry,
877-
};
878-
879-
match (full_path, path_from_head) {
880-
(UsageKind::Mixed, _)
881-
| (UsageKind::Single(PathKind::Coinductive), PathKind::Coinductive)
882-
| (UsageKind::Single(PathKind::Inductive), PathKind::Inductive) => {
883-
debug!(
884-
?full_path,
885-
?path_from_head,
886-
"cache entry not applicable due to matching paths"
887-
);
888-
return false;
889-
}
890-
_ => debug!(?full_path, ?path_from_head, "paths don't match"),
932+
let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head);
933+
let full_paths = path_from_global_entry.extend_with(head_to_curr);
934+
if full_paths.contains(head_to_provisional.into()) {
935+
debug!(
936+
?full_paths,
937+
?head_to_provisional,
938+
"cache entry not applicable due to matching paths"
939+
);
940+
return false;
891941
}
892942
}
893943
}
@@ -986,8 +1036,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
9861036
let last = &mut self.stack[last_index];
9871037
last.reached_depth = last.reached_depth.max(next_index);
9881038

989-
last.nested_goals.insert(input, UsageKind::Single(step_kind_from_parent));
990-
last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive));
1039+
last.nested_goals.insert(input, step_kind_from_parent.into());
1040+
last.nested_goals.insert(last.input, PathsToNested::EMPTY);
9911041
if last_index != head {
9921042
last.heads.insert(head, step_kind_from_parent);
9931043
}

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,35 +58,44 @@ impl<I: Interner, P> Goal<I, P> {
5858
/// Why a specific goal has to be proven.
5959
///
6060
/// This is necessary as we treat nested goals different depending on
61-
/// their source. This is currently mostly used by proof tree visitors
62-
/// but will be used by cycle handling in the future.
61+
/// their source. This is used to decide whether a cycle is coinductive.
62+
/// See the documentation of `EvalCtxt::step_kind_for_source` for more details
63+
/// about this.
64+
///
65+
/// It is also used by proof tree visitors, e.g. for diagnostics purposes.
6366
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
6467
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
6568
pub enum GoalSource {
6669
Misc,
70+
/// A miscellaneous goal which is definitely an inductive/unproductive
71+
/// step. Cycles involving exclusively such goals are treated as errors.
72+
MiscKnownInductive,
6773
/// We're proving a where-bound of an impl.
68-
///
69-
/// FIXME(-Znext-solver=coinductive): Explain how and why this
70-
/// changes whether cycles are coinductive.
7174
ImplWhereBound,
7275
/// Const conditions that need to hold for `~const` alias bounds to hold.
73-
///
74-
/// FIXME(-Znext-solver=coinductive): Are these even coinductive?
7576
AliasBoundConstCondition,
7677
/// Instantiating a higher-ranked goal and re-proving it.
7778
InstantiateHigherRanked,
7879
/// Predicate required for an alias projection to be well-formed.
7980
/// This is used in two places: projecting to an opaque whose hidden type
8081
/// is already registered in the opaque type storage, and for rigid projections.
8182
AliasWellFormed,
82-
8383
/// In case normalizing aliases in nested goals cycles, eagerly normalizing these
8484
/// aliases in the context of the parent may incorrectly change the cycle kind.
8585
/// Normalizing aliases in goals therefore tracks the original path kind for this
8686
/// nested goal. See the comment of the `ReplaceAliasWithInfer` visitor for more
8787
/// details.
8888
NormalizeGoal(PathKind),
8989
}
90+
impl GoalSource {
91+
/// The goal source used when evaluating `NormalizesTo` goals
92+
/// is not explicitly tracked anywhere, so this is used to make
93+
/// sure we consistently use the same goal source for them.
94+
pub fn normalizes_to() -> GoalSource {
95+
// Normalization is always unproductive.
96+
GoalSource::MiscKnownInductive
97+
}
98+
}
9099

91100
#[derive_where(Clone; I: Interner, Goal<I, P>: Clone)]
92101
#[derive_where(Copy; I: Interner, Goal<I, P>: Copy)]

‎tests/ui/associated-type-bounds/hrtb.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
//@ check-pass
2+
//@ revisions: current next
3+
//@[next] compile-flags: -Znext-solver
4+
//@ ignore-compare-mode-next-solver (explicit revisions)
25

36
trait A<'a> {}
47
trait B<'b> {}

‎tests/ui/associated-type-bounds/supertrait-defines-ty.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
//@ check-pass
2+
//@ revisions: current next
3+
//@[next] compile-flags: -Znext-solver
4+
//@ ignore-compare-mode-next-solver (explicit revisions)
25

36
// Make sure that we don't look into associated type bounds when looking for
47
// supertraits that define an associated type. Fixes #76593.

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0275]: overflow evaluating the requirement `Loop == _`
1+
error[E0271]: type mismatch resolving `Loop normalizes-to _`
22
--> $DIR/inherent-impls-overflow.rs:10:6
33
|
44
LL | impl Loop {}
5-
| ^^^^
5+
| ^^^^ types differ
66

77
error: type parameter `T` is only used recursively
88
--> $DIR/inherent-impls-overflow.rs:14:24
@@ -36,4 +36,5 @@ LL | impl Poly0<()> {}
3636

3737
error: aborting due to 4 previous errors
3838

39-
For more information about this error, try `rustc --explain E0275`.
39+
Some errors have detailed explanations: E0271, E0275.
40+
For more information about an error, try `rustc --explain E0271`.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type Loop = Loop; //[current]~ ERROR overflow normalizing the type alias `Loop`
99

1010
impl Loop {}
1111
//[current]~^ ERROR overflow normalizing the type alias `Loop`
12-
//[next]~^^ ERROR overflow evaluating the requirement `Loop == _`
12+
//[next]~^^ ERROR type mismatch resolving `Loop normalizes-to _`
1313

1414
type Poly0<T> = Poly1<(T,)>;
1515
//[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
trait Overflow {
77
type Assoc;
88
}
9-
impl<T> Overflow for T {
10-
type Assoc = <T as Overflow>::Assoc;
11-
//~^ ERROR: overflow
9+
impl<T> Overflow for T
10+
where
11+
(T,): Overflow
12+
{
13+
type Assoc = <(T,) as Overflow>::Assoc;
1214
}
1315

1416

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
1-
error[E0275]: overflow evaluating the requirement `<T as Overflow>::Assoc == _`
2-
--> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18
3-
|
4-
LL | type Assoc = <T as Overflow>::Assoc;
5-
| ^^^^^^^^^^^^^^^^^^^^^^
6-
71
error[E0119]: conflicting implementations of trait `Trait`
8-
--> $DIR/trait_ref_is_knowable-norm-overflow.rs:18:1
2+
--> $DIR/trait_ref_is_knowable-norm-overflow.rs:20:1
93
|
104
LL | impl<T: Copy> Trait for T {}
115
| ------------------------- first implementation here
126
LL | struct LocalTy;
137
LL | impl Trait for <LocalTy as Overflow>::Assoc {}
148
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`)
1512

16-
error: aborting due to 2 previous errors
13+
error: aborting due to 1 previous error
1714

18-
Some errors have detailed explanations: E0119, E0275.
19-
For more information about an error, try `rustc --explain E0119`.
15+
For more information about this error, try `rustc --explain E0119`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Regression test for trait-system-refactor-initiative#114.
2+
//
3+
// We previously treated the cycle when trying to use the
4+
// `<R as DimMin<C>>::Output: DimMin` where-bound when
5+
// normalizing `<R as DimMin<C>>::Output` as ambiguous, causing
6+
// this to error.
7+
8+
//@ check-pass
9+
//@ compile-flags: -Znext-solver
10+
//@ ignore-compare-mode-next-solver
11+
12+
pub trait DimMin<D> {
13+
type Output;
14+
}
15+
pub fn repro<R: DimMin<C>, C>()
16+
where
17+
<R as DimMin<C>>::Output: DimMin<C, Output = <R as DimMin<C>>::Output>,
18+
{
19+
}
20+
21+
fn main() {}

‎tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,7 @@ fn needs_bar<S: Bar>() {}
1313

1414
fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
1515
needs_bar::<T::Assoc1>();
16-
//~^ ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
17-
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
18-
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
19-
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
20-
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Sized`
21-
//~| ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
16+
//~^ ERROR the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
2217
}
2318

2419
fn main() {}
Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,19 @@
1-
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
1+
error[E0277]: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
22
--> $DIR/recursive-self-normalization-2.rs:15:17
33
|
44
LL | needs_bar::<T::Assoc1>();
5-
| ^^^^^^^^^
6-
7-
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
8-
--> $DIR/recursive-self-normalization-2.rs:15:17
9-
|
10-
LL | needs_bar::<T::Assoc1>();
11-
| ^^^^^^^^^
5+
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo1>::Assoc1`
126
|
137
note: required by a bound in `needs_bar`
148
--> $DIR/recursive-self-normalization-2.rs:12:17
159
|
1610
LL | fn needs_bar<S: Bar>() {}
1711
| ^^^ required by this bound in `needs_bar`
18-
19-
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Sized`
20-
--> $DIR/recursive-self-normalization-2.rs:15:17
21-
|
22-
LL | needs_bar::<T::Assoc1>();
23-
| ^^^^^^^^^
24-
|
25-
note: required by an implicit `Sized` bound in `needs_bar`
26-
--> $DIR/recursive-self-normalization-2.rs:12:14
27-
|
28-
LL | fn needs_bar<S: Bar>() {}
29-
| ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar`
30-
help: consider relaxing the implicit `Sized` restriction
31-
|
32-
LL | fn needs_bar<S: Bar + ?Sized>() {}
33-
| ++++++++
34-
35-
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
36-
--> $DIR/recursive-self-normalization-2.rs:15:5
37-
|
38-
LL | needs_bar::<T::Assoc1>();
39-
| ^^^^^^^^^^^^^^^^^^^^^^
40-
41-
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
42-
--> $DIR/recursive-self-normalization-2.rs:15:5
43-
|
44-
LL | needs_bar::<T::Assoc1>();
45-
| ^^^^^^^^^^^^^^^^^^^^^^
46-
|
47-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
48-
49-
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1 == _`
50-
--> $DIR/recursive-self-normalization-2.rs:15:17
51-
|
52-
LL | needs_bar::<T::Assoc1>();
53-
| ^^^^^^^^^
12+
help: consider further restricting the associated type
5413
|
55-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14+
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo1>::Assoc1: Bar {
15+
| ++++++++++++++++++++++++++++++
5616

57-
error: aborting due to 6 previous errors
17+
error: aborting due to 1 previous error
5818

59-
For more information about this error, try `rustc --explain E0275`.
19+
For more information about this error, try `rustc --explain E0277`.

‎tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,7 @@ fn needs_bar<S: Bar>() {}
99

1010
fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() {
1111
needs_bar::<T::Assoc>();
12-
//~^ ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
13-
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
14-
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
15-
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc == _`
16-
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Sized`
17-
//~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
12+
//~^ ERROR the trait bound `<T as Foo>::Assoc: Bar` is not satisfied
1813
}
1914

2015
fn main() {}
Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,19 @@
1-
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
1+
error[E0277]: the trait bound `<T as Foo>::Assoc: Bar` is not satisfied
22
--> $DIR/recursive-self-normalization.rs:11:17
33
|
44
LL | needs_bar::<T::Assoc>();
5-
| ^^^^^^^^
6-
7-
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
8-
--> $DIR/recursive-self-normalization.rs:11:17
9-
|
10-
LL | needs_bar::<T::Assoc>();
11-
| ^^^^^^^^
5+
| ^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo>::Assoc`
126
|
137
note: required by a bound in `needs_bar`
148
--> $DIR/recursive-self-normalization.rs:8:17
159
|
1610
LL | fn needs_bar<S: Bar>() {}
1711
| ^^^ required by this bound in `needs_bar`
18-
19-
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Sized`
20-
--> $DIR/recursive-self-normalization.rs:11:17
21-
|
22-
LL | needs_bar::<T::Assoc>();
23-
| ^^^^^^^^
24-
|
25-
note: required by an implicit `Sized` bound in `needs_bar`
26-
--> $DIR/recursive-self-normalization.rs:8:14
27-
|
28-
LL | fn needs_bar<S: Bar>() {}
29-
| ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar`
30-
help: consider relaxing the implicit `Sized` restriction
31-
|
32-
LL | fn needs_bar<S: Bar + ?Sized>() {}
33-
| ++++++++
34-
35-
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
36-
--> $DIR/recursive-self-normalization.rs:11:5
37-
|
38-
LL | needs_bar::<T::Assoc>();
39-
| ^^^^^^^^^^^^^^^^^^^^^
40-
41-
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
42-
--> $DIR/recursive-self-normalization.rs:11:5
43-
|
44-
LL | needs_bar::<T::Assoc>();
45-
| ^^^^^^^^^^^^^^^^^^^^^
46-
|
47-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
48-
49-
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc == _`
50-
--> $DIR/recursive-self-normalization.rs:11:17
51-
|
52-
LL | needs_bar::<T::Assoc>();
53-
| ^^^^^^^^
12+
help: consider further restricting the associated type
5413
|
55-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14+
LL | fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() where <T as Foo>::Assoc: Bar {
15+
| ++++++++++++++++++++++++++++
5616

57-
error: aborting due to 6 previous errors
17+
error: aborting due to 1 previous error
5818

59-
For more information about this error, try `rustc --explain E0275`.
19+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)
Please sign in to comment.