Skip to content

Commit

Permalink
Handle recursive opaque types in reveal_opaque_ty
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Oct 30, 2023
1 parent 3280909 commit e822651
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 4 deletions.
22 changes: 19 additions & 3 deletions compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ use rustc_data_structures::captures::Captures;

use rustc_arena::TypedArena;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::HirId;
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
Expand Down Expand Up @@ -370,18 +370,33 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
struct RevealOpaqueTys<'tcx> {
tcx: TyCtxt<'tcx>,
typeck_results: &'tcx ty::TypeckResults<'tcx>,
// When we reveal nested opaques, we track the parents in a stack-like fashion to avoid
// recursive loops like in #113326.
parent_opaques: Vec<LocalDefId>,
}

impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RevealOpaqueTys<'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
if let Some(local_def_id) = alias_ty.def_id.as_local() {
// Abort if we found a recursive loop.
if self.parent_opaques.contains(&local_def_id) {
return ty;
}
let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
if let Some(real_ty) = self.typeck_results.concrete_opaque_types.get(&key) {
ty = real_ty.ty;
let ty = real_ty.ty;
if ty.has_opaque_types() {
self.parent_opaques.push(local_def_id);
let folded = ty.super_fold_with(self);
self.parent_opaques.pop();
return folded;
} else {
return ty;
}
}
}
}
Expand All @@ -394,6 +409,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
ty.fold_with(&mut RevealOpaqueTys {
tcx: self.tcx,
typeck_results: self.typeck_results,
parent_opaques: Vec::new(),
})
} else {
ty
Expand Down
17 changes: 17 additions & 0 deletions tests/ui/pattern/usefulness/impl-trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,20 @@ fn infer_in_match(x: Option<V>) {
}
}
}

type W = impl Copy;
#[derive(Copy, Clone)]
struct Rec<'a> {
n: u32,
w: Option<&'a W>,
}
fn recursive_opaque() -> W {
if true {
match recursive_opaque() {
// Check for the ol' ICE when the type is recursively opaque.
_ => {}
Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} //~ERROR unreachable
}
}
Rec { n: 0, w: None }
}
10 changes: 9 additions & 1 deletion tests/ui/pattern/usefulness/impl-trait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ error: unreachable pattern
LL | Some((mut x, mut y)) => {
| ^^^^^^^^^^^^^^^^^^^^

error: unreachable pattern
--> $DIR/impl-trait.rs:116:13
|
LL | _ => {}
| - matches any value
LL | Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern

error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty
--> $DIR/impl-trait.rs:21:11
|
Expand Down Expand Up @@ -70,6 +78,6 @@ LL + _ => todo!(),
LL + }
|

error: aborting due to 8 previous errors
error: aborting due to 9 previous errors

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

0 comments on commit e822651

Please sign in to comment.