Skip to content

Commit 3280909

Browse files
committed
Reveal opaque types in depth
1 parent 39105be commit 3280909

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
@@ -318,7 +318,9 @@ use rustc_arena::TypedArena;
318318
use rustc_data_structures::stack::ensure_sufficient_stack;
319319
use rustc_hir::def_id::DefId;
320320
use rustc_hir::HirId;
321-
use rustc_middle::ty::{self, Ty, TyCtxt};
321+
use rustc_middle::ty::{
322+
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
323+
};
322324
use rustc_session::lint;
323325
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
324326
use rustc_span::{Span, DUMMY_SP};
@@ -362,17 +364,40 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
362364

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

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)