8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use util:: nodemap:: FxHashSet ;
11
+ use util:: nodemap:: { FxHashMap , FxHashSet } ;
12
12
use ty:: context:: TyCtxt ;
13
13
use ty:: { AdtDef , VariantDef , FieldDef , TyS } ;
14
14
use ty:: { DefId , Substs } ;
@@ -66,27 +66,21 @@ impl<'a, 'gcx, 'tcx> AdtDef {
66
66
/// Calculate the forest of DefIds from which this adt is visibly uninhabited.
67
67
pub fn uninhabited_from (
68
68
& self ,
69
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
69
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
70
70
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
71
71
substs : & ' tcx Substs < ' tcx > ) -> DefIdForest
72
72
{
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| {
78
74
v. uninhabited_from ( visited, tcx, substs, self . adt_kind ( ) )
79
- } ) ) ;
80
- visited. remove ( & ( self . did , substs) ) ;
81
- ret
75
+ } ) )
82
76
}
83
77
}
84
78
85
79
impl < ' a , ' gcx , ' tcx > VariantDef {
86
80
/// Calculate the forest of DefIds from which this variant is visibly uninhabited.
87
81
pub fn uninhabited_from (
88
82
& self ,
89
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
83
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
90
84
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
91
85
substs : & ' tcx Substs < ' tcx > ,
92
86
adt_kind : AdtKind ) -> DefIdForest
@@ -115,12 +109,14 @@ impl<'a, 'gcx, 'tcx> FieldDef {
115
109
/// Calculate the forest of DefIds from which this field is visibly uninhabited.
116
110
pub fn uninhabited_from (
117
111
& self ,
118
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
112
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
119
113
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
120
114
substs : & ' tcx Substs < ' tcx > ,
121
115
is_enum : bool ) -> DefIdForest
122
116
{
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
+ } ;
124
120
// FIXME(canndrew): Currently enum fields are (incorrectly) stored with
125
121
// Visibility::Invisible so we need to override self.vis if we're
126
122
// dealing with an enum.
@@ -144,7 +140,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
144
140
/// Calculate the forest of DefIds from which this type is visibly uninhabited.
145
141
pub fn uninhabited_from (
146
142
& self ,
147
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
143
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
148
144
tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
149
145
{
150
146
match tcx. lift_to_global ( & self ) {
@@ -169,12 +165,37 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
169
165
170
166
fn uninhabited_from_inner (
171
167
& self ,
172
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
168
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
173
169
tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
174
170
{
175
171
match self . sty {
176
172
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
178
199
} ,
179
200
180
201
TyNever => DefIdForest :: full ( tcx) ,
0 commit comments