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 958909a

Browse files
committedFeb 28, 2025·
change definitely non-productive cycles to error
1 parent 6a3b30f commit 958909a

File tree

19 files changed

+231
-204
lines changed

19 files changed

+231
-204
lines changed
 

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

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,32 @@ 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 miscellaneous
276+
// nested goals will be converted to `GoalSource::MiscKnownInductive` over time.
277+
GoalSource::Misc => PathKind::Unknown,
278+
GoalSource::NormalizeGoal(path_kind) => path_kind,
279+
GoalSource::ImplWhereBound => {
280+
// We currently only consider a cycle coinductive if it steps
281+
// into a where-clause of a coinductive trait.
282+
//
283+
// We probably want to make all traits coinductive in the future,
284+
// so we treat cycles involving their where-clauses as ambiguous.
285+
if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind {
286+
PathKind::Coinductive
287+
} else {
288+
PathKind::Unknown
289+
}
278290
}
279-
_ => PathKind::Inductive,
291+
// A step which is clearly unproductive. Cycles exclusively involving such steps
292+
// result in `Err(NoSolution)`.
293+
GoalSource::MiscKnownInductive | GoalSource::InstantiateHigherRanked => {
294+
PathKind::Inductive
295+
}
296+
// These goal sources are likely unproductive and can be changed to
297+
// `PathKind::Inductive`. Keeping them as unknown until we're confident
298+
// about this and have an example where it is necessary.
299+
GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
280300
}
281301
}
282302

@@ -606,7 +626,7 @@ where
606626

607627
let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw(
608628
GoalEvaluationKind::Nested,
609-
GoalSource::Misc,
629+
GoalSource::normalizes_to(),
610630
unconstrained_goal,
611631
)?;
612632
// Add the nested goals from normalization to our own nested goals.
@@ -683,7 +703,7 @@ where
683703
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
684704
goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(
685705
self,
686-
GoalSource::Misc,
706+
GoalSource::normalizes_to(),
687707
goal.param_env,
688708
));
689709
self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
@@ -939,7 +959,16 @@ where
939959
rhs: T,
940960
) -> Result<(), NoSolution> {
941961
let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
942-
self.add_goals(GoalSource::Misc, goals);
962+
if cfg!(debug_assertions) {
963+
for g in goals.iter() {
964+
match g.predicate.kind().skip_binder() {
965+
ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {}
966+
p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
967+
}
968+
}
969+
}
970+
// Relating types is always unproductive.
971+
self.add_goals(GoalSource::MiscKnownInductive, goals);
943972
Ok(())
944973
}
945974

‎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: 106 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,71 @@ 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+
/// The implementation of this function is kind of ugly. We check whether
338+
/// there currently exist 'weaker' paths in the set, if so we upgrade these
339+
/// paths to at least `path`.
340+
#[must_use]
341+
fn extend_with(mut self, path: PathKind) -> Self {
342+
match path {
343+
PathKind::Inductive => {
344+
if self.intersects(PathsToNested::EMPTY) {
345+
self.remove(PathsToNested::EMPTY);
346+
self.insert(PathsToNested::INDUCTIVE);
347+
}
348+
}
349+
PathKind::Unknown => {
350+
if self.intersects(PathsToNested::EMPTY | PathsToNested::INDUCTIVE) {
351+
self.remove(PathsToNested::EMPTY | PathsToNested::INDUCTIVE);
352+
self.insert(PathsToNested::UNKNOWN);
353+
}
354+
}
355+
PathKind::Coinductive => {
356+
if self.intersects(
357+
PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
358+
) {
359+
self.remove(
360+
PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
361+
);
362+
self.insert(PathsToNested::COINDUCTIVE);
363+
}
364+
}
365+
}
366+
367+
self
368+
}
369+
}
370+
308371
/// The nested goals of each stack entry and the path from the
309372
/// stack entry to that nested goal.
310373
///
@@ -322,15 +385,18 @@ impl CycleHeads {
322385
/// results from a the cycle BAB depending on the cycle root.
323386
#[derive_where(Debug, Default, Clone; X: Cx)]
324387
struct NestedGoals<X: Cx> {
325-
nested_goals: HashMap<X::Input, UsageKind>,
388+
nested_goals: HashMap<X::Input, PathsToNested>,
326389
}
327390
impl<X: Cx> NestedGoals<X> {
328391
fn is_empty(&self) -> bool {
329392
self.nested_goals.is_empty()
330393
}
331394

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);
395+
fn insert(&mut self, input: X::Input, paths_to_nested: PathsToNested) {
396+
match self.nested_goals.entry(input) {
397+
Entry::Occupied(mut entry) => *entry.get_mut() |= paths_to_nested,
398+
Entry::Vacant(entry) => drop(entry.insert(paths_to_nested)),
399+
}
334400
}
335401

336402
/// Adds the nested goals of a nested goal, given that the path `step_kind` from this goal
@@ -341,18 +407,15 @@ impl<X: Cx> NestedGoals<X> {
341407
/// the same as for the child.
342408
fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals<X>) {
343409
#[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);
410+
for (input, paths_to_nested) in nested_goals.iter() {
411+
let paths_to_nested = paths_to_nested.extend_with(step_kind);
412+
self.insert(input, paths_to_nested);
350413
}
351414
}
352415

353416
#[cfg_attr(feature = "nightly", rustc_lint_query_instability)]
354417
#[allow(rustc::potential_query_instability)]
355-
fn iter(&self) -> impl Iterator<Item = (X::Input, UsageKind)> {
418+
fn iter(&self) -> impl Iterator<Item = (X::Input, PathsToNested)> + '_ {
356419
self.nested_goals.iter().map(|(i, p)| (*i, *p))
357420
}
358421

@@ -490,7 +553,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
490553
// goals as this change may cause them to now depend on additional
491554
// goals, resulting in new cycles. See the dev-guide for examples.
492555
if parent_depends_on_cycle {
493-
parent.nested_goals.insert(parent.input, UsageKind::Single(PathKind::Inductive))
556+
parent.nested_goals.insert(parent.input, PathsToNested::EMPTY);
494557
}
495558
}
496559
}
@@ -666,7 +729,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
666729
//
667730
// We must therefore not use the global cache entry for `B` in that case.
668731
// See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs
669-
last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive));
732+
last.nested_goals.insert(last.input, PathsToNested::EMPTY);
670733
}
671734

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

750813
// We now care about the path from the next highest cycle head to the
751814
// 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-
}
815+
*path_from_head = path_from_head.extend(Self::cycle_path_kind(
816+
&self.stack,
817+
stack_entry.step_kind_from_parent,
818+
head,
819+
));
762820
// Mutate the result of the provisional cache entry in case we did
763821
// not reach a fixpoint.
764822
*result = mutate_result(input, *result);
@@ -858,7 +916,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
858916
for &ProvisionalCacheEntry {
859917
encountered_overflow,
860918
ref heads,
861-
path_from_head,
919+
path_from_head: head_to_provisional,
862920
result: _,
863921
} in entries.iter()
864922
{
@@ -870,24 +928,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
870928

871929
// A provisional cache entry only applies if the path from its highest head
872930
// matches the path when encountering the goal.
931+
//
932+
// We check if any of the paths taken while computing the global goal
933+
// would end up with an applicable provisional cache entry.
873934
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"),
935+
let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head);
936+
let full_paths = path_from_global_entry.extend_with(head_to_curr);
937+
if full_paths.contains(head_to_provisional.into()) {
938+
debug!(
939+
?full_paths,
940+
?head_to_provisional,
941+
"cache entry not applicable due to matching paths"
942+
);
943+
return false;
891944
}
892945
}
893946
}
@@ -986,8 +1039,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
9861039
let last = &mut self.stack[last_index];
9871040
last.reached_depth = last.reached_depth.max(next_index);
9881041

989-
last.nested_goals.insert(input, UsageKind::Single(step_kind_from_parent));
990-
last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive));
1042+
last.nested_goals.insert(input, step_kind_from_parent.into());
1043+
last.nested_goals.insert(last.input, PathsToNested::EMPTY);
9911044
if last_index != head {
9921045
last.heads.insert(head, step_kind_from_parent);
9931046
}

‎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.