Rollup merge of #73005 - Aaron1011:fix/error-overflow, r=estebank

Don't create impl candidates when obligation contains errors

Fixes #72839

In PR #72621, trait selection was modified to no longer bail out early
when an error type was encountered. This allowed us treat `ty::Error` as
`Sized`, causing us to avoid emitting a spurious "not sized" error after
a type error had already occured.

However, this means that we may now try to match an impl candidate
against the error type. Since the error type will unify with almost
anything, this can cause us to infinitely recurse (eventually triggering
an overflow) when trying to verify certain `where` clauses.

This commit causes us to skip generating any impl candidates when an
error type is involved.
This commit is contained in:
Dylan DPC 2020-06-10 11:03:43 +02:00 committed by GitHub
commit 024f025934
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 181 deletions

View File

@ -331,6 +331,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<(), SelectionError<'tcx>> {
debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
// Essentially any user-written impl will match with an error type,
// so creating `ImplCandidates` isn't useful. However, we might
// end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized)
// This helps us avoid overflow: see issue #72839
// Since compilation is already guaranteed to fail, this is just
// to try to show the 'nicest' possible errors to the user.
if obligation.references_error() {
return Ok(());
}
self.tcx().for_each_relevant_impl(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),

View File

@ -1104,6 +1104,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// who might care about this case, like coherence, should use
// that function).
if candidates.is_empty() {
// If there's an error type, 'downgrade' our result from
// `Err(Unimplemented)` to `Ok(None)`. This helps us avoid
// emitting additional spurious errors, since we're guaranteed
// to have emitted at least one.
if stack.obligation.references_error() {
debug!("no results for error type, treating as ambiguous");
return Ok(None);
}
return Err(Unimplemented);
}

View File

@ -11,8 +11,6 @@ fn main() {
// return type, which can't depend on the obligation.
fn cycle1() -> impl Clone {
//~^ ERROR cycle detected
//~| ERROR cycle detected
//~| ERROR cycle detected
send(cycle2().clone());
//~^ ERROR cannot be sent between threads safely

View File

@ -36,37 +36,37 @@ LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
note: ...which requires computing type of `cycle2::{{opaque}}#0`...
--> $DIR/auto-trait-leak.rs:22:16
--> $DIR/auto-trait-leak.rs:20:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
--> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
--> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
--> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
--> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
--> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
--> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -84,178 +84,8 @@ LL | | Rc::new(String::from("foo"))
LL | | }
| |_^
error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0`
--> $DIR/auto-trait-leak.rs:12:16
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^
|
note: ...which requires borrow-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
note: ...which requires computing type of `cycle2::{{opaque}}#0`...
--> $DIR/auto-trait-leak.rs:22:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle
note: cycle used when checking item types in top-level module
--> $DIR/auto-trait-leak.rs:1:1
|
LL | / use std::cell::Cell;
LL | | use std::rc::Rc;
LL | |
LL | | fn send<T: Send>(_: T) {}
... |
LL | | Rc::new(String::from("foo"))
LL | | }
| |_^
error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0`
--> $DIR/auto-trait-leak.rs:12:16
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^
|
note: ...which requires borrow-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
note: ...which requires computing type of `cycle2::{{opaque}}#0`...
--> $DIR/auto-trait-leak.rs:22:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle
note: cycle used when checking item types in top-level module
--> $DIR/auto-trait-leak.rs:1:1
|
LL | / use std::cell::Cell;
LL | | use std::rc::Rc;
LL | |
LL | | fn send<T: Send>(_: T) {}
... |
LL | | Rc::new(String::from("foo"))
LL | | }
| |_^
error[E0277]: `std::rc::Rc<std::string::String>` cannot be sent between threads safely
--> $DIR/auto-trait-leak.rs:16:5
--> $DIR/auto-trait-leak.rs:14:5
|
LL | fn send<T: Send>(_: T) {}
| ---- required by this bound in `send`
@ -269,7 +99,7 @@ LL | fn cycle2() -> impl Clone {
= help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
= note: required because it appears within the type `impl std::clone::Clone`
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0391.
For more information about an error, try `rustc --explain E0277`.

View File

@ -0,0 +1,19 @@
// Regression test for issue #72839
// Tests that we do not overflow during trait selection after
// a type error occurs
use std::ops::Rem;
trait Foo {}
struct MyStruct<T>(T);
impl<T, U> Rem<MyStruct<T>> for MyStruct<U> where MyStruct<U>: Rem<MyStruct<T>> {
type Output = u8;
fn rem(self, _: MyStruct<T>) -> Self::Output {
panic!()
}
}
fn main() {}
fn foo() {
if missing_var % 8 == 0 {} //~ ERROR cannot find
}

View File

@ -0,0 +1,9 @@
error[E0425]: cannot find value `missing_var` in this scope
--> $DIR/issue-72839-error-overflow.rs:18:8
|
LL | if missing_var % 8 == 0 {}
| ^^^^^^^^^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.