@@ -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,42 @@ 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
+ cache : DelayedSet < ( I :: Ty , I :: Ty ) > ,
191
193
}
192
194
193
195
impl < I : Interner > DeepRejectCtxt < I , false , false > {
194
196
/// Treat parameters in both the lhs and the rhs as rigid.
195
197
pub fn relate_rigid_rigid ( _interner : I ) -> DeepRejectCtxt < I , false , false > {
196
- DeepRejectCtxt { _interner : PhantomData }
198
+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
197
199
}
198
200
}
199
201
200
202
impl < I : Interner > DeepRejectCtxt < I , true , true > {
201
203
/// Treat parameters in both the lhs and the rhs as infer vars.
202
204
pub fn relate_infer_infer ( _interner : I ) -> DeepRejectCtxt < I , true , true > {
203
- DeepRejectCtxt { _interner : PhantomData }
205
+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
204
206
}
205
207
}
206
208
207
209
impl < I : Interner > DeepRejectCtxt < I , false , true > {
208
210
/// Treat parameters in the lhs as rigid, and in rhs as infer vars.
209
211
pub fn relate_rigid_infer ( _interner : I ) -> DeepRejectCtxt < I , false , true > {
210
- DeepRejectCtxt { _interner : PhantomData }
212
+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
211
213
}
212
214
}
213
215
214
216
impl < I : Interner , const INSTANTIATE_LHS_WITH_INFER : bool , const INSTANTIATE_RHS_WITH_INFER : bool >
215
217
DeepRejectCtxt < I , INSTANTIATE_LHS_WITH_INFER , INSTANTIATE_RHS_WITH_INFER >
216
218
{
217
219
pub fn args_may_unify (
218
- self ,
220
+ & mut self ,
219
221
obligation_args : I :: GenericArgs ,
220
222
impl_args : I :: GenericArgs ,
221
223
) -> bool {
@@ -234,7 +236,24 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
234
236
} )
235
237
}
236
238
237
- pub fn types_may_unify ( self , lhs : I :: Ty , rhs : I :: Ty ) -> bool {
239
+ /// We only cache types if they may be part of exponential blowup, i.e. recursing into
240
+ /// them may relate more than one types. Constants and regions bottom out, so we don't
241
+ /// need to worry about them.
242
+ ///
243
+ /// We use a cache here as exponentially large - but self-similar - types otherwise
244
+ /// cause hangs, e.g. when compiling itertools with the `-Znext-solver`.
245
+ fn relate_cached ( & mut self , lhs : I :: Ty , rhs : I :: Ty , f : impl FnOnce ( & mut Self ) -> bool ) -> bool {
246
+ if self . cache . contains ( & ( lhs, rhs) ) {
247
+ true
248
+ } else if f ( self ) {
249
+ self . cache . insert ( ( lhs, rhs) ) ;
250
+ true
251
+ } else {
252
+ false
253
+ }
254
+ }
255
+
256
+ pub fn types_may_unify ( & mut self , lhs : I :: Ty , rhs : I :: Ty ) -> bool {
238
257
match rhs. kind ( ) {
239
258
// Start by checking whether the `rhs` type may unify with
240
259
// pretty much everything. Just return `true` in that case.
@@ -283,8 +302,8 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
283
302
} ,
284
303
285
304
ty:: Adt ( lhs_def, lhs_args) => match rhs. kind ( ) {
286
- ty:: Adt ( rhs_def, rhs_args) => {
287
- lhs_def == rhs_def && self . args_may_unify ( lhs_args, rhs_args)
305
+ ty:: Adt ( rhs_def, rhs_args) if lhs_def == rhs_def => {
306
+ self . relate_cached ( lhs , rhs , |this| this . args_may_unify ( lhs_args, rhs_args) )
288
307
}
289
308
_ => false ,
290
309
} ,
@@ -322,12 +341,10 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
322
341
| ty:: Never
323
342
| ty:: Foreign ( _) => lhs == rhs,
324
343
325
- ty:: Tuple ( lhs) => match rhs. kind ( ) {
326
- ty:: Tuple ( rhs) => {
327
- lhs. len ( ) == rhs. len ( )
328
- && iter:: zip ( lhs. iter ( ) , rhs. iter ( ) )
329
- . all ( |( lhs, rhs) | self . types_may_unify ( lhs, rhs) )
330
- }
344
+ ty:: Tuple ( l) => match rhs. kind ( ) {
345
+ ty:: Tuple ( r) if l. len ( ) == r. len ( ) => self . relate_cached ( lhs, rhs, |this| {
346
+ iter:: zip ( l. iter ( ) , r. iter ( ) ) . all ( |( lhs, rhs) | this. types_may_unify ( lhs, rhs) )
347
+ } ) ,
331
348
_ => false ,
332
349
} ,
333
350
@@ -363,47 +380,51 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
363
380
let lhs_sig_tys = lhs_sig_tys. skip_binder ( ) . inputs_and_output ;
364
381
let rhs_sig_tys = rhs_sig_tys. skip_binder ( ) . inputs_and_output ;
365
382
366
- lhs_hdr == rhs_hdr
367
- && lhs_sig_tys. len ( ) == rhs_sig_tys. len ( )
368
- && iter:: zip ( lhs_sig_tys. iter ( ) , rhs_sig_tys. iter ( ) )
369
- . all ( |( lhs, rhs) | self . types_may_unify ( lhs, rhs) )
383
+ if lhs_hdr == rhs_hdr && lhs_sig_tys. len ( ) == rhs_sig_tys. len ( ) {
384
+ self . relate_cached ( lhs, rhs, |this| {
385
+ iter:: zip ( lhs_sig_tys. iter ( ) , rhs_sig_tys. iter ( ) )
386
+ . all ( |( lhs, rhs) | this. types_may_unify ( lhs, rhs) )
387
+ } )
388
+ } else {
389
+ false
390
+ }
370
391
}
371
392
_ => false ,
372
393
} ,
373
394
374
395
ty:: Bound ( ..) => true ,
375
396
376
397
ty:: FnDef ( lhs_def_id, lhs_args) => match rhs. kind ( ) {
377
- ty:: FnDef ( rhs_def_id, rhs_args) => {
378
- lhs_def_id == rhs_def_id && self . args_may_unify ( lhs_args, rhs_args)
398
+ ty:: FnDef ( rhs_def_id, rhs_args) if lhs_def_id == rhs_def_id => {
399
+ self . relate_cached ( lhs , rhs , |this| this . args_may_unify ( lhs_args, rhs_args) )
379
400
}
380
401
_ => false ,
381
402
} ,
382
403
383
404
ty:: Closure ( lhs_def_id, lhs_args) => match rhs. kind ( ) {
384
- ty:: Closure ( rhs_def_id, rhs_args) => {
385
- lhs_def_id == rhs_def_id && self . args_may_unify ( lhs_args, rhs_args)
405
+ ty:: Closure ( rhs_def_id, rhs_args) if lhs_def_id == rhs_def_id => {
406
+ self . relate_cached ( lhs , rhs , |this| this . args_may_unify ( lhs_args, rhs_args) )
386
407
}
387
408
_ => false ,
388
409
} ,
389
410
390
411
ty:: CoroutineClosure ( lhs_def_id, lhs_args) => match rhs. kind ( ) {
391
- ty:: CoroutineClosure ( rhs_def_id, rhs_args) => {
392
- lhs_def_id == rhs_def_id && self . args_may_unify ( lhs_args, rhs_args)
412
+ ty:: CoroutineClosure ( rhs_def_id, rhs_args) if lhs_def_id == rhs_def_id => {
413
+ self . relate_cached ( lhs , rhs , |this| this . args_may_unify ( lhs_args, rhs_args) )
393
414
}
394
415
_ => false ,
395
416
} ,
396
417
397
418
ty:: Coroutine ( lhs_def_id, lhs_args) => match rhs. kind ( ) {
398
- ty:: Coroutine ( rhs_def_id, rhs_args) => {
399
- lhs_def_id == rhs_def_id && self . args_may_unify ( lhs_args, rhs_args)
419
+ ty:: Coroutine ( rhs_def_id, rhs_args) if lhs_def_id == rhs_def_id => {
420
+ self . relate_cached ( lhs , rhs , |this| this . args_may_unify ( lhs_args, rhs_args) )
400
421
}
401
422
_ => false ,
402
423
} ,
403
424
404
425
ty:: CoroutineWitness ( lhs_def_id, lhs_args) => match rhs. kind ( ) {
405
- ty:: CoroutineWitness ( rhs_def_id, rhs_args) => {
406
- lhs_def_id == rhs_def_id && self . args_may_unify ( lhs_args, rhs_args)
426
+ ty:: CoroutineWitness ( rhs_def_id, rhs_args) if lhs_def_id == rhs_def_id => {
427
+ self . relate_cached ( lhs , rhs , |this| this . args_may_unify ( lhs_args, rhs_args) )
407
428
}
408
429
_ => false ,
409
430
} ,
@@ -417,7 +438,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
417
438
}
418
439
}
419
440
420
- pub fn consts_may_unify ( self , lhs : I :: Const , rhs : I :: Const ) -> bool {
441
+ pub fn consts_may_unify ( & mut self , lhs : I :: Const , rhs : I :: Const ) -> bool {
421
442
match rhs. kind ( ) {
422
443
ty:: ConstKind :: Param ( _) => {
423
444
if INSTANTIATE_RHS_WITH_INFER {
@@ -465,7 +486,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
465
486
}
466
487
}
467
488
468
- fn var_and_ty_may_unify ( self , var : ty:: InferTy , ty : I :: Ty ) -> bool {
489
+ fn var_and_ty_may_unify ( & mut self , var : ty:: InferTy , ty : I :: Ty ) -> bool {
469
490
if !ty. is_known_rigid ( ) {
470
491
return true ;
471
492
}
0 commit comments