11//! Type inhabitedness logic.
22use std:: ops:: ControlFlow :: { self , Break , Continue } ;
33
4- use chalk_ir:: {
5- DebruijnIndex ,
6- visit:: { TypeSuperVisitable , TypeVisitable , TypeVisitor } ,
7- } ;
84use hir_def:: { AdtId , EnumVariantId , ModuleId , VariantId , visibility:: Visibility } ;
95use rustc_hash:: FxHashSet ;
6+ use rustc_type_ir:: {
7+ TypeSuperVisitable , TypeVisitable , TypeVisitor ,
8+ inherent:: { AdtDef , IntoKind } ,
9+ } ;
1010use triomphe:: Arc ;
1111
1212use crate :: {
13- AliasTy , Binders , Interner , Substitution , TraitEnvironment , Ty , TyKind ,
13+ TraitEnvironment ,
1414 consteval:: try_const_usize,
1515 db:: HirDatabase ,
16- next_solver:: { DbInterner , mapping:: ChalkToNextSolver } ,
16+ next_solver:: {
17+ DbInterner , EarlyBinder , GenericArgs , Ty , TyKind ,
18+ infer:: { InferCtxt , traits:: ObligationCause } ,
19+ obligation_ctxt:: ObligationCtxt ,
20+ } ,
1721} ;
1822
1923// FIXME: Turn this into a query, it can be quite slow
2024/// Checks whether a type is visibly uninhabited from a particular module.
21- pub ( crate ) fn is_ty_uninhabited_from (
22- db : & dyn HirDatabase ,
23- ty : & Ty ,
25+ pub ( crate ) fn is_ty_uninhabited_from < ' db > (
26+ infcx : & InferCtxt < ' db > ,
27+ ty : Ty < ' db > ,
2428 target_mod : ModuleId ,
25- env : Arc < TraitEnvironment < ' _ > > ,
29+ env : Arc < TraitEnvironment < ' db > > ,
2630) -> bool {
2731 let _p = tracing:: info_span!( "is_ty_uninhabited_from" , ?ty) . entered ( ) ;
28- let mut uninhabited_from =
29- UninhabitedFrom { target_mod, db, max_depth : 500 , recursive_ty : FxHashSet :: default ( ) , env } ;
30- let inhabitedness = ty. visit_with ( & mut uninhabited_from, DebruijnIndex :: INNERMOST ) ;
32+ let mut uninhabited_from = UninhabitedFrom :: new ( infcx, target_mod, env) ;
33+ let inhabitedness = ty. visit_with ( & mut uninhabited_from) ;
3134 inhabitedness == BREAK_VISIBLY_UNINHABITED
3235}
3336
3437// FIXME: Turn this into a query, it can be quite slow
3538/// Checks whether a variant is visibly uninhabited from a particular module.
36- pub ( crate ) fn is_enum_variant_uninhabited_from (
37- db : & dyn HirDatabase ,
39+ pub ( crate ) fn is_enum_variant_uninhabited_from < ' db > (
40+ infcx : & InferCtxt < ' db > ,
3841 variant : EnumVariantId ,
39- subst : & Substitution ,
42+ subst : GenericArgs < ' db > ,
4043 target_mod : ModuleId ,
41- env : Arc < TraitEnvironment < ' _ > > ,
44+ env : Arc < TraitEnvironment < ' db > > ,
4245) -> bool {
4346 let _p = tracing:: info_span!( "is_enum_variant_uninhabited_from" ) . entered ( ) ;
4447
45- let mut uninhabited_from =
46- UninhabitedFrom { target_mod, db, max_depth : 500 , recursive_ty : FxHashSet :: default ( ) , env } ;
48+ let mut uninhabited_from = UninhabitedFrom :: new ( infcx, target_mod, env) ;
4749 let inhabitedness = uninhabited_from. visit_variant ( variant. into ( ) , subst) ;
4850 inhabitedness == BREAK_VISIBLY_UNINHABITED
4951}
5052
51- struct UninhabitedFrom < ' a > {
53+ struct UninhabitedFrom < ' a , ' db > {
5254 target_mod : ModuleId ,
53- recursive_ty : FxHashSet < Ty > ,
55+ recursive_ty : FxHashSet < Ty < ' db > > ,
5456 // guard for preventing stack overflow in non trivial non terminating types
5557 max_depth : usize ,
56- db : & ' a dyn HirDatabase ,
57- env : Arc < TraitEnvironment < ' a > > ,
58+ infcx : & ' a InferCtxt < ' db > ,
59+ env : Arc < TraitEnvironment < ' db > > ,
5860}
5961
6062const CONTINUE_OPAQUELY_INHABITED : ControlFlow < VisiblyUninhabited > = Continue ( ( ) ) ;
6163const BREAK_VISIBLY_UNINHABITED : ControlFlow < VisiblyUninhabited > = Break ( VisiblyUninhabited ) ;
6264#[ derive( PartialEq , Eq ) ]
6365struct VisiblyUninhabited ;
6466
65- impl TypeVisitor < Interner > for UninhabitedFrom < ' _ > {
66- type BreakTy = VisiblyUninhabited ;
67-
68- fn as_dyn ( & mut self ) -> & mut dyn TypeVisitor < Interner , BreakTy = VisiblyUninhabited > {
69- self
70- }
67+ impl < ' db > TypeVisitor < DbInterner < ' db > > for UninhabitedFrom < ' _ , ' db > {
68+ type Result = ControlFlow < VisiblyUninhabited > ;
7169
72- fn visit_ty (
73- & mut self ,
74- ty : & Ty ,
75- outer_binder : DebruijnIndex ,
76- ) -> ControlFlow < VisiblyUninhabited > {
77- if self . recursive_ty . contains ( ty) || self . max_depth == 0 {
70+ fn visit_ty ( & mut self , mut ty : Ty < ' db > ) -> ControlFlow < VisiblyUninhabited > {
71+ if self . recursive_ty . contains ( & ty) || self . max_depth == 0 {
7872 // rustc considers recursive types always inhabited. I think it is valid to consider
7973 // recursive types as always uninhabited, but we should do what rustc is doing.
8074 return CONTINUE_OPAQUELY_INHABITED ;
8175 }
82- self . recursive_ty . insert ( ty. clone ( ) ) ;
76+ self . recursive_ty . insert ( ty) ;
8377 self . max_depth -= 1 ;
84- let interner = DbInterner :: new_with ( self . db , None , None ) ;
85- let r = match ty. kind ( Interner ) {
86- TyKind :: Adt ( adt, subst) => self . visit_adt ( adt. 0 , subst) ,
87- TyKind :: Never => BREAK_VISIBLY_UNINHABITED ,
88- TyKind :: Tuple ( ..) => ty. super_visit_with ( self , outer_binder) ,
89- TyKind :: Array ( item_ty, len) => {
90- match try_const_usize ( self . db , len. to_nextsolver ( interner) ) {
91- Some ( 0 ) | None => CONTINUE_OPAQUELY_INHABITED ,
92- Some ( 1 ..) => item_ty. super_visit_with ( self , outer_binder) ,
93- }
94- }
95- TyKind :: Alias ( AliasTy :: Projection ( projection) ) => {
96- // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle
97- // `TyKind::AssociatedType`, but perhaps in the future it will.
98- let normalized = self . db . normalize_projection ( projection. clone ( ) , self . env . clone ( ) ) ;
99- self . visit_ty ( & normalized, outer_binder)
78+
79+ if matches ! ( ty. kind( ) , TyKind :: Alias ( ..) ) {
80+ let mut ocx = ObligationCtxt :: new ( self . infcx ) ;
81+ match ocx. structurally_normalize_ty ( & ObligationCause :: dummy ( ) , self . env . env , ty) {
82+ Ok ( it) => ty = it,
83+ Err ( _) => return CONTINUE_OPAQUELY_INHABITED ,
10084 }
85+ }
86+
87+ let r = match ty. kind ( ) {
88+ TyKind :: Adt ( adt, subst) => self . visit_adt ( adt. def_id ( ) . 0 , subst) ,
89+ TyKind :: Never => BREAK_VISIBLY_UNINHABITED ,
90+ TyKind :: Tuple ( ..) => ty. super_visit_with ( self ) ,
91+ TyKind :: Array ( item_ty, len) => match try_const_usize ( self . infcx . interner . db , len) {
92+ Some ( 0 ) | None => CONTINUE_OPAQUELY_INHABITED ,
93+ Some ( 1 ..) => item_ty. super_visit_with ( self ) ,
94+ } ,
10195 _ => CONTINUE_OPAQUELY_INHABITED ,
10296 } ;
103- self . recursive_ty . remove ( ty) ;
97+ self . recursive_ty . remove ( & ty) ;
10498 self . max_depth += 1 ;
10599 r
106100 }
101+ }
107102
108- fn interner ( & self ) -> Interner {
109- Interner
103+ impl < ' a , ' db > UninhabitedFrom < ' a , ' db > {
104+ fn new (
105+ infcx : & ' a InferCtxt < ' db > ,
106+ target_mod : ModuleId ,
107+ env : Arc < TraitEnvironment < ' db > > ,
108+ ) -> Self {
109+ Self { target_mod, recursive_ty : FxHashSet :: default ( ) , max_depth : 500 , infcx, env }
110+ }
111+
112+ #[ inline]
113+ fn interner ( & self ) -> DbInterner < ' db > {
114+ self . infcx . interner
115+ }
116+
117+ #[ inline]
118+ fn db ( & self ) -> & ' db dyn HirDatabase {
119+ self . interner ( ) . db
110120 }
111- }
112121
113- impl UninhabitedFrom < ' _ > {
114- fn visit_adt ( & mut self , adt : AdtId , subst : & Substitution ) -> ControlFlow < VisiblyUninhabited > {
122+ fn visit_adt (
123+ & mut self ,
124+ adt : AdtId ,
125+ subst : GenericArgs < ' db > ,
126+ ) -> ControlFlow < VisiblyUninhabited > {
115127 // An ADT is uninhabited iff all its variants uninhabited.
116128 match adt {
117129 // rustc: For now, `union`s are never considered uninhabited.
118130 AdtId :: UnionId ( _) => CONTINUE_OPAQUELY_INHABITED ,
119131 AdtId :: StructId ( s) => self . visit_variant ( s. into ( ) , subst) ,
120132 AdtId :: EnumId ( e) => {
121- let enum_data = e. enum_variants ( self . db ) ;
133+ let enum_data = e. enum_variants ( self . db ( ) ) ;
122134
123135 for & ( variant, _, _) in enum_data. variants . iter ( ) {
124136 let variant_inhabitedness = self . visit_variant ( variant. into ( ) , subst) ;
@@ -135,17 +147,17 @@ impl UninhabitedFrom<'_> {
135147 fn visit_variant (
136148 & mut self ,
137149 variant : VariantId ,
138- subst : & Substitution ,
150+ subst : GenericArgs < ' db > ,
139151 ) -> ControlFlow < VisiblyUninhabited > {
140- let variant_data = variant. fields ( self . db ) ;
152+ let variant_data = variant. fields ( self . db ( ) ) ;
141153 let fields = variant_data. fields ( ) ;
142154 if fields. is_empty ( ) {
143155 return CONTINUE_OPAQUELY_INHABITED ;
144156 }
145157
146158 let is_enum = matches ! ( variant, VariantId :: EnumVariantId ( ..) ) ;
147- let field_tys = self . db . field_types ( variant) ;
148- let field_vis = if is_enum { None } else { Some ( self . db . field_visibilities ( variant) ) } ;
159+ let field_tys = self . db ( ) . field_types_ns ( variant) ;
160+ let field_vis = if is_enum { None } else { Some ( self . db ( ) . field_visibilities ( variant) ) } ;
149161
150162 for ( fid, _) in fields. iter ( ) {
151163 self . visit_field ( field_vis. as_ref ( ) . map ( |it| it[ fid] ) , & field_tys[ fid] , subst) ?;
@@ -156,12 +168,12 @@ impl UninhabitedFrom<'_> {
156168 fn visit_field (
157169 & mut self ,
158170 vis : Option < Visibility > ,
159- ty : & Binders < Ty > ,
160- subst : & Substitution ,
171+ ty : & EarlyBinder < ' db , Ty < ' db > > ,
172+ subst : GenericArgs < ' db > ,
161173 ) -> ControlFlow < VisiblyUninhabited > {
162- if vis. is_none_or ( |it| it. is_visible_from ( self . db , self . target_mod ) ) {
163- let ty = ty. clone ( ) . substitute ( Interner , subst) ;
164- ty. visit_with ( self , DebruijnIndex :: INNERMOST )
174+ if vis. is_none_or ( |it| it. is_visible_from ( self . db ( ) , self . target_mod ) ) {
175+ let ty = ty. instantiate ( self . interner ( ) , subst) ;
176+ ty. visit_with ( self )
165177 } else {
166178 CONTINUE_OPAQUELY_INHABITED
167179 }
0 commit comments