@@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas
1111#[ cfg( feature = "nightly" ) ]
1212use rustc_macros:: { HashStable_NoContext , TyDecodable , TyEncodable } ;
1313
14+ use crate :: data_structures:: DelayedSet ;
1415use crate :: inherent:: * ;
1516use crate :: visit:: TypeVisitableExt as _;
1617use crate :: { self as ty, Interner } ;
@@ -181,41 +182,44 @@ impl<DefId> SimplifiedType<DefId> {
181182/// We also use this function during coherence. For coherence the
182183/// impls only have to overlap for some value, so we treat parameters
183184/// on both sides like inference variables.
184- #[ derive( Debug , Clone , Copy ) ]
185+ #[ derive( Debug ) ]
185186pub struct DeepRejectCtxt <
186187 I : Interner ,
187188 const INSTANTIATE_LHS_WITH_INFER : bool ,
188189 const INSTANTIATE_RHS_WITH_INFER : bool ,
189190> {
190191 _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 ) > ,
191195}
192196
193197impl < I : Interner > DeepRejectCtxt < I , false , false > {
194198 /// Treat parameters in both the lhs and the rhs as rigid.
195199 pub fn relate_rigid_rigid ( _interner : I ) -> DeepRejectCtxt < I , false , false > {
196- DeepRejectCtxt { _interner : PhantomData }
200+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
197201 }
198202}
199203
200204impl < I : Interner > DeepRejectCtxt < I , true , true > {
201205 /// Treat parameters in both the lhs and the rhs as infer vars.
202206 pub fn relate_infer_infer ( _interner : I ) -> DeepRejectCtxt < I , true , true > {
203- DeepRejectCtxt { _interner : PhantomData }
207+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
204208 }
205209}
206210
207211impl < I : Interner > DeepRejectCtxt < I , false , true > {
208212 /// Treat parameters in the lhs as rigid, and in rhs as infer vars.
209213 pub fn relate_rigid_infer ( _interner : I ) -> DeepRejectCtxt < I , false , true > {
210- DeepRejectCtxt { _interner : PhantomData }
214+ DeepRejectCtxt { _interner : PhantomData , cache : Default :: default ( ) }
211215 }
212216}
213217
214218impl < I : Interner , const INSTANTIATE_LHS_WITH_INFER : bool , const INSTANTIATE_RHS_WITH_INFER : bool >
215219 DeepRejectCtxt < I , INSTANTIATE_LHS_WITH_INFER , INSTANTIATE_RHS_WITH_INFER >
216220{
217221 pub fn args_may_unify (
218- self ,
222+ & mut self ,
219223 obligation_args : I :: GenericArgs ,
220224 impl_args : I :: GenericArgs ,
221225 ) -> bool {
@@ -234,7 +238,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
234238 } )
235239 }
236240
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 {
238242 match rhs. kind ( ) {
239243 // Start by checking whether the `rhs` type may unify with
240244 // 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_
273277 | ty:: Placeholder ( _) => { }
274278 } ;
275279
280+ if self . cache . contains ( & ( lhs, rhs) ) {
281+ return true ;
282+ }
283+
276284 // For purely rigid types, use structural equivalence.
277- match lhs. kind ( ) {
285+ let result = match lhs. kind ( ) {
278286 ty:: Ref ( _, lhs_ty, lhs_mutbl) => match rhs. kind ( ) {
279287 ty:: Ref ( _, rhs_ty, rhs_mutbl) => {
280288 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_
414422 }
415423
416424 ty:: Error ( ..) => true ,
425+ } ;
426+
427+ if result {
428+ self . cache . insert ( ( lhs, rhs) ) ;
417429 }
430+
431+ result
418432 }
419433
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 {
421435 match rhs. kind ( ) {
422436 ty:: ConstKind :: Param ( _) => {
423437 if INSTANTIATE_RHS_WITH_INFER {
@@ -465,7 +479,7 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
465479 }
466480 }
467481
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 {
469483 if !ty. is_known_rigid ( ) {
470484 return true ;
471485 }
0 commit comments