@@ -27,6 +27,7 @@ use rustc_hir::def::DefKind;
2727use rustc_hir:: def_id:: DefId ;
2828use rustc_hir:: lang_items:: LangItem ;
2929use rustc_infer:: infer:: resolve:: OpportunisticRegionResolver ;
30+ use rustc_middle:: ty:: fold:: MaxUniverse ;
3031use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder } ;
3132use rustc_middle:: ty:: subst:: Subst ;
3233use rustc_middle:: ty:: { self , Term , ToPredicate , Ty , TyCtxt } ;
@@ -143,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
143144 }
144145}
145146
147+ /// Takes the place of a
148+ /// Result<
149+ /// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
150+ /// MismatchedProjectionTypes<'tcx>,
151+ /// >
152+ pub ( super ) enum ProjectAndUnifyResult < ' tcx > {
153+ Holds ( Vec < PredicateObligation < ' tcx > > ) ,
154+ FailedNormalization ,
155+ Recursive ,
156+ MismatchedProjectionTypes ( MismatchedProjectionTypes < ' tcx > ) ,
157+ }
158+
146159/// Evaluates constraints of the form:
147160///
148161/// for<...> <T as Trait>::U == V
@@ -166,19 +179,39 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
166179pub ( super ) fn poly_project_and_unify_type < ' cx , ' tcx > (
167180 selcx : & mut SelectionContext < ' cx , ' tcx > ,
168181 obligation : & PolyProjectionObligation < ' tcx > ,
169- ) -> Result <
170- Result < Option < Vec < PredicateObligation < ' tcx > > > , InProgress > ,
171- MismatchedProjectionTypes < ' tcx > ,
172- > {
182+ ) -> ProjectAndUnifyResult < ' tcx > {
173183 let infcx = selcx. infcx ( ) ;
174- infcx. commit_if_ok ( |_snapshot| {
184+ let r = infcx. commit_if_ok ( |_snapshot| {
185+ let old_universe = infcx. universe ( ) ;
175186 let placeholder_predicate =
176187 infcx. replace_bound_vars_with_placeholders ( obligation. predicate ) ;
188+ let new_universe = infcx. universe ( ) ;
177189
178190 let placeholder_obligation = obligation. with ( placeholder_predicate) ;
179- let result = project_and_unify_type ( selcx, & placeholder_obligation) ?;
180- Ok ( result)
181- } )
191+ match project_and_unify_type ( selcx, & placeholder_obligation) {
192+ ProjectAndUnifyResult :: MismatchedProjectionTypes ( e) => Err ( e) ,
193+ ProjectAndUnifyResult :: Holds ( obligations)
194+ if old_universe != new_universe
195+ && selcx. tcx ( ) . features ( ) . generic_associated_types_extended =>
196+ {
197+ let new_obligations = obligations
198+ . into_iter ( )
199+ . filter ( |obligation| {
200+ let mut visitor = MaxUniverse :: new ( ) ;
201+ obligation. predicate . visit_with ( & mut visitor) ;
202+ visitor. max_universe ( ) < new_universe
203+ } )
204+ . collect ( ) ;
205+ Ok ( ProjectAndUnifyResult :: Holds ( new_obligations) )
206+ }
207+ other => Ok ( other) ,
208+ }
209+ } ) ;
210+
211+ match r {
212+ Ok ( inner) => inner,
213+ Err ( err) => ProjectAndUnifyResult :: MismatchedProjectionTypes ( err) ,
214+ }
182215}
183216
184217/// Evaluates constraints of the form:
@@ -188,15 +221,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
188221/// If successful, this may result in additional obligations.
189222///
190223/// See [poly_project_and_unify_type] for an explanation of the return value.
224+ #[ tracing:: instrument( level = "debug" , skip( selcx) ) ]
191225fn project_and_unify_type < ' cx , ' tcx > (
192226 selcx : & mut SelectionContext < ' cx , ' tcx > ,
193227 obligation : & ProjectionObligation < ' tcx > ,
194- ) -> Result <
195- Result < Option < Vec < PredicateObligation < ' tcx > > > , InProgress > ,
196- MismatchedProjectionTypes < ' tcx > ,
197- > {
198- debug ! ( ?obligation, "project_and_unify_type" ) ;
199-
228+ ) -> ProjectAndUnifyResult < ' tcx > {
200229 let mut obligations = vec ! [ ] ;
201230
202231 let infcx = selcx. infcx ( ) ;
@@ -209,8 +238,8 @@ fn project_and_unify_type<'cx, 'tcx>(
209238 & mut obligations,
210239 ) {
211240 Ok ( Some ( n) ) => n,
212- Ok ( None ) => return Ok ( Ok ( None ) ) ,
213- Err ( InProgress ) => return Ok ( Err ( InProgress ) ) ,
241+ Ok ( None ) => return ProjectAndUnifyResult :: FailedNormalization ,
242+ Err ( InProgress ) => return ProjectAndUnifyResult :: Recursive ,
214243 } ;
215244 debug ! ( ?normalized, ?obligations, "project_and_unify_type result" ) ;
216245 match infcx
@@ -219,11 +248,11 @@ fn project_and_unify_type<'cx, 'tcx>(
219248 {
220249 Ok ( InferOk { obligations : inferred_obligations, value : ( ) } ) => {
221250 obligations. extend ( inferred_obligations) ;
222- Ok ( Ok ( Some ( obligations) ) )
251+ ProjectAndUnifyResult :: Holds ( obligations)
223252 }
224253 Err ( err) => {
225- debug ! ( "project_and_unify_type: equating types encountered error {:?}" , err) ;
226- Err ( MismatchedProjectionTypes { err } )
254+ debug ! ( "equating types encountered error {:?}" , err) ;
255+ ProjectAndUnifyResult :: MismatchedProjectionTypes ( MismatchedProjectionTypes { err } )
227256 }
228257 }
229258}
0 commit comments