Skip to content

Commit e822651

Browse files
committed
Handle recursive opaque types in reveal_opaque_ty
1 parent 3280909 commit e822651

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ use rustc_data_structures::captures::Captures;
316316

317317
use rustc_arena::TypedArena;
318318
use rustc_data_structures::stack::ensure_sufficient_stack;
319-
use rustc_hir::def_id::DefId;
319+
use rustc_hir::def_id::{DefId, LocalDefId};
320320
use rustc_hir::HirId;
321321
use rustc_middle::ty::{
322322
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
@@ -370,18 +370,33 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
370370
struct RevealOpaqueTys<'tcx> {
371371
tcx: TyCtxt<'tcx>,
372372
typeck_results: &'tcx ty::TypeckResults<'tcx>,
373+
// When we reveal nested opaques, we track the parents in a stack-like fashion to avoid
374+
// recursive loops like in #113326.
375+
parent_opaques: Vec<LocalDefId>,
373376
}
374377

375378
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RevealOpaqueTys<'tcx> {
376379
fn interner(&self) -> TyCtxt<'tcx> {
377380
self.tcx
378381
}
379-
fn fold_ty(&mut self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
382+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
380383
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
381384
if let Some(local_def_id) = alias_ty.def_id.as_local() {
385+
// Abort if we found a recursive loop.
386+
if self.parent_opaques.contains(&local_def_id) {
387+
return ty;
388+
}
382389
let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
383390
if let Some(real_ty) = self.typeck_results.concrete_opaque_types.get(&key) {
384-
ty = real_ty.ty;
391+
let ty = real_ty.ty;
392+
if ty.has_opaque_types() {
393+
self.parent_opaques.push(local_def_id);
394+
let folded = ty.super_fold_with(self);
395+
self.parent_opaques.pop();
396+
return folded;
397+
} else {
398+
return ty;
399+
}
385400
}
386401
}
387402
}
@@ -394,6 +409,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
394409
ty.fold_with(&mut RevealOpaqueTys {
395410
tcx: self.tcx,
396411
typeck_results: self.typeck_results,
412+
parent_opaques: Vec::new(),
397413
})
398414
} else {
399415
ty

tests/ui/pattern/usefulness/impl-trait.rs

+17
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,20 @@ fn infer_in_match(x: Option<V>) {
101101
}
102102
}
103103
}
104+
105+
type W = impl Copy;
106+
#[derive(Copy, Clone)]
107+
struct Rec<'a> {
108+
n: u32,
109+
w: Option<&'a W>,
110+
}
111+
fn recursive_opaque() -> W {
112+
if true {
113+
match recursive_opaque() {
114+
// Check for the ol' ICE when the type is recursively opaque.
115+
_ => {}
116+
Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} //~ERROR unreachable
117+
}
118+
}
119+
Rec { n: 0, w: None }
120+
}

tests/ui/pattern/usefulness/impl-trait.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ error: unreachable pattern
4242
LL | Some((mut x, mut y)) => {
4343
| ^^^^^^^^^^^^^^^^^^^^
4444

45+
error: unreachable pattern
46+
--> $DIR/impl-trait.rs:116:13
47+
|
48+
LL | _ => {}
49+
| - matches any value
50+
LL | Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {}
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
52+
4553
error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty
4654
--> $DIR/impl-trait.rs:21:11
4755
|
@@ -70,6 +78,6 @@ LL + _ => todo!(),
7078
LL + }
7179
|
7280

73-
error: aborting due to 8 previous errors
81+
error: aborting due to 9 previous errors
7482

7583
For more information about this error, try `rustc --explain E0004`.

0 commit comments

Comments
 (0)