diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 824cf0ccb6eb2..9b25c932ee761 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -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, @@ -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, } impl<'tcx> TypeFolder> 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; + } } } } @@ -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 diff --git a/tests/ui/pattern/usefulness/impl-trait.rs b/tests/ui/pattern/usefulness/impl-trait.rs index 92011dcff5a92..d8b033d5d20f1 100644 --- a/tests/ui/pattern/usefulness/impl-trait.rs +++ b/tests/ui/pattern/usefulness/impl-trait.rs @@ -101,3 +101,20 @@ fn infer_in_match(x: Option) { } } } + +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 } +} diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr index 5b7688180df7c..497a8ba0326df 100644 --- a/tests/ui/pattern/usefulness/impl-trait.stderr +++ b/tests/ui/pattern/usefulness/impl-trait.stderr @@ -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 | @@ -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`.