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
50
let value = generalizer. relate ( term, term) ?;
47
51
let needs_wf = generalizer. needs_wf ;
48
- Ok ( Generalization { value, needs_wf } )
52
+ Ok ( Generalization { value : HandleProjection ( value ) , 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,12 @@ 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. 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`.
160
+ in_alias : bool ,
161
+
142
162
/// See the field `needs_wf` in `Generalization`.
143
163
needs_wf : bool ,
144
164
}
@@ -309,6 +329,38 @@ where
309
329
}
310
330
}
311
331
332
+ ty:: Alias ( kind, data) => {
333
+ let is_nested_alias = mem:: replace ( & mut self . in_alias , true ) ;
334
+ let result = match self . relate ( data, data) {
335
+ Ok ( data) => Ok ( Ty :: new_alias ( self . tcx ( ) , kind, data) ) ,
336
+ Err ( e) => {
337
+ if is_nested_alias {
338
+ return Err ( e) ;
339
+ } else {
340
+ let mut visitor = MaxUniverse :: new ( ) ;
341
+ t. visit_with ( & mut visitor) ;
342
+ let infer_replacement_is_complete =
343
+ self . for_universe . can_name ( visitor. max_universe ( ) )
344
+ && !t. has_escaping_bound_vars ( ) ;
345
+ if !infer_replacement_is_complete {
346
+ warn ! ( "incomplete generalization of an alias type: {t:?}" ) ;
347
+ }
348
+
349
+ debug ! ( "generalization failure in alias" ) ;
350
+ Ok ( self . infcx . next_ty_var_in_universe (
351
+ TypeVariableOrigin {
352
+ kind : TypeVariableOriginKind :: MiscVariable ,
353
+ span : self . delegate . span ( ) ,
354
+ } ,
355
+ self . for_universe ,
356
+ ) )
357
+ }
358
+ }
359
+ } ;
360
+ self . in_alias = is_nested_alias;
361
+ result
362
+ }
363
+
312
364
_ => relate:: structurally_relate_tys ( self , t, t) ,
313
365
} ?;
314
366
@@ -452,12 +504,20 @@ where
452
504
}
453
505
}
454
506
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
+
455
515
/// Result from a generalization operation. This includes
456
516
/// not only the generalized type, but also a bool flag
457
517
/// indicating whether further WF checks are needed.
458
518
#[ derive( Debug ) ]
459
- pub struct Generalization < T > {
460
- pub value : T ,
519
+ pub ( super ) struct Generalization < T > {
520
+ pub ( super ) value : HandleProjection < T > ,
461
521
462
522
/// If true, then the generalized type may not be well-formed,
463
523
/// even if the source type is well-formed, so we should add an
@@ -484,5 +544,5 @@ pub struct Generalization<T> {
484
544
/// will force the calling code to check that `WF(Foo<?C, ?D>)`
485
545
/// holds, which in turn implies that `?C::Item == ?D`. So once
486
546
/// `?C` is constrained, that should suffice to restrict `?D`.
487
- pub needs_wf : bool ,
547
+ pub ( super ) needs_wf : bool ,
488
548
}
0 commit comments