1+ use std:: mem;
2+
13use rustc_data_structures:: sso:: SsoHashMap ;
24use rustc_hir:: def_id:: DefId ;
35use rustc_middle:: infer:: unify_key:: { ConstVarValue , ConstVariableValue } ;
46use rustc_middle:: ty:: error:: TypeError ;
57use rustc_middle:: ty:: relate:: { self , Relate , RelateResult , TypeRelation } ;
6- use rustc_middle:: ty:: { self , InferConst , Term , Ty , TyCtxt , TypeVisitableExt } ;
8+ use rustc_middle:: ty:: visit:: MaxUniverse ;
9+ use rustc_middle:: ty:: { self , InferConst , Term , Ty , TyCtxt , TypeVisitable , TypeVisitableExt } ;
710use rustc_span:: Span ;
811
912use crate :: infer:: nll_relate:: TypeRelatingDelegate ;
10- use crate :: infer:: type_variable:: TypeVariableValue ;
13+ use crate :: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind , TypeVariableValue } ;
1114use crate :: infer:: { InferCtxt , RegionVariableOrigin } ;
1215
1316/// Attempts to generalize `term` for the type variable `for_vid`.
@@ -38,27 +41,30 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
3841 root_vid,
3942 for_universe,
4043 root_term : term. into ( ) ,
44+ in_alias : false ,
4145 needs_wf : false ,
4246 cache : Default :: default ( ) ,
4347 } ;
4448
4549 assert ! ( !term. has_escaping_bound_vars( ) ) ;
46- let value = generalizer. relate ( term, term) ?;
50+ let value_may_be_infer = generalizer. relate ( term, term) ?;
4751 let needs_wf = generalizer. needs_wf ;
48- Ok ( Generalization { value , needs_wf } )
52+ Ok ( Generalization { value_may_be_infer , needs_wf } )
4953}
5054
5155/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
5256/// in the generalizer code.
53- pub trait GeneralizerDelegate < ' tcx > {
57+ pub ( super ) trait GeneralizerDelegate < ' tcx > {
5458 fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > ;
5559
5660 fn forbid_inference_vars ( ) -> bool ;
5761
62+ fn span ( & self ) -> Span ;
63+
5864 fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > ;
5965}
6066
61- pub struct CombineDelegate < ' cx , ' tcx > {
67+ pub ( super ) struct CombineDelegate < ' cx , ' tcx > {
6268 pub infcx : & ' cx InferCtxt < ' tcx > ,
6369 pub param_env : ty:: ParamEnv < ' tcx > ,
6470 pub span : Span ,
@@ -73,6 +79,10 @@ impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
7379 false
7480 }
7581
82+ fn span ( & self ) -> Span {
83+ self . span
84+ }
85+
7686 fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > {
7787 // FIXME: This is non-ideal because we don't give a
7888 // very descriptive origin for this region variable.
@@ -93,6 +103,10 @@ where
93103 <Self as TypeRelatingDelegate < ' tcx > >:: forbid_inference_vars ( )
94104 }
95105
106+ fn span ( & self ) -> Span {
107+ <Self as TypeRelatingDelegate < ' tcx > >:: span ( & self )
108+ }
109+
96110 fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > {
97111 <Self as TypeRelatingDelegate < ' tcx > >:: generalize_existential ( self , universe)
98112 }
@@ -139,6 +153,13 @@ struct Generalizer<'me, 'tcx, D> {
139153
140154 cache : SsoHashMap < Ty < ' tcx > , Ty < ' tcx > > ,
141155
156+ /// This is set once we're generalizing the arguments of an alias.
157+ ///
158+ /// This is necessary to correctly handle
159+ /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
160+ /// hold by either normalizing the outer or the inner associated type.
161+ in_alias : bool ,
162+
142163 /// See the field `needs_wf` in `Generalization`.
143164 needs_wf : bool ,
144165}
@@ -193,7 +214,7 @@ where
193214 opt_variances,
194215 a_subst,
195216 b_subst,
196- true ,
217+ false ,
197218 )
198219 }
199220 }
@@ -309,6 +330,44 @@ where
309330 }
310331 }
311332
333+ ty:: Alias ( kind, data) => {
334+ // An occurs check failure inside of an alias does not mean
335+ // that the types definitely don't unify. We may be able
336+ // to normalize the alias after all.
337+ //
338+ // We handle this by lazily equating the alias and generalizing
339+ // it to an inference variable.
340+ let is_nested_alias = mem:: replace ( & mut self . in_alias , true ) ;
341+ let result = match self . relate ( data, data) {
342+ Ok ( data) => Ok ( Ty :: new_alias ( self . tcx ( ) , kind, data) ) ,
343+ Err ( e) => {
344+ if is_nested_alias {
345+ return Err ( e) ;
346+ } else {
347+ let mut visitor = MaxUniverse :: new ( ) ;
348+ t. visit_with ( & mut visitor) ;
349+ let infer_replacement_is_complete =
350+ self . for_universe . can_name ( visitor. max_universe ( ) )
351+ && !t. has_escaping_bound_vars ( ) ;
352+ if !infer_replacement_is_complete {
353+ warn ! ( "may incompletely handle alias type: {t:?}" ) ;
354+ }
355+
356+ debug ! ( "generalization failure in alias" ) ;
357+ Ok ( self . infcx . next_ty_var_in_universe (
358+ TypeVariableOrigin {
359+ kind : TypeVariableOriginKind :: MiscVariable ,
360+ span : self . delegate . span ( ) ,
361+ } ,
362+ self . for_universe ,
363+ ) )
364+ }
365+ }
366+ } ;
367+ self . in_alias = is_nested_alias;
368+ result
369+ }
370+
312371 _ => relate:: structurally_relate_tys ( self , t, t) ,
313372 } ?;
314373
@@ -456,8 +515,16 @@ where
456515/// not only the generalized type, but also a bool flag
457516/// indicating whether further WF checks are needed.
458517#[ derive( Debug ) ]
459- pub struct Generalization < T > {
460- pub value : T ,
518+ pub ( super ) struct Generalization < T > {
519+ /// When generalizing `<?0 as Trait>::Assoc` or
520+ /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc`
521+ /// for `?0` generalization returns an inference
522+ /// variable.
523+ ///
524+ /// This has to be handled wotj care as it can
525+ /// otherwise very easily result in infinite
526+ /// recursion.
527+ pub ( super ) value_may_be_infer : T ,
461528
462529 /// If true, then the generalized type may not be well-formed,
463530 /// even if the source type is well-formed, so we should add an
@@ -484,5 +551,5 @@ pub struct Generalization<T> {
484551 /// will force the calling code to check that `WF(Foo<?C, ?D>)`
485552 /// holds, which in turn implies that `?C::Item == ?D`. So once
486553 /// `?C` is constrained, that should suffice to restrict `?D`.
487- pub needs_wf : bool ,
554+ pub ( super ) needs_wf : bool ,
488555}
0 commit comments