@@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas
11
11
#[ cfg( feature = "nightly" ) ]
12
12
use rustc_macros:: { HashStable_NoContext , TyDecodable , TyEncodable } ;
13
13
14
+ use crate :: data_structures:: DelayedSet ;
14
15
use crate :: inherent:: * ;
15
16
use crate :: visit:: TypeVisitableExt as _;
16
17
use crate :: { self as ty, Interner } ;
@@ -181,41 +182,44 @@ impl<DefId> SimplifiedType<DefId> {
181
182
/// We also use this function during coherence. For coherence the
182
183
/// impls only have to overlap for some value, so we treat parameters
183
184
/// on both sides like inference variables.
184
- #[ derive( Debug , Clone , Copy ) ]
185
+ #[ derive( Debug ) ]
185
186
pub struct DeepRejectCtxt <
186
187
I : Interner ,
187
188
const INSTANTIATE_LHS_WITH_INFER : bool ,
188
189
const INSTANTIATE_RHS_WITH_INFER : bool ,
189
190
> {
190
191
_interner : PhantomData < I > ,
192
+ /// We use a cache here as exponentially large - but self-similar - types otherwise
193
+ /// cause hangs, e.g. when compiling itertools with the `-Znext-solver`.
194
+ cache : DelayedSet < ( I :: Ty , I :: Ty ) > ,
191
195
}
192
196
193
197
impl < I : Interner > DeepRejectCtxt < I , false , false > {
194
198
/// Treat parameters in both the lhs and the rhs as rigid.
195
199
pub fn relate_rigid_rigid ( _interner : I ) -> DeepRejectCtxt < I , false , false > {
196
- DeepRejectCtxt { _interner : PhantomData }
200
+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
197
201
}
198
202
}
199
203
200
204
impl < I : Interner > DeepRejectCtxt < I , true , true > {
201
205
/// Treat parameters in both the lhs and the rhs as infer vars.
202
206
pub fn relate_infer_infer ( _interner : I ) -> DeepRejectCtxt < I , true , true > {
203
- DeepRejectCtxt { _interner : PhantomData }
207
+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
204
208
}
205
209
}
206
210
207
211
impl < I : Interner > DeepRejectCtxt < I , false , true > {
208
212
/// Treat parameters in the lhs as rigid, and in rhs as infer vars.
209
213
pub fn relate_rigid_infer ( _interner : I ) -> DeepRejectCtxt < I , false , true > {
210
- DeepRejectCtxt { _interner : PhantomData }
214
+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
211
215
}
212
216
}
213
217
214
218
impl < I : Interner , const INSTANTIATE_LHS_WITH_INFER : bool , const INSTANTIATE_RHS_WITH_INFER : bool >
215
219
DeepRejectCtxt < I , INSTANTIATE_LHS_WITH_INFER , INSTANTIATE_RHS_WITH_INFER >
216
220
{
217
221
pub fn args_may_unify (
218
- self ,
222
+ & mut self ,
219
223
obligation_args : I :: GenericArgs ,
220
224
impl_args : I :: GenericArgs ,
221
225
) -> bool {
@@ -234,7 +238,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
234
238
} )
235
239
}
236
240
237
- pub fn types_may_unify ( self , lhs : I :: Ty , rhs : I :: Ty ) -> bool {
241
+ pub fn types_may_unify ( & mut self , lhs : I :: Ty , rhs : I :: Ty ) -> bool {
238
242
match rhs. kind ( ) {
239
243
// Start by checking whether the `rhs` type may unify with
240
244
// pretty much everything. Just return `true` in that case.
@@ -273,8 +277,12 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
273
277
| ty:: Placeholder ( _) => { }
274
278
} ;
275
279
280
+ if self . cache . contains ( & ( lhs, rhs) ) {
281
+ return true ;
282
+ }
283
+
276
284
// For purely rigid types, use structural equivalence.
277
- match lhs. kind ( ) {
285
+ let result = match lhs. kind ( ) {
278
286
ty:: Ref ( _, lhs_ty, lhs_mutbl) => match rhs. kind ( ) {
279
287
ty:: Ref ( _, rhs_ty, rhs_mutbl) => {
280
288
lhs_mutbl == rhs_mutbl && self . types_may_unify ( lhs_ty, rhs_ty)
@@ -414,10 +422,16 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
414
422
}
415
423
416
424
ty:: Error ( ..) => true ,
425
+ } ;
426
+
427
+ if result {
428
+ self . cache . insert ( ( lhs, rhs) ) ;
417
429
}
430
+
431
+ result
418
432
}
419
433
420
- pub fn consts_may_unify ( self , lhs : I :: Const , rhs : I :: Const ) -> bool {
434
+ pub fn consts_may_unify ( & mut self , lhs : I :: Const , rhs : I :: Const ) -> bool {
421
435
match rhs. kind ( ) {
422
436
ty:: ConstKind :: Param ( _) => {
423
437
if INSTANTIATE_RHS_WITH_INFER {
@@ -465,7 +479,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
465
479
}
466
480
}
467
481
468
- fn var_and_ty_may_unify ( self , var : ty:: InferTy , ty : I :: Ty ) -> bool {
482
+ fn var_and_ty_may_unify ( & mut self , var : ty:: InferTy , ty : I :: Ty ) -> bool {
469
483
if !ty. is_known_rigid ( ) {
470
484
return true ;
471
485
}
0 commit comments