Skip to content

Commit 1d04764

Browse files
committed
Handle recursive opaque types in reveal_opaque_ty
1 parent 6a37b08 commit 1d04764

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

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

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

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

376379
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RevealOpaqueTys<'tcx> {
377380
fn interner(&self) -> TyCtxt<'tcx> {
378381
self.tcx
379382
}
380-
fn fold_ty(&mut self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
383+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
381384
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
382385
if let Some(local_def_id) = alias_ty.def_id.as_local() {
386+
// Abort if we found a recursive loop.
387+
if self.parent_opaques.contains(&local_def_id) {
388+
return ty;
389+
}
383390
let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
384391
if let Some(real_ty) = self.typeck_results.concrete_opaque_types.get(&key) {
385-
ty = real_ty.ty;
392+
let ty = real_ty.ty;
393+
if ty.has_opaque_types() {
394+
self.parent_opaques.push(local_def_id);
395+
let folded = ty.super_fold_with(self);
396+
self.parent_opaques.pop();
397+
return folded;
398+
} else {
399+
return ty;
400+
}
386401
}
387402
}
388403
}
@@ -395,6 +410,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
395410
ty.fold_with(&mut RevealOpaqueTys {
396411
tcx: self.tcx,
397412
typeck_results: self.typeck_results,
413+
parent_opaques: Vec::new(),
398414
})
399415
} else {
400416
ty

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

+31
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,34 @@ 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+
let w: Option<&'static W> = None;
120+
Rec { n: 0, w }
121+
}
122+
123+
type X = impl Copy;
124+
struct SecretelyVoid(X);
125+
fn nested_empty_opaque(x: Void) -> X {
126+
if true {
127+
let opaque_void = nested_empty_opaque(x);
128+
let secretely_void = SecretelyVoid(opaque_void);
129+
match secretely_void {
130+
_ => {}
131+
}
132+
}
133+
x
134+
}

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)