1
Fork 0

Fix stack overflow in exhaustiveness due to recursive HIR opaque type values

This commit is contained in:
Michael Goulet 2025-04-07 22:32:49 +00:00
parent e643f59f6d
commit b08e9c2a60
4 changed files with 224 additions and 5 deletions

View file

@ -1,5 +1,6 @@
use std::fmt;
use std::iter::once;
use std::ops::ControlFlow;
use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
use rustc_arena::DroplessArena;
@ -11,7 +12,8 @@ use rustc_middle::mir::{self, Const};
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{
self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, VariantDef,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
@ -135,11 +137,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
/// Returns the hidden type corresponding to this key if the body under analysis is allowed to
/// know it.
fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
self.typeck_results
.concrete_opaque_types
.get(&key.def_id)
.map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args))
if let Some(hidden_ty) = self.typeck_results.concrete_opaque_types.get(&key.def_id) {
let ty = ty::EarlyBinder::bind(hidden_ty.ty).instantiate(self.tcx, key.args);
if ty.visit_with(&mut RecursiveOpaque { def_id: key.def_id.into() }).is_continue() {
Some(ty)
} else {
// HACK: We skip revealing opaque types which recursively expand
// to themselves. This is because we may infer hidden types like
// `Opaque<T> = Opaque<Opaque<T>>` or `Opaque<T> = Opaque<(T,)>`
// in hir typeck.
None
}
} else {
None
}
}
// This can take a non-revealed `Ty` because it reveals opaques itself.
pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
!ty.inhabited_predicate(self.tcx).apply_revealing_opaque(
@ -1105,3 +1118,20 @@ pub fn analyze_match<'p, 'tcx>(
Ok(report)
}
struct RecursiveOpaque {
def_id: DefId,
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for RecursiveOpaque {
type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
if let ty::Alias(ty::Opaque, alias_ty) = t.kind() {
if alias_ty.def_id == self.def_id {
return ControlFlow::Break(());
}
}
if t.has_opaque_types() { t.super_visit_with(self) } else { ControlFlow::Continue(()) }
}
}