@@ -13,11 +13,14 @@ use rustc_middle::traits::solve::{
1313 inspect, CanonicalInput , CanonicalResponse , Certainty , PredefinedOpaquesData , QueryResult ,
1414} ;
1515use rustc_middle:: traits:: specialization_graph;
16+ use rustc_middle:: ty:: AliasRelationDirection ;
17+ use rustc_middle:: ty:: TypeFolder ;
1618use rustc_middle:: ty:: {
1719 self , InferCtxtLike , OpaqueTypeKey , Ty , TyCtxt , TypeFoldable , TypeSuperVisitable ,
1820 TypeVisitable , TypeVisitableExt , TypeVisitor ,
1921} ;
2022use rustc_span:: DUMMY_SP ;
23+ use rustc_type_ir:: fold:: TypeSuperFoldable ;
2124use rustc_type_ir:: { self as ir, CanonicalVarValues , Interner } ;
2225use rustc_type_ir_macros:: { Lift_Generic , TypeFoldable_Generic , TypeVisitable_Generic } ;
2326use std:: ops:: ControlFlow ;
@@ -455,13 +458,23 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
455458 }
456459
457460 #[ instrument( level = "trace" , skip( self ) ) ]
458- pub ( super ) fn add_normalizes_to_goal ( & mut self , goal : Goal < ' tcx , ty:: NormalizesTo < ' tcx > > ) {
461+ pub ( super ) fn add_normalizes_to_goal ( & mut self , mut goal : Goal < ' tcx , ty:: NormalizesTo < ' tcx > > ) {
462+ goal. predicate = goal
463+ . predicate
464+ . fold_with ( & mut ReplaceAliasWithInfer { ecx : self , param_env : goal. param_env } ) ;
459465 self . inspect . add_normalizes_to_goal ( self . infcx , self . max_input_universe , goal) ;
460466 self . nested_goals . normalizes_to_goals . push ( goal) ;
461467 }
462468
463469 #[ instrument( level = "debug" , skip( self ) ) ]
464- pub ( super ) fn add_goal ( & mut self , source : GoalSource , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) {
470+ pub ( super ) fn add_goal (
471+ & mut self ,
472+ source : GoalSource ,
473+ mut goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ,
474+ ) {
475+ goal. predicate = goal
476+ . predicate
477+ . fold_with ( & mut ReplaceAliasWithInfer { ecx : self , param_env : goal. param_env } ) ;
465478 self . inspect . add_goal ( self . infcx , self . max_input_universe , source, goal) ;
466479 self . nested_goals . goals . push ( ( source, goal) ) ;
467480 }
@@ -1084,3 +1097,63 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
10841097 } ) ;
10851098 }
10861099}
1100+
1101+ /// Eagerly replace aliases with inference variables, emitting `AliasRelate`
1102+ /// goals, used when adding goals to the `EvalCtxt`. We compute the
1103+ /// `AliasRelate` goals before evaluating the actual goal to get all the
1104+ /// constraints we can.
1105+ ///
1106+ /// This is a performance optimization to more eagerly detect cycles during trait
1107+ /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
1108+ struct ReplaceAliasWithInfer < ' me , ' a , ' tcx > {
1109+ ecx : & ' me mut EvalCtxt < ' a , InferCtxt < ' tcx > > ,
1110+ param_env : ty:: ParamEnv < ' tcx > ,
1111+ }
1112+
1113+ impl < ' tcx > TypeFolder < TyCtxt < ' tcx > > for ReplaceAliasWithInfer < ' _ , ' _ , ' tcx > {
1114+ fn interner ( & self ) -> TyCtxt < ' tcx > {
1115+ self . ecx . tcx ( )
1116+ }
1117+
1118+ fn fold_ty ( & mut self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
1119+ match * ty. kind ( ) {
1120+ ty:: Alias ( ..) if !ty. has_escaping_bound_vars ( ) => {
1121+ let infer_ty = self . ecx . next_ty_infer ( ) ;
1122+ let normalizes_to = ty:: PredicateKind :: AliasRelate (
1123+ ty. into ( ) ,
1124+ infer_ty. into ( ) ,
1125+ AliasRelationDirection :: Equate ,
1126+ ) ;
1127+ self . ecx . add_goal (
1128+ GoalSource :: Misc ,
1129+ Goal :: new ( self . interner ( ) , self . param_env , normalizes_to) ,
1130+ ) ;
1131+ infer_ty
1132+ }
1133+ _ => ty. super_fold_with ( self ) ,
1134+ }
1135+ }
1136+
1137+ fn fold_const ( & mut self , ct : ty:: Const < ' tcx > ) -> ty:: Const < ' tcx > {
1138+ match ct. kind ( ) {
1139+ ty:: ConstKind :: Unevaluated ( ..) if !ct. has_escaping_bound_vars ( ) => {
1140+ let infer_ct = self . ecx . next_const_infer ( ct. ty ( ) ) ;
1141+ let normalizes_to = ty:: PredicateKind :: AliasRelate (
1142+ ct. into ( ) ,
1143+ infer_ct. into ( ) ,
1144+ AliasRelationDirection :: Equate ,
1145+ ) ;
1146+ self . ecx . add_goal (
1147+ GoalSource :: Misc ,
1148+ Goal :: new ( self . interner ( ) , self . param_env , normalizes_to) ,
1149+ ) ;
1150+ infer_ct
1151+ }
1152+ _ => ct. super_fold_with ( self ) ,
1153+ }
1154+ }
1155+
1156+ fn fold_predicate ( & mut self , predicate : ty:: Predicate < ' tcx > ) -> ty:: Predicate < ' tcx > {
1157+ if predicate. allow_normalization ( ) { predicate. super_fold_with ( self ) } else { predicate }
1158+ }
1159+ }
0 commit comments