@@ -28,7 +28,7 @@ use rustc_hir::def_id::DefId;
28
28
use rustc_hir:: lang_items:: LangItem ;
29
29
use rustc_infer:: infer:: resolve:: OpportunisticRegionResolver ;
30
30
use rustc_middle:: traits:: select:: OverflowError ;
31
- use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder } ;
31
+ use rustc_middle:: ty:: fold:: { MaxUniverse , TypeFoldable , TypeFolder } ;
32
32
use rustc_middle:: ty:: subst:: Subst ;
33
33
use rustc_middle:: ty:: { self , Term , ToPredicate , Ty , TyCtxt } ;
34
34
use rustc_span:: symbol:: sym;
@@ -144,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
144
144
}
145
145
}
146
146
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
+
147
159
/// Evaluates constraints of the form:
148
160
///
149
161
/// for<...> <T as Trait>::U == V
@@ -167,19 +179,47 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
167
179
pub ( super ) fn poly_project_and_unify_type < ' cx , ' tcx > (
168
180
selcx : & mut SelectionContext < ' cx , ' tcx > ,
169
181
obligation : & PolyProjectionObligation < ' tcx > ,
170
- ) -> Result <
171
- Result < Option < Vec < PredicateObligation < ' tcx > > > , InProgress > ,
172
- MismatchedProjectionTypes < ' tcx > ,
173
- > {
182
+ ) -> ProjectAndUnifyResult < ' tcx > {
174
183
let infcx = selcx. infcx ( ) ;
175
- infcx. commit_if_ok ( |_snapshot| {
184
+ let r = infcx. commit_if_ok ( |_snapshot| {
185
+ let old_universe = infcx. universe ( ) ;
176
186
let placeholder_predicate =
177
187
infcx. replace_bound_vars_with_placeholders ( obligation. predicate ) ;
188
+ let new_universe = infcx. universe ( ) ;
178
189
179
190
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
+ }
183
223
}
184
224
185
225
/// Evaluates constraints of the form:
@@ -189,15 +229,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
189
229
/// If successful, this may result in additional obligations.
190
230
///
191
231
/// See [poly_project_and_unify_type] for an explanation of the return value.
232
+ #[ tracing:: instrument( level = "debug" , skip( selcx) ) ]
192
233
fn project_and_unify_type < ' cx , ' tcx > (
193
234
selcx : & mut SelectionContext < ' cx , ' tcx > ,
194
235
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 > {
201
237
let mut obligations = vec ! [ ] ;
202
238
203
239
let infcx = selcx. infcx ( ) ;
@@ -210,8 +246,8 @@ fn project_and_unify_type<'cx, 'tcx>(
210
246
& mut obligations,
211
247
) {
212
248
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 ,
215
251
} ;
216
252
debug ! ( ?normalized, ?obligations, "project_and_unify_type result" ) ;
217
253
let actual = obligation. predicate . term ;
@@ -231,11 +267,11 @@ fn project_and_unify_type<'cx, 'tcx>(
231
267
match infcx. at ( & obligation. cause , obligation. param_env ) . eq ( normalized, actual) {
232
268
Ok ( InferOk { obligations : inferred_obligations, value : ( ) } ) => {
233
269
obligations. extend ( inferred_obligations) ;
234
- Ok ( Ok ( Some ( obligations) ) )
270
+ ProjectAndUnifyResult :: Holds ( obligations)
235
271
}
236
272
Err ( err) => {
237
- debug ! ( "project_and_unify_type: equating types encountered error {:?}" , err) ;
238
- Err ( MismatchedProjectionTypes { err } )
273
+ debug ! ( "equating types encountered error {:?}" , err) ;
274
+ ProjectAndUnifyResult :: MismatchedProjectionTypes ( MismatchedProjectionTypes { err } )
239
275
}
240
276
}
241
277
}
0 commit comments