1+ use std:: mem;
2+
13use rustc_data_structures:: sso:: SsoHashMap ;
24use rustc_hir:: def_id:: DefId ;
35use rustc_middle:: infer:: unify_key:: { ConstVarValue , ConstVariableValue } ;
46use rustc_middle:: ty:: error:: TypeError ;
57use 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 } ;
710use rustc_span:: Span ;
811
912use crate :: infer:: nll_relate:: TypeRelatingDelegate ;
10- use crate :: infer:: type_variable:: TypeVariableValue ;
13+ use crate :: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind , TypeVariableValue } ;
1114use crate :: infer:: { InferCtxt , RegionVariableOrigin } ;
1215
1316/// 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>>
3841 root_vid,
3942 for_universe,
4043 root_term : term. into ( ) ,
44+ in_alias : false ,
4145 needs_wf : false ,
4246 cache : Default :: default ( ) ,
4347 } ;
4448
4549 assert ! ( !term. has_escaping_bound_vars( ) ) ;
4650 let value = generalizer. relate ( term, term) ?;
4751 let needs_wf = generalizer. needs_wf ;
48- Ok ( Generalization { value, needs_wf } )
52+ Ok ( Generalization { value : HandleProjection ( value ) , needs_wf } )
4953}
5054
5155/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
5256/// in the generalizer code.
53- pub trait GeneralizerDelegate < ' tcx > {
57+ pub ( super ) trait GeneralizerDelegate < ' tcx > {
5458 fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > ;
5559
5660 fn forbid_inference_vars ( ) -> bool ;
5761
62+ fn span ( & self ) -> Span ;
63+
5864 fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > ;
5965}
6066
61- pub struct CombineDelegate < ' cx , ' tcx > {
67+ pub ( super ) struct CombineDelegate < ' cx , ' tcx > {
6268 pub infcx : & ' cx InferCtxt < ' tcx > ,
6369 pub param_env : ty:: ParamEnv < ' tcx > ,
6470 pub span : Span ,
@@ -73,6 +79,10 @@ impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
7379 false
7480 }
7581
82+ fn span ( & self ) -> Span {
83+ self . span
84+ }
85+
7686 fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > {
7787 // FIXME: This is non-ideal because we don't give a
7888 // very descriptive origin for this region variable.
@@ -93,6 +103,10 @@ where
93103 <Self as TypeRelatingDelegate < ' tcx > >:: forbid_inference_vars ( )
94104 }
95105
106+ fn span ( & self ) -> Span {
107+ <Self as TypeRelatingDelegate < ' tcx > >:: span ( & self )
108+ }
109+
96110 fn generalize_region ( & mut self , universe : ty:: UniverseIndex ) -> ty:: Region < ' tcx > {
97111 <Self as TypeRelatingDelegate < ' tcx > >:: generalize_existential ( self , universe)
98112 }
@@ -139,6 +153,12 @@ struct Generalizer<'me, 'tcx, D> {
139153
140154 cache : SsoHashMap < Ty < ' tcx > , Ty < ' tcx > > ,
141155
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+
142162 /// See the field `needs_wf` in `Generalization`.
143163 needs_wf : bool ,
144164}
@@ -309,6 +329,38 @@ where
309329 }
310330 }
311331
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+
312364 _ => relate:: structurally_relate_tys ( self , t, t) ,
313365 } ?;
314366
@@ -452,12 +504,20 @@ where
452504 }
453505}
454506
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+
455515/// Result from a generalization operation. This includes
456516/// not only the generalized type, but also a bool flag
457517/// indicating whether further WF checks are needed.
458518#[ derive( Debug ) ]
459- pub struct Generalization < T > {
460- pub value : T ,
519+ pub ( super ) struct Generalization < T > {
520+ pub ( super ) value : HandleProjection < T > ,
461521
462522 /// If true, then the generalized type may not be well-formed,
463523 /// even if the source type is well-formed, so we should add an
@@ -484,5 +544,5 @@ pub struct Generalization<T> {
484544 /// will force the calling code to check that `WF(Foo<?C, ?D>)`
485545 /// holds, which in turn implies that `?C::Item == ?D`. So once
486546 /// `?C` is constrained, that should suffice to restrict `?D`.
487- pub needs_wf : bool ,
547+ pub ( super ) needs_wf : bool ,
488548}
0 commit comments