@@ -28,7 +28,7 @@ use rustc_hir::def_id::DefId;
2828use rustc_hir:: lang_items:: LangItem ;
2929use rustc_infer:: infer:: resolve:: OpportunisticRegionResolver ;
3030use rustc_middle:: traits:: select:: OverflowError ;
31- use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder } ;
31+ use rustc_middle:: ty:: fold:: { MaxUniverse , TypeFoldable , TypeFolder } ;
3232use rustc_middle:: ty:: subst:: Subst ;
3333use rustc_middle:: ty:: { self , Term , ToPredicate , Ty , TyCtxt } ;
3434use rustc_span:: symbol:: sym;
@@ -144,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
144144 }
145145}
146146
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+
147159/// Evaluates constraints of the form:
148160///
149161/// for<...> <T as Trait>::U == V
@@ -167,19 +179,47 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
167179pub ( super ) fn poly_project_and_unify_type < ' cx , ' tcx > (
168180 selcx : & mut SelectionContext < ' cx , ' tcx > ,
169181 obligation : & PolyProjectionObligation < ' tcx > ,
170- ) -> Result <
171- Result < Option < Vec < PredicateObligation < ' tcx > > > , InProgress > ,
172- MismatchedProjectionTypes < ' tcx > ,
173- > {
182+ ) -> ProjectAndUnifyResult < ' tcx > {
174183 let infcx = selcx. infcx ( ) ;
175- infcx. commit_if_ok ( |_snapshot| {
184+ let r = infcx. commit_if_ok ( |_snapshot| {
185+ let old_universe = infcx. universe ( ) ;
176186 let placeholder_predicate =
177187 infcx. replace_bound_vars_with_placeholders ( obligation. predicate ) ;
188+ let new_universe = infcx. universe ( ) ;
178189
179190 let placeholder_obligation = obligation. with ( placeholder_predicate) ;
180- let result = project_and_unify_type ( selcx, & placeholder_obligation) ?;
181- Ok ( result)
182- } )
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+ // If the `generic_associated_types_extended` feature is active, then we ignore any
198+ // obligations references lifetimes from any universe greater than or equal to the
199+ // universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`,
200+ // which isn't quite what we want. Ideally, we want either an implied
201+ // `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we
202+ // substitute concrete regions. There is design work to be done here; until then,
203+ // however, this allows experimenting potential GAT features without running into
204+ // well-formedness issues.
205+ let new_obligations = obligations
206+ . into_iter ( )
207+ . filter ( |obligation| {
208+ let mut visitor = MaxUniverse :: new ( ) ;
209+ obligation. predicate . visit_with ( & mut visitor) ;
210+ visitor. max_universe ( ) < new_universe
211+ } )
212+ . collect ( ) ;
213+ Ok ( ProjectAndUnifyResult :: Holds ( new_obligations) )
214+ }
215+ other => Ok ( other) ,
216+ }
217+ } ) ;
218+
219+ match r {
220+ Ok ( inner) => inner,
221+ Err ( err) => ProjectAndUnifyResult :: MismatchedProjectionTypes ( err) ,
222+ }
183223}
184224
185225/// Evaluates constraints of the form:
@@ -189,15 +229,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
189229/// If successful, this may result in additional obligations.
190230///
191231/// See [poly_project_and_unify_type] for an explanation of the return value.
232+ #[ tracing:: instrument( level = "debug" , skip( selcx) ) ]
192233fn project_and_unify_type < ' cx , ' tcx > (
193234 selcx : & mut SelectionContext < ' cx , ' tcx > ,
194235 obligation : & ProjectionObligation < ' tcx > ,
195- ) -> Result <
196- Result < Option < Vec < PredicateObligation < ' tcx > > > , InProgress > ,
197- MismatchedProjectionTypes < ' tcx > ,
198- > {
199- debug ! ( ?obligation, "project_and_unify_type" ) ;
200-
236+ ) -> ProjectAndUnifyResult < ' tcx > {
201237 let mut obligations = vec ! [ ] ;
202238
203239 let infcx = selcx. infcx ( ) ;
@@ -210,8 +246,8 @@ fn project_and_unify_type<'cx, 'tcx>(
210246 & mut obligations,
211247 ) {
212248 Ok ( Some ( n) ) => n,
213- Ok ( None ) => return Ok ( Ok ( None ) ) ,
214- Err ( InProgress ) => return Ok ( Err ( InProgress ) ) ,
249+ Ok ( None ) => return ProjectAndUnifyResult :: FailedNormalization ,
250+ Err ( InProgress ) => return ProjectAndUnifyResult :: Recursive ,
215251 } ;
216252 debug ! ( ?normalized, ?obligations, "project_and_unify_type result" ) ;
217253 match infcx
@@ -220,11 +256,11 @@ fn project_and_unify_type<'cx, 'tcx>(
220256 {
221257 Ok ( InferOk { obligations : inferred_obligations, value : ( ) } ) => {
222258 obligations. extend ( inferred_obligations) ;
223- Ok ( Ok ( Some ( obligations) ) )
259+ ProjectAndUnifyResult :: Holds ( obligations)
224260 }
225261 Err ( err) => {
226- debug ! ( "project_and_unify_type: equating types encountered error {:?}" , err) ;
227- Err ( MismatchedProjectionTypes { err } )
262+ debug ! ( "equating types encountered error {:?}" , err) ;
263+ ProjectAndUnifyResult :: MismatchedProjectionTypes ( MismatchedProjectionTypes { err } )
228264 }
229265 }
230266}
0 commit comments