Skip to content

Commit 7f7729d

Browse files
committed
Don't create impl candidates when obligation contains errors
Fixes rust-lang#72839 In PR rust-lang#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.
1 parent 3d5d0f8 commit 7f7729d

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

src/librustc_trait_selection/traits/select/candidate_assembly.rs

+10
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
331331
) -> Result<(), SelectionError<'tcx>> {
332332
debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
333333

334+
// Essentially any user-written impl will match with an error type,
335+
// so creating `ImplCandidates` isn't useful. However, we might
336+
// end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized)
337+
// This helps us avoid overflow: see issue #72839
338+
// Since compilation is already guarnateed to fail, this is just
339+
// to try to show the 'nicest' possible errors to the user.
340+
if obligation.references_error() {
341+
return Ok(());
342+
}
343+
334344
self.tcx().for_each_relevant_impl(
335345
obligation.predicate.def_id(),
336346
obligation.predicate.skip_binder().trait_ref.self_ty(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Regression test for issue #72839
2+
// Tests that we do not overflow during trait selection after
3+
// a type error occurs
4+
use std::ops::Rem;
5+
trait Foo {}
6+
struct MyStruct<T>(T);
7+
8+
impl<T, U> Rem<MyStruct<T>> for MyStruct<U> where MyStruct<U>: Rem<MyStruct<T>> {
9+
type Output = u8;
10+
fn rem(self, _: MyStruct<T>) -> Self::Output {
11+
panic!()
12+
}
13+
}
14+
15+
fn main() {}
16+
17+
fn foo() {
18+
if missing_var % 8 == 0 {} //~ ERROR cannot find
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0425]: cannot find value `missing_var` in this scope
2+
--> $DIR/issue-72839-error-overflow.rs:18:8
3+
|
4+
LL | if missing_var % 8 == 0 {}
5+
| ^^^^^^^^^^^ not found in this scope
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)