@@ -47,9 +47,9 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
47
47
} ;
48
48
49
49
assert ! ( !term. has_escaping_bound_vars( ) ) ;
50
- let value = generalizer. relate ( term, term) ?;
50
+ let value_may_be_infer = generalizer. relate ( term, term) ?;
51
51
let needs_wf = generalizer. needs_wf ;
52
- Ok ( Generalization { value : HandleProjection ( value ) , needs_wf } )
52
+ Ok ( Generalization { value_may_be_infer , needs_wf } )
53
53
}
54
54
55
55
/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
@@ -153,10 +153,11 @@ struct Generalizer<'me, 'tcx, D> {
153
153
154
154
cache : SsoHashMap < Ty < ' tcx > , Ty < ' tcx > > ,
155
155
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.
160
161
in_alias : bool ,
161
162
162
163
/// See the field `needs_wf` in `Generalization`.
@@ -330,6 +331,12 @@ where
330
331
}
331
332
332
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.
333
340
let is_nested_alias = mem:: replace ( & mut self . in_alias , true ) ;
334
341
let result = match self . relate ( data, data) {
335
342
Ok ( data) => Ok ( Ty :: new_alias ( self . tcx ( ) , kind, data) ) ,
@@ -343,7 +350,7 @@ where
343
350
self . for_universe . can_name ( visitor. max_universe ( ) )
344
351
&& !t. has_escaping_bound_vars ( ) ;
345
352
if !infer_replacement_is_complete {
346
- warn ! ( "incomplete generalization of an alias type: {t:?}" ) ;
353
+ warn ! ( "may incompletely handle alias type: {t:?}" ) ;
347
354
}
348
355
349
356
debug ! ( "generalization failure in alias" ) ;
@@ -504,20 +511,20 @@ where
504
511
}
505
512
}
506
513
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
-
515
514
/// Result from a generalization operation. This includes
516
515
/// not only the generalized type, but also a bool flag
517
516
/// indicating whether further WF checks are needed.
518
517
#[ derive( Debug ) ]
519
518
pub ( 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 ,
521
528
522
529
/// If true, then the generalized type may not be well-formed,
523
530
/// even if the source type is well-formed, so we should add an
0 commit comments