@@ -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" ) ;
@@ -500,20 +507,20 @@ where
500
507
}
501
508
}
502
509
503
- #[ derive( Debug ) ]
504
- pub ( super ) struct HandleProjection < T > ( T ) ;
505
- impl < T > HandleProjection < T > {
506
- pub ( super ) fn may_be_infer ( self ) -> T {
507
- self . 0
508
- }
509
- }
510
-
511
510
/// Result from a generalization operation. This includes
512
511
/// not only the generalized type, but also a bool flag
513
512
/// indicating whether further WF checks are needed.
514
513
#[ derive( Debug ) ]
515
514
pub ( super ) struct Generalization < T > {
516
- pub ( super ) value : HandleProjection < T > ,
515
+ /// When generalizing `<?0 as Trait>::Assoc` or
516
+ /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc`
517
+ /// for `?0` generalization returns an inference
518
+ /// variable.
519
+ ///
520
+ /// This has to be handled wotj care as it can
521
+ /// otherwise very easily result in infinite
522
+ /// recursion.
523
+ pub ( super ) value_may_be_infer : T ,
517
524
518
525
/// If true, then the generalized type may not be well-formed,
519
526
/// even if the source type is well-formed, so we should add an
0 commit comments