pub enum ProjectionCacheEntry<'tcx> {
InProgress,
Ambiguous,
+ Recur,
Error,
NormalizedTy(NormalizedTy<'tcx>),
}
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
key, value
);
- let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value));
+ let mut map = self.map();
+ if let Some(ProjectionCacheEntry::Recur) = map.get(&key) {
+ debug!("Not overwriting Recur");
+ return;
+ }
+ let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
assert!(!fresh_key, "never started projecting `{:?}`", key);
}
assert!(!fresh, "never started projecting `{:?}`", key);
}
+ /// Indicates that while trying to normalize `key`, `key` was required to
+ /// be normalized again. Selection or evaluation should eventually report
+ /// an error here.
+ pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) {
+ let fresh = self.map().insert(key, ProjectionCacheEntry::Recur);
+ assert!(!fresh, "never started projecting `{:?}`", key);
+ }
+
/// Indicates that trying to normalize `key` resulted in
/// error.
pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
return Ok(None);
}
Err(ProjectionCacheEntry::InProgress) => {
- // If while normalized A::B, we are asked to normalize
- // A::B, just return A::B itself. This is a conservative
- // answer, in the sense that A::B *is* clearly equivalent
- // to A::B, though there may be a better value we can
- // find.
-
// Under lazy normalization, this can arise when
// bootstrapping. That is, imagine an environment with a
// where-clause like `A::B == u32`. Now, if we are asked
debug!("found cache entry: in-progress");
+ // Cache that normalizing this projection resulted in a cycle. This
+ // should ensure that, unless this happens within a snapshot that's
+ // rolled back, fulfillment or evaluation will notice the cycle.
+
+ infcx.inner.borrow_mut().projection_cache().recur(cache_key);
+ return Err(InProgress);
+ }
+ Err(ProjectionCacheEntry::Recur) => {
return Err(InProgress);
}
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
self.infcx.tcx
}
+ pub(super) fn query_mode(&self) -> TraitQueryMode {
+ self.query_mode
+ }
+
///////////////////////////////////////////////////////////////////////////
// Selection
//
// ...but not in an impl that redefines one of the types.
impl Tr for bool {
type A = Box<Self::B>;
- //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
+ //~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
}
// (the error is shown twice for some reason)
impl Tr for usize {
type B = &'static Self::A;
- //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
+ //~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
}
fn main() {
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
+error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
--> $DIR/defaults-cyclic-fail-1.rs:26:5
|
LL | type A = Box<Self::B>;
- | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
+error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
--> $DIR/defaults-cyclic-fail-1.rs:32:5
|
LL | type B = &'static Self::A;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0275`.
impl Tr for bool {
type A = Box<Self::B>;
- //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
+ //~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
}
// (the error is shown twice for some reason)
impl Tr for usize {
type B = &'static Self::A;
- //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
+ //~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
}
fn main() {
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
+error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
--> $DIR/defaults-cyclic-fail-2.rs:27:5
|
LL | type A = Box<Self::B>;
- | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
+error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
--> $DIR/defaults-cyclic-fail-2.rs:33:5
|
LL | type B = &'static Self::A;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0275`.
--- /dev/null
+// Regression test for #79714
+
+trait Baz {}
+impl Baz for () {}
+impl<T> Baz for (T,) {}
+
+trait Fiz {}
+impl Fiz for bool {}
+
+trait Grault {
+ type A;
+ type B;
+}
+
+impl<T: Grault> Grault for (T,)
+where
+ Self::A: Baz,
+ Self::B: Fiz,
+{
+ type A = ();
+ //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ type B = bool;
+ //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+}
+//~^^^^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+
+fn main() {
+ let x: <(_,) as Grault>::A = ();
+}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-1.rs:15:1
+ |
+LL | / impl<T: Grault> Grault for (T,)
+LL | | where
+LL | | Self::A: Baz,
+LL | | Self::B: Fiz,
+... |
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+ = note: 1 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-1.rs:20:5
+ |
+LL | type A = ();
+ | ^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+ = note: 1 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-1.rs:22:5
+ |
+LL | type B = bool;
+ | ^^^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+ = note: 1 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
--- /dev/null
+// Regression test for #79714
+
+trait Grault {
+ type A;
+}
+
+impl<T: Grault> Grault for (T,)
+where
+ Self::A: Copy,
+{
+ type A = ();
+ //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+}
+//~^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+
+fn main() {}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-2.rs:7:1
+ |
+LL | / impl<T: Grault> Grault for (T,)
+LL | | where
+LL | | Self::A: Copy,
+LL | | {
+LL | | type A = ();
+LL | |
+LL | | }
+ | |_^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+ --> $DIR/impl-wf-cycle-2.rs:11:5
+ |
+LL | type A = ();
+ | ^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Grault` for `(T,)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0275`.