1
+ use std:: mem;
2
+
1
3
use rustc_data_structures:: sso:: SsoHashMap ;
2
4
use rustc_hir:: def_id:: DefId ;
3
5
use rustc_middle:: infer:: unify_key:: { ConstVarValue , ConstVariableValue } ;
4
6
use rustc_middle:: ty:: error:: TypeError ;
5
7
use 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 } ;
7
10
use rustc_span:: Span ;
8
11
9
12
use crate :: infer:: nll_relate:: TypeRelatingDelegate ;
10
- use crate :: infer:: type_variable:: TypeVariableValue ;
13
+ use crate :: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind , TypeVariableValue } ;
11
14
use crate :: infer:: { InferCtxt , RegionVariableOrigin } ;
12
15
13
16
/// 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>>
38
41
root_vid,
39
42
for_universe,
40
43
root_term : term. into ( ) ,
44
+ in_alias : false ,
41
45
needs_wf : false ,
42
46
cache : Default :: default ( ) ,
43
47
} ;
44
48
45
49
assert ! ( !term. has_escaping_bound_vars( ) ) ;
46
- let value = generalizer. relate ( term, term) ?;
50
+ let value_may_be_infer = generalizer. relate ( term, term) ?;
47
51
let needs_wf = generalizer. needs_wf ;
48
- Ok ( Generalization { value , needs_wf } )
52
+ Ok ( Generalization { value_may_be_infer , needs_wf } )
49
53
}
50
54
51
55
/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
52
56
/// in the generalizer code.
53
- pub trait GeneralizerDelegate < ' tcx > {
57
+ pub ( super ) trait GeneralizerDelegate < ' tcx > {
54
58
fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > ;
55
59
56
60
fn forbid_inference_vars ( ) -> bool ;
57
61
62
+ fn span ( & self ) -> Span ;
63
+
58
64
fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > ;
59
65
}
60
66
61
- pub struct CombineDelegate < ' cx , ' tcx > {
67
+ pub ( super ) struct CombineDelegate < ' cx , ' tcx > {
62
68
pub infcx : & ' cx InferCtxt < ' tcx > ,
63
69
pub param_env : ty:: ParamEnv < ' tcx > ,
64
70
pub span : Span ,
@@ -73,6 +79,10 @@ impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
73
79
false
74
80
}
75
81
82
+ fn span ( & self ) -> Span {
83
+ self . span
84
+ }
85
+
76
86
fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > {
77
87
// FIXME: This is non-ideal because we don't give a
78
88
// very descriptive origin for this region variable.
@@ -93,6 +103,10 @@ where
93
103
<Self as TypeRelatingDelegate < ' tcx > >:: forbid_inference_vars ( )
94
104
}
95
105
106
+ fn span ( & self ) -> Span {
107
+ <Self as TypeRelatingDelegate < ' tcx > >:: span ( & self )
108
+ }
109
+
96
110
fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > {
97
111
<Self as TypeRelatingDelegate < ' tcx > >:: generalize_existential ( self , universe)
98
112
}
@@ -139,6 +153,13 @@ struct Generalizer<'me, 'tcx, D> {
139
153
140
154
cache : SsoHashMap < Ty < ' tcx > , Ty < ' tcx > > ,
141
155
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
+
142
163
/// See the field `needs_wf` in `Generalization`.
143
164
needs_wf : bool ,
144
165
}
@@ -193,7 +214,7 @@ where
193
214
opt_variances,
194
215
a_subst,
195
216
b_subst,
196
- true ,
217
+ false ,
197
218
)
198
219
}
199
220
}
@@ -309,6 +330,44 @@ where
309
330
}
310
331
}
311
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.
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
+
312
371
_ => relate:: structurally_relate_tys ( self , t, t) ,
313
372
} ?;
314
373
@@ -456,8 +515,16 @@ where
456
515
/// not only the generalized type, but also a bool flag
457
516
/// indicating whether further WF checks are needed.
458
517
#[ 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 ,
461
528
462
529
/// If true, then the generalized type may not be well-formed,
463
530
/// even if the source type is well-formed, so we should add an
@@ -484,5 +551,5 @@ pub struct Generalization<T> {
484
551
/// will force the calling code to check that `WF(Foo<?C, ?D>)`
485
552
/// holds, which in turn implies that `?C::Item == ?D`. So once
486
553
/// `?C` is constrained, that should suffice to restrict `?D`.
487
- pub needs_wf : bool ,
554
+ pub ( super ) needs_wf : bool ,
488
555
}
0 commit comments