@@ -76,6 +76,7 @@ impl<'tcx> InferCtxt<'tcx> {
7676 target_vid,
7777 instantiation_variance,
7878 source_ty,
79+ & mut |alias| relation. try_eagerly_normalize_alias ( alias) ,
7980 ) ?;
8081
8182 // Constrain `b_vid` to the generalized type `generalized_ty`.
@@ -210,6 +211,7 @@ impl<'tcx> InferCtxt<'tcx> {
210211 target_vid,
211212 ty:: Invariant ,
212213 source_ct,
214+ & mut |alias| relation. try_eagerly_normalize_alias ( alias) ,
213215 ) ?;
214216
215217 debug_assert ! ( !generalized_ct. is_ct_infer( ) ) ;
@@ -249,6 +251,7 @@ impl<'tcx> InferCtxt<'tcx> {
249251 target_vid : impl Into < TermVid > ,
250252 ambient_variance : ty:: Variance ,
251253 source_term : T ,
254+ normalize : & mut dyn FnMut ( ty:: AliasTy < ' tcx > ) -> Ty < ' tcx > ,
252255 ) -> RelateResult < ' tcx , Generalization < T > > {
253256 assert ! ( !source_term. has_escaping_bound_vars( ) ) ;
254257 let ( for_universe, root_vid) = match target_vid. into ( ) {
@@ -264,15 +267,20 @@ impl<'tcx> InferCtxt<'tcx> {
264267 let mut generalizer = Generalizer {
265268 infcx : self ,
266269 span,
267- structurally_relate_aliases,
268270 root_vid,
269271 for_universe,
270272 root_term : source_term. into ( ) ,
271273 ambient_variance,
272- in_alias : false ,
274+ state : match structurally_relate_aliases {
275+ StructurallyRelateAliases :: No => GeneralizerState :: Default ,
276+ StructurallyRelateAliases :: Yes => GeneralizerState :: StructurallyRelateAliases ,
277+ } ,
273278 cache : Default :: default ( ) ,
279+ normalize,
274280 } ;
275281
282+ debug ! ( ?root_vid, ?generalizer. root_term, "generalize" ) ;
283+
276284 let value_may_be_infer = generalizer. relate ( source_term, source_term) ?;
277285 Ok ( Generalization { value_may_be_infer } )
278286 }
@@ -317,6 +325,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
317325 }
318326}
319327
328+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
329+ enum GeneralizerState {
330+ /// Treat aliases as potentially normalizable.
331+ Default ,
332+ IncompletelyRelateHigherRankedAlias ,
333+ /// Only one layer
334+ ShallowStructurallyRelateAliases ,
335+ StructurallyRelateAliases ,
336+ }
337+
320338/// The "generalizer" is used when handling inference variables.
321339///
322340/// The basic strategy for handling a constraint like `?A <: B` is to
@@ -335,10 +353,6 @@ struct Generalizer<'me, 'tcx> {
335353
336354 span : Span ,
337355
338- /// Whether aliases should be related structurally. If not, we have to
339- /// be careful when generalizing aliases.
340- structurally_relate_aliases : StructurallyRelateAliases ,
341-
342356 /// The vid of the type variable that is in the process of being
343357 /// instantiated. If we find this within the value we are folding,
344358 /// that means we would have created a cyclic value.
@@ -361,9 +375,13 @@ struct Generalizer<'me, 'tcx> {
361375 /// This is necessary to correctly handle
362376 /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
363377 /// hold by either normalizing the outer or the inner associated type.
364- in_alias : bool ,
378+ state : GeneralizerState ,
365379
366- cache : SsoHashMap < ( Ty < ' tcx > , ty:: Variance , bool ) , Ty < ' tcx > > ,
380+ cache : SsoHashMap < ( Ty < ' tcx > , ty:: Variance , GeneralizerState ) , Ty < ' tcx > > ,
381+
382+ /// Normalize an alias in the trait solver.
383+ /// If normalization fails, a fresh infer var is returned.
384+ normalize : & ' me mut dyn FnMut ( ty:: AliasTy < ' tcx > ) -> Ty < ' tcx > ,
367385}
368386
369387impl < ' tcx > Generalizer < ' _ , ' tcx > {
@@ -399,27 +417,51 @@ impl<'tcx> Generalizer<'_, 'tcx> {
399417 /// continue generalizing the alias. This ends up pulling down the universe of the
400418 /// inference variable and is incomplete in case the alias would normalize to a type
401419 /// which does not mention that inference variable.
402- fn generalize_alias_ty (
420+ fn handle_alias_ty (
403421 & mut self ,
422+ alias_ty : Ty < ' tcx > ,
404423 alias : ty:: AliasTy < ' tcx > ,
405424 ) -> Result < Ty < ' tcx > , TypeError < ' tcx > > {
406- // We do not eagerly replace aliases with inference variables if they have
407- // escaping bound vars, see the method comment for details. However, when we
408- // are inside of an alias with escaping bound vars replacing nested aliases
409- // with inference variables can cause incorrect ambiguity.
410- //
411- // cc trait-system-refactor-initiative#110
412- if self . infcx . next_trait_solver ( ) && !alias. has_escaping_bound_vars ( ) && !self . in_alias {
413- return Ok ( self . next_ty_var_for_alias ( ) ) ;
425+ match self . state {
426+ GeneralizerState :: ShallowStructurallyRelateAliases => {
427+ // We can switch back to default, we've treated one layer as rigid by doing this operation.
428+ self . state = GeneralizerState :: Default ;
429+ let res = relate:: structurally_relate_tys ( self , alias_ty, alias_ty) ;
430+ self . state = GeneralizerState :: ShallowStructurallyRelateAliases ;
431+ return res;
432+ }
433+ GeneralizerState :: StructurallyRelateAliases => {
434+ return relate:: structurally_relate_tys ( self , alias_ty, alias_ty) ;
435+ }
436+ GeneralizerState :: Default
437+ if self . infcx . next_trait_solver ( ) && !alias. has_escaping_bound_vars ( ) =>
438+ {
439+ // We do not eagerly replace aliases with inference variables if they have
440+ // escaping bound vars, see the method comment for details. However, when we
441+ // are inside of an alias with escaping bound vars replacing nested aliases
442+ // with inference variables can cause incorrect ambiguity.
443+ //
444+ // cc trait-system-refactor-initiative#110
445+ let normalized_alias = ( self . normalize ) ( alias) ;
446+
447+ self . state = GeneralizerState :: ShallowStructurallyRelateAliases ;
448+ // recursively generalize, trCeat the outer alias as rigid to avoid infinite recursion
449+ let res = self . relate ( normalized_alias, normalized_alias) ;
450+
451+ // only one way to get here
452+ self . state = GeneralizerState :: Default ;
453+
454+ return res;
455+ }
456+ GeneralizerState :: Default | GeneralizerState :: IncompletelyRelateHigherRankedAlias => { }
414457 }
415458
416- let is_nested_alias = mem:: replace ( & mut self . in_alias , true ) ;
459+ let previous_state =
460+ mem:: replace ( & mut self . state , GeneralizerState :: IncompletelyRelateHigherRankedAlias ) ;
417461 let result = match self . relate ( alias, alias) {
418462 Ok ( alias) => Ok ( alias. to_ty ( self . cx ( ) ) ) ,
419- Err ( e) => {
420- if is_nested_alias {
421- return Err ( e) ;
422- } else {
463+ Err ( e) => match previous_state {
464+ GeneralizerState :: Default => {
423465 let mut visitor = MaxUniverse :: new ( ) ;
424466 alias. visit_with ( & mut visitor) ;
425467 let infer_replacement_is_complete =
@@ -432,9 +474,14 @@ impl<'tcx> Generalizer<'_, 'tcx> {
432474 debug ! ( "generalization failure in alias" ) ;
433475 Ok ( self . next_ty_var_for_alias ( ) )
434476 }
435- }
477+ GeneralizerState :: IncompletelyRelateHigherRankedAlias => return Err ( e) ,
478+
479+ // Early return.
480+ GeneralizerState :: ShallowStructurallyRelateAliases
481+ | GeneralizerState :: StructurallyRelateAliases => unreachable ! ( ) ,
482+ } ,
436483 } ;
437- self . in_alias = is_nested_alias ;
484+ self . state = previous_state ;
438485 result
439486 }
440487}
@@ -488,7 +535,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
488535 fn tys ( & mut self , t : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
489536 assert_eq ! ( t, t2) ; // we are misusing TypeRelation here; both LHS and RHS ought to be ==
490537
491- if let Some ( & result) = self . cache . get ( & ( t, self . ambient_variance , self . in_alias ) ) {
538+ if let Some ( & result) = self . cache . get ( & ( t, self . ambient_variance , self . state ) ) {
492539 return Ok ( result) ;
493540 }
494541
@@ -553,9 +600,15 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
553600 // cc trait-system-refactor-initiative#108
554601 if self . infcx . next_trait_solver ( )
555602 && !matches ! ( self . infcx. typing_mode( ) , TypingMode :: Coherence )
556- && self . in_alias
557603 {
558- inner. type_variables ( ) . equate ( vid, new_var_id) ;
604+ match self . state {
605+ GeneralizerState :: IncompletelyRelateHigherRankedAlias => {
606+ inner. type_variables ( ) . equate ( vid, new_var_id) ;
607+ }
608+ GeneralizerState :: Default
609+ | GeneralizerState :: ShallowStructurallyRelateAliases
610+ | GeneralizerState :: StructurallyRelateAliases => { }
611+ }
559612 }
560613
561614 debug ! ( "replacing original vid={:?} with new={:?}" , vid, new_var_id) ;
@@ -584,15 +637,12 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
584637 }
585638 }
586639
587- ty:: Alias ( _, data) => match self . structurally_relate_aliases {
588- StructurallyRelateAliases :: No => self . generalize_alias_ty ( data) ,
589- StructurallyRelateAliases :: Yes => relate:: structurally_relate_tys ( self , t, t) ,
590- } ,
640+ ty:: Alias ( _, data) => self . handle_alias_ty ( t, data) ,
591641
592642 _ => relate:: structurally_relate_tys ( self , t, t) ,
593643 } ?;
594644
595- self . cache . insert ( ( t, self . ambient_variance , self . in_alias ) , g) ;
645+ self . cache . insert ( ( t, self . ambient_variance , self . state ) , g) ;
596646 Ok ( g)
597647 }
598648
@@ -683,9 +733,15 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
683733 // for more details.
684734 if self . infcx . next_trait_solver ( )
685735 && !matches ! ( self . infcx. typing_mode( ) , TypingMode :: Coherence )
686- && self . in_alias
687736 {
688- variable_table. union ( vid, new_var_id) ;
737+ match self . state {
738+ GeneralizerState :: IncompletelyRelateHigherRankedAlias => {
739+ variable_table. union ( vid, new_var_id) ;
740+ }
741+ GeneralizerState :: Default
742+ | GeneralizerState :: ShallowStructurallyRelateAliases
743+ | GeneralizerState :: StructurallyRelateAliases => { }
744+ }
689745 }
690746 Ok ( ty:: Const :: new_var ( self . cx ( ) , new_var_id) )
691747 }
0 commit comments