Skip to content

Commit 6a37b08

Browse files
committed
Reveal opaque types in depth
1 parent f750770 commit 6a37b08

File tree

3 files changed

+48
-16
lines changed

3 files changed

+48
-16
lines changed

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

+33-8
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,9 @@ use rustc_arena::TypedArena;
319319
use rustc_data_structures::stack::ensure_sufficient_stack;
320320
use rustc_hir::def_id::DefId;
321321
use rustc_hir::HirId;
322-
use rustc_middle::ty::{self, Ty, TyCtxt};
322+
use rustc_middle::ty::{
323+
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
324+
};
323325
use rustc_session::lint;
324326
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
325327
use rustc_span::{Span, DUMMY_SP};
@@ -363,17 +365,40 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
363365

364366
/// Type inference occasionally gives us opaque types in places where corresponding patterns
365367
/// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited
366-
/// types, we use the corresponding concrete type if possible.
368+
/// types, we use the corresponding concrete type if possible. This recursively reveals all the
369+
/// opaque types in `ty` that we can.
367370
fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
368-
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
369-
if let Some(local_def_id) = alias_ty.def_id.as_local() {
370-
let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
371-
if let Some(real_ty) = self.typeck_results.concrete_opaque_types.get(&key) {
372-
return real_ty.ty;
371+
struct RevealOpaqueTys<'tcx> {
372+
tcx: TyCtxt<'tcx>,
373+
typeck_results: &'tcx ty::TypeckResults<'tcx>,
374+
}
375+
376+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RevealOpaqueTys<'tcx> {
377+
fn interner(&self) -> TyCtxt<'tcx> {
378+
self.tcx
379+
}
380+
fn fold_ty(&mut self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
381+
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
382+
if let Some(local_def_id) = alias_ty.def_id.as_local() {
383+
let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
384+
if let Some(real_ty) = self.typeck_results.concrete_opaque_types.get(&key) {
385+
ty = real_ty.ty;
386+
}
387+
}
373388
}
389+
390+
if ty.has_opaque_types() { ty.super_fold_with(self) } else { ty }
374391
}
375392
}
376-
ty
393+
394+
if ty.has_opaque_types() {
395+
ty.fold_with(&mut RevealOpaqueTys {
396+
tcx: self.tcx,
397+
typeck_results: self.typeck_results,
398+
})
399+
} else {
400+
ty
401+
}
377402
}
378403
}
379404

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ fn option_never(x: Void) -> Option<impl Copy> {
4242
}
4343
match option_never(x) {
4444
None => {}
45-
// FIXME: Unreachable not detected because `is_uninhabited` did not look into the
46-
// opaque type.
47-
_ => {}
45+
_ => {} //~ERROR unreachable
46+
}
47+
match option_never(x) {
48+
None => {}
4849
}
4950
}
5051
Some(x)

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

+11-5
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,33 @@ LL | #![deny(unreachable_patterns)]
1111
| ^^^^^^^^^^^^^^^^^^^^
1212

1313
error: unreachable pattern
14-
--> $DIR/impl-trait.rs:57:13
14+
--> $DIR/impl-trait.rs:45:13
15+
|
16+
LL | _ => {}
17+
| ^
18+
19+
error: unreachable pattern
20+
--> $DIR/impl-trait.rs:58:13
1521
|
1622
LL | Some(_) => {}
1723
| ^^^^^^^
1824

1925
error: unreachable pattern
20-
--> $DIR/impl-trait.rs:61:13
26+
--> $DIR/impl-trait.rs:62:13
2127
|
2228
LL | _ => {}
2329
| ^
2430

2531
error: unreachable pattern
26-
--> $DIR/impl-trait.rs:82:9
32+
--> $DIR/impl-trait.rs:83:9
2733
|
2834
LL | _ => {}
2935
| - matches any value
3036
LL | Some((a, b)) => {}
3137
| ^^^^^^^^^^^^ unreachable pattern
3238

3339
error: unreachable pattern
34-
--> $DIR/impl-trait.rs:96:9
40+
--> $DIR/impl-trait.rs:97:9
3541
|
3642
LL | Some((mut x, mut y)) => {
3743
| ^^^^^^^^^^^^^^^^^^^^
@@ -64,6 +70,6 @@ LL + _ => todo!(),
6470
LL + }
6571
|
6672

67-
error: aborting due to 7 previous errors
73+
error: aborting due to 8 previous errors
6874

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

0 commit comments

Comments
 (0)