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 } ;
@@ -66,27 +66,21 @@ impl<'a, 'gcx, 'tcx> AdtDef {
6666 /// Calculate the forest of DefIds from which this adt is visibly uninhabited.
6767 pub fn uninhabited_from (
6868 & self ,
69- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
69+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
7070 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
7171 substs : & ' tcx Substs < ' tcx > ) -> DefIdForest
7272 {
73- if !visited. insert ( ( self . did , substs) ) {
74- return DefIdForest :: empty ( ) ;
75- }
76-
77- let ret = DefIdForest :: intersection ( tcx, self . variants . iter ( ) . map ( |v| {
73+ DefIdForest :: intersection ( tcx, self . variants . iter ( ) . map ( |v| {
7874 v. uninhabited_from ( visited, tcx, substs, self . adt_kind ( ) )
79- } ) ) ;
80- visited. remove ( & ( self . did , substs) ) ;
81- ret
75+ } ) )
8276 }
8377}
8478
8579impl < ' a , ' gcx , ' tcx > VariantDef {
8680 /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
8781 pub fn uninhabited_from (
8882 & self ,
89- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
83+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
9084 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
9185 substs : & ' tcx Substs < ' tcx > ,
9286 adt_kind : AdtKind ) -> DefIdForest
@@ -115,12 +109,14 @@ impl<'a, 'gcx, 'tcx> FieldDef {
115109 /// Calculate the forest of DefIds from which this field is visibly uninhabited.
116110 pub fn uninhabited_from (
117111 & self ,
118- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
112+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
119113 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
120114 substs : & ' tcx Substs < ' tcx > ,
121115 is_enum : bool ) -> DefIdForest
122116 {
123- let mut data_uninhabitedness = move || self . ty ( tcx, substs) . uninhabited_from ( visited, tcx) ;
117+ let mut data_uninhabitedness = move || {
118+ self . ty ( tcx, substs) . uninhabited_from ( visited, tcx)
119+ } ;
124120 // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
125121 // Visibility::Invisible so we need to override self.vis if we're
126122 // dealing with an enum.
@@ -144,7 +140,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
144140 /// Calculate the forest of DefIds from which this type is visibly uninhabited.
145141 pub fn uninhabited_from (
146142 & self ,
147- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
143+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
148144 tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
149145 {
150146 match tcx. lift_to_global ( & self ) {
@@ -169,12 +165,37 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
169165
170166 fn uninhabited_from_inner (
171167 & self ,
172- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
168+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
173169 tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
174170 {
175171 match self . sty {
176172 TyAdt ( def, substs) => {
177- def. uninhabited_from ( visited, 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
178199 } ,
179200
180201 TyNever => DefIdForest :: full ( tcx) ,
0 commit comments