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 } ;
@@ -62,53 +62,43 @@ mod def_id_forest;
62
62
// This code should only compile in modules where the uninhabitedness of Foo is
63
63
// visible.
64
64
65
- const ARBITRARY_RECURSION_LIMIT : u32 = 24 ;
66
-
67
65
impl < ' a , ' gcx , ' tcx > AdtDef {
68
66
/// Calculate the forest of DefIds from which this adt is visibly uninhabited.
69
67
pub fn uninhabited_from (
70
68
& self ,
71
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
72
- recursion_depth : u32 ,
69
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
73
70
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
74
71
substs : & ' tcx Substs < ' tcx > ) -> DefIdForest
75
72
{
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
+ } ) )
85
76
}
86
77
}
87
78
88
79
impl < ' a , ' gcx , ' tcx > VariantDef {
89
80
/// Calculate the forest of DefIds from which this variant is visibly uninhabited.
90
81
pub fn uninhabited_from (
91
82
& self ,
92
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
93
- recursion_depth : u32 ,
83
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
94
84
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
95
85
substs : & ' tcx Substs < ' tcx > ,
96
86
adt_kind : AdtKind ) -> DefIdForest
97
87
{
98
88
match adt_kind {
99
89
AdtKind :: Union => {
100
90
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 )
102
92
} ) )
103
93
} ,
104
94
AdtKind :: Struct => {
105
95
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 )
107
97
} ) )
108
98
} ,
109
99
AdtKind :: Enum => {
110
100
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 )
112
102
} ) )
113
103
} ,
114
104
}
@@ -119,14 +109,13 @@ impl<'a, 'gcx, 'tcx> FieldDef {
119
109
/// Calculate the forest of DefIds from which this field is visibly uninhabited.
120
110
pub fn uninhabited_from (
121
111
& self ,
122
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
123
- recursion_depth : u32 ,
112
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
124
113
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
125
114
substs : & ' tcx Substs < ' tcx > ,
126
115
is_enum : bool ) -> DefIdForest
127
116
{
128
117
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)
130
119
} ;
131
120
// FIXME(canndrew): Currently enum fields are (incorrectly) stored with
132
121
// Visibility::Invisible so we need to override self.vis if we're
@@ -151,15 +140,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
151
140
/// Calculate the forest of DefIds from which this type is visibly uninhabited.
152
141
pub fn uninhabited_from (
153
142
& self ,
154
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
155
- mut recursion_depth : u32 ,
143
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
156
144
tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
157
145
{
158
- recursion_depth += 1 ;
159
- if recursion_depth >= ARBITRARY_RECURSION_LIMIT {
160
- return DefIdForest :: empty ( ) ;
161
- }
162
-
163
146
match tcx. lift_to_global ( & self ) {
164
147
Some ( global_ty) => {
165
148
{
@@ -168,44 +151,68 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
168
151
return forest. clone ( ) ;
169
152
}
170
153
}
171
- let forest = global_ty. uninhabited_from_inner ( visited, recursion_depth , tcx) ;
154
+ let forest = global_ty. uninhabited_from_inner ( visited, tcx) ;
172
155
let mut cache = tcx. inhabitedness_cache . borrow_mut ( ) ;
173
156
cache. insert ( global_ty, forest. clone ( ) ) ;
174
157
forest
175
158
} ,
176
159
None => {
177
- let forest = self . uninhabited_from_inner ( visited, recursion_depth , tcx) ;
160
+ let forest = self . uninhabited_from_inner ( visited, tcx) ;
178
161
forest
179
162
} ,
180
163
}
181
164
}
182
165
183
166
fn uninhabited_from_inner (
184
167
& self ,
185
- visited : & mut FxHashSet < ( DefId , & ' tcx Substs < ' tcx > ) > ,
186
- recursion_depth : u32 ,
168
+ visited : & mut FxHashMap < DefId , FxHashSet < & ' tcx Substs < ' tcx > > > ,
187
169
tcx : TyCtxt < ' a , ' gcx , ' tcx > ) -> DefIdForest
188
170
{
189
171
match self . sty {
190
172
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
192
199
} ,
193
200
194
201
TyNever => DefIdForest :: full ( tcx) ,
195
202
TyTuple ( ref tys, _) => {
196
203
DefIdForest :: union ( tcx, tys. iter ( ) . map ( |ty| {
197
- ty. uninhabited_from ( visited, recursion_depth , tcx)
204
+ ty. uninhabited_from ( visited, tcx)
198
205
} ) )
199
206
} ,
200
207
TyArray ( ty, len) => {
201
208
if len == 0 {
202
209
DefIdForest :: empty ( )
203
210
} else {
204
- ty. uninhabited_from ( visited, recursion_depth , tcx)
211
+ ty. uninhabited_from ( visited, tcx)
205
212
}
206
213
}
207
214
TyRef ( _, ref tm) => {
208
- tm. ty . uninhabited_from ( visited, recursion_depth , tcx)
215
+ tm. ty . uninhabited_from ( visited, tcx)
209
216
}
210
217
211
218
_ => DefIdForest :: empty ( ) ,
0 commit comments