@@ -47,9 +47,9 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
4747 } ;
4848
4949 assert ! ( !term. has_escaping_bound_vars( ) ) ;
50- let value = generalizer. relate ( term, term) ?;
50+ let value_may_be_infer = generalizer. relate ( term, term) ?;
5151 let needs_wf = generalizer. needs_wf ;
52- Ok ( Generalization { value : HandleProjection ( value ) , needs_wf } )
52+ Ok ( Generalization { value_may_be_infer , needs_wf } )
5353}
5454
5555/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
@@ -153,10 +153,11 @@ struct Generalizer<'me, 'tcx, D> {
153153
154154 cache : SsoHashMap < Ty < ' tcx > , Ty < ' tcx > > ,
155155
156- /// This is set once we're generalizing the arguments of an alias. In case
157- /// we encounter an occurs check failure we generalize the alias to an
158- /// inference variable instead of erroring. This is necessary to avoid
159- /// incorrect errors when relating `?0` with `<?0 as Trait>::Assoc`.
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.
160161 in_alias : bool ,
161162
162163 /// See the field `needs_wf` in `Generalization`.
@@ -330,6 +331,12 @@ where
330331 }
331332
332333 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.
333340 let is_nested_alias = mem:: replace ( & mut self . in_alias , true ) ;
334341 let result = match self . relate ( data, data) {
335342 Ok ( data) => Ok ( Ty :: new_alias ( self . tcx ( ) , kind, data) ) ,
@@ -343,7 +350,7 @@ where
343350 self . for_universe . can_name ( visitor. max_universe ( ) )
344351 && !t. has_escaping_bound_vars ( ) ;
345352 if !infer_replacement_is_complete {
346- warn ! ( "incomplete generalization of an alias type: {t:?}" ) ;
353+ warn ! ( "may incompletely handle alias type: {t:?}" ) ;
347354 }
348355
349356 debug ! ( "generalization failure in alias" ) ;
@@ -504,20 +511,20 @@ where
504511 }
505512}
506513
507- #[ derive( Debug ) ]
508- pub ( super ) struct HandleProjection < T > ( T ) ;
509- impl < T > HandleProjection < T > {
510- pub ( super ) fn may_be_infer ( self ) -> T {
511- self . 0
512- }
513- }
514-
515514/// Result from a generalization operation. This includes
516515/// not only the generalized type, but also a bool flag
517516/// indicating whether further WF checks are needed.
518517#[ derive( Debug ) ]
519518pub ( super ) struct Generalization < T > {
520- pub ( super ) value : HandleProjection < 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 ,
521528
522529 /// If true, then the generalized type may not be well-formed,
523530 /// even if the source type is well-formed, so we should add an
0 commit comments