@@ -9,14 +9,16 @@ use hir_def::{
99 adt:: VariantData , attr:: Attrs , visibility:: Visibility , AdtId , EnumVariantId , HasModule , Lookup ,
1010 ModuleId , VariantId ,
1111} ;
12+ use rustc_hash:: FxHashSet ;
1213
1314use crate :: {
1415 consteval:: try_const_usize, db:: HirDatabase , Binders , Interner , Substitution , Ty , TyKind ,
1516} ;
1617
1718/// Checks whether a type is visibly uninhabited from a particular module.
1819pub ( crate ) fn is_ty_uninhabited_from ( ty : & Ty , target_mod : ModuleId , db : & dyn HirDatabase ) -> bool {
19- let mut uninhabited_from = UninhabitedFrom { target_mod, db } ;
20+ let mut uninhabited_from =
21+ UninhabitedFrom { target_mod, db, max_depth : 500 , recursive_ty : FxHashSet :: default ( ) } ;
2022 let inhabitedness = ty. visit_with ( & mut uninhabited_from, DebruijnIndex :: INNERMOST ) ;
2123 inhabitedness == BREAK_VISIBLY_UNINHABITED
2224}
@@ -32,7 +34,8 @@ pub(crate) fn is_enum_variant_uninhabited_from(
3234 let vars_attrs = db. variants_attrs ( variant. parent ) ;
3335 let is_local = variant. parent . lookup ( db. upcast ( ) ) . container . krate ( ) == target_mod. krate ( ) ;
3436
35- let mut uninhabited_from = UninhabitedFrom { target_mod, db } ;
37+ let mut uninhabited_from =
38+ UninhabitedFrom { target_mod, db, max_depth : 500 , recursive_ty : FxHashSet :: default ( ) } ;
3639 let inhabitedness = uninhabited_from. visit_variant (
3740 variant. into ( ) ,
3841 & enum_data. variants [ variant. local_id ] . variant_data ,
@@ -45,6 +48,9 @@ pub(crate) fn is_enum_variant_uninhabited_from(
4548
4649struct UninhabitedFrom < ' a > {
4750 target_mod : ModuleId ,
51+ recursive_ty : FxHashSet < Ty > ,
52+ // guard for preventing stack overflow in non trivial non terminating types
53+ max_depth : usize ,
4854 db : & ' a dyn HirDatabase ,
4955}
5056
@@ -65,7 +71,14 @@ impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
6571 ty : & Ty ,
6672 outer_binder : DebruijnIndex ,
6773 ) -> ControlFlow < VisiblyUninhabited > {
68- match ty. kind ( Interner ) {
74+ if self . recursive_ty . contains ( ty) || self . max_depth == 0 {
75+ // rustc considers recursive types always inhabited. I think it is valid to consider
76+ // recursive types as always uninhabited, but we should do what rustc is doing.
77+ return CONTINUE_OPAQUELY_INHABITED ;
78+ }
79+ self . recursive_ty . insert ( ty. clone ( ) ) ;
80+ self . max_depth -= 1 ;
81+ let r = match ty. kind ( Interner ) {
6982 TyKind :: Adt ( adt, subst) => self . visit_adt ( adt. 0 , subst) ,
7083 TyKind :: Never => BREAK_VISIBLY_UNINHABITED ,
7184 TyKind :: Tuple ( ..) => ty. super_visit_with ( self , outer_binder) ,
@@ -75,7 +88,10 @@ impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
7588 } ,
7689
7790 TyKind :: Ref ( ..) | _ => CONTINUE_OPAQUELY_INHABITED ,
78- }
91+ } ;
92+ self . recursive_ty . remove ( ty) ;
93+ self . max_depth += 1 ;
94+ r
7995 }
8096
8197 fn interner ( & self ) -> Interner {
0 commit comments