88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use util:: nodemap:: FxHashSet ;
11+ use util:: nodemap:: { FxHashMap , FxHashSet } ;
1212use ty:: context:: TyCtxt ;
1313use ty:: { AdtDef , VariantDef , FieldDef , TyS } ;
1414use ty:: { DefId , Substs } ;
@@ -62,53 +62,43 @@ mod def_id_forest;
6262// This code should only compile in modules where the uninhabitedness of Foo is
6363// visible.
6464
65- const ARBITRARY_RECURSION_LIMIT : u32 = 24 ;
66-
6765impl < ' a , ' gcx , ' tcx > AdtDef {
6866 /// Calculate the forest of DefIds from which this adt is visibly uninhabited.
6967 pub fn uninhabited_from (
7068 & self ,
71- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
72- recursion_depth : u32 ,
69+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
7370 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
7471 substs : & ' tcx Substs < ' tcx > ) -> DefIdForest
7572 {
76- if !visited. insert ( ( self . did , substs) ) {
77- return DefIdForest :: empty ( ) ;
78- }
79-
80- let ret = DefIdForest :: intersection ( tcx, self . variants . iter ( ) . map ( |v| {
81- v. uninhabited_from ( visited, recursion_depth, tcx, substs, self . adt_kind ( ) )
82- } ) ) ;
83- visited. remove ( & ( self . did , substs) ) ;
84- ret
73+ DefIdForest :: intersection ( tcx, self . variants . iter ( ) . map ( |v| {
74+ v. uninhabited_from ( visited, tcx, substs, self . adt_kind ( ) )
75+ } ) )
8576 }
8677}
8778
8879impl < ' a , ' gcx , ' tcx > VariantDef {
8980 /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
9081 pub fn uninhabited_from (
9182 & self ,
92- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
93- recursion_depth : u32 ,
83+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
9484 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
9585 substs : & ' tcx Substs < ' tcx > ,
9686 adt_kind : AdtKind ) -> DefIdForest
9787 {
9888 match adt_kind {
9989 AdtKind :: Union => {
10090 DefIdForest :: intersection ( tcx, self . fields . iter ( ) . map ( |f| {
101- f. uninhabited_from ( visited, recursion_depth , tcx, substs, false )
91+ f. uninhabited_from ( visited, tcx, substs, false )
10292 } ) )
10393 } ,
10494 AdtKind :: Struct => {
10595 DefIdForest :: union ( tcx, self . fields . iter ( ) . map ( |f| {
106- f. uninhabited_from ( visited, recursion_depth , tcx, substs, false )
96+ f. uninhabited_from ( visited, tcx, substs, false )
10797 } ) )
10898 } ,
10999 AdtKind :: Enum => {
110100 DefIdForest :: union ( tcx, self . fields . iter ( ) . map ( |f| {
111- f. uninhabited_from ( visited, recursion_depth , tcx, substs, true )
101+ f. uninhabited_from ( visited, tcx, substs, true )
112102 } ) )
113103 } ,
114104 }
@@ -119,14 +109,13 @@ impl<'a, 'gcx, 'tcx> FieldDef {
119109 /// Calculate the forest of DefIds from which this field is visibly uninhabited.
120110 pub fn uninhabited_from (
121111 & self ,
122- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
123- recursion_depth : u32 ,
112+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
124113 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
125114 substs : & ' tcx Substs < ' tcx > ,
126115 is_enum : bool ) -> DefIdForest
127116 {
128117 let mut data_uninhabitedness = move || {
129- self . ty ( tcx, substs) . uninhabited_from ( visited, recursion_depth , tcx)
118+ self . ty ( tcx, substs) . uninhabited_from ( visited, tcx)
130119 } ;
131120 // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
132121 // Visibility::Invisible so we need to override self.vis if we're
@@ -151,15 +140,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
151140 /// Calculate the forest of DefIds from which this type is visibly uninhabited.
152141 pub fn uninhabited_from (
153142 & self ,
154- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
155- mut recursion_depth : u32 ,
143+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
156144 tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
157145 {
158- recursion_depth += 1 ;
159- if recursion_depth >= ARBITRARY_RECURSION_LIMIT {
160- return DefIdForest :: empty ( ) ;
161- }
162-
163146 match tcx. lift_to_global ( & self ) {
164147 Some ( global_ty) => {
165148 {
@@ -168,44 +151,68 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
168151 return forest. clone ( ) ;
169152 }
170153 }
171- let forest = global_ty. uninhabited_from_inner ( visited, recursion_depth , tcx) ;
154+ let forest = global_ty. uninhabited_from_inner ( visited, tcx) ;
172155 let mut cache = tcx. inhabitedness_cache . borrow_mut ( ) ;
173156 cache. insert ( global_ty, forest. clone ( ) ) ;
174157 forest
175158 } ,
176159 None => {
177- let forest = self . uninhabited_from_inner ( visited, recursion_depth , tcx) ;
160+ let forest = self . uninhabited_from_inner ( visited, tcx) ;
178161 forest
179162 } ,
180163 }
181164 }
182165
183166 fn uninhabited_from_inner (
184167 & self ,
185- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
186- recursion_depth : u32 ,
168+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
187169 tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
188170 {
189171 match self . sty {
190172 TyAdt ( def, substs) => {
191- def. uninhabited_from ( visited, recursion_depth, tcx, substs)
173+ {
174+ let mut substs_set = visited. entry ( def. did ) . or_insert ( FxHashSet :: default ( ) ) ;
175+ if !substs_set. insert ( substs) {
176+ // We are already calculating the inhabitedness of this type.
177+ // The type must contain a reference to itself. Break the
178+ // infinite loop.
179+ return DefIdForest :: empty ( ) ;
180+ }
181+ if substs_set. len ( ) >= tcx. sess . recursion_limit . get ( ) / 4 {
182+ // We have gone very deep, reinstantiating this ADT inside
183+ // itself with different type arguments. We are probably
184+ // hitting an infinite loop. For example, it's possible to write:
185+ // a type Foo<T>
186+ // which contains a Foo<(T, T)>
187+ // which contains a Foo<((T, T), (T, T))>
188+ // which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))>
189+ // etc.
190+ let error = format ! ( "reached recursion limit while checking
191+ inhabitedness of `{}`" , self ) ;
192+ tcx. sess . fatal ( & error) ;
193+ }
194+ }
195+ let ret = def. uninhabited_from ( visited, tcx, substs) ;
196+ let mut substs_set = visited. get_mut ( & def. did ) . unwrap ( ) ;
197+ substs_set. remove ( substs) ;
198+ ret
192199 } ,
193200
194201 TyNever => DefIdForest :: full ( tcx) ,
195202 TyTuple ( ref tys, _) => {
196203 DefIdForest :: union ( tcx, tys. iter ( ) . map ( |ty| {
197- ty. uninhabited_from ( visited, recursion_depth , tcx)
204+ ty. uninhabited_from ( visited, tcx)
198205 } ) )
199206 } ,
200207 TyArray ( ty, len) => {
201208 if len == 0 {
202209 DefIdForest :: empty ( )
203210 } else {
204- ty. uninhabited_from ( visited, recursion_depth , tcx)
211+ ty. uninhabited_from ( visited, tcx)
205212 }
206213 }
207214 TyRef ( _, ref tm) => {
208- tm. ty . uninhabited_from ( visited, recursion_depth , tcx)
215+ tm. ty . uninhabited_from ( visited, tcx)
209216 }
210217
211218 _ => DefIdForest :: empty ( ) ,
0 commit comments