@@ -27,6 +27,7 @@ use rustc_hir::def::DefKind;
27
27
use rustc_hir:: def_id:: DefId ;
28
28
use rustc_hir:: lang_items:: LangItem ;
29
29
use rustc_infer:: infer:: resolve:: OpportunisticRegionResolver ;
30
+ use rustc_middle:: ty:: fold:: MaxUniverse ;
30
31
use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder } ;
31
32
use rustc_middle:: ty:: subst:: Subst ;
32
33
use rustc_middle:: ty:: { self , Term , ToPredicate , Ty , TyCtxt } ;
@@ -143,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
143
144
}
144
145
}
145
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
+
146
159
/// Evaluates constraints of the form:
147
160
///
148
161
/// for<...> <T as Trait>::U == V
@@ -166,19 +179,39 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
166
179
pub ( super ) fn poly_project_and_unify_type < ' cx , ' tcx > (
167
180
selcx : & mut SelectionContext < ' cx , ' tcx > ,
168
181
obligation : & PolyProjectionObligation < ' tcx > ,
169
- ) -> Result <
170
- Result < Option < Vec < PredicateObligation < ' tcx > > > , InProgress > ,
171
- MismatchedProjectionTypes < ' tcx > ,
172
- > {
182
+ ) -> ProjectAndUnifyResult < ' tcx > {
173
183
let infcx = selcx. infcx ( ) ;
174
- infcx. commit_if_ok ( |_snapshot| {
184
+ let r = infcx. commit_if_ok ( |_snapshot| {
185
+ let old_universe = infcx. universe ( ) ;
175
186
let placeholder_predicate =
176
187
infcx. replace_bound_vars_with_placeholders ( obligation. predicate ) ;
188
+ let new_universe = infcx. universe ( ) ;
177
189
178
190
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
+ }
182
215
}
183
216
184
217
/// Evaluates constraints of the form:
@@ -188,15 +221,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
188
221
/// If successful, this may result in additional obligations.
189
222
///
190
223
/// See [poly_project_and_unify_type] for an explanation of the return value.
224
+ #[ tracing:: instrument( level = "debug" , skip( selcx) ) ]
191
225
fn project_and_unify_type < ' cx , ' tcx > (
192
226
selcx : & mut SelectionContext < ' cx , ' tcx > ,
193
227
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 > {
200
229
let mut obligations = vec ! [ ] ;
201
230
202
231
let infcx = selcx. infcx ( ) ;
@@ -209,8 +238,8 @@ fn project_and_unify_type<'cx, 'tcx>(
209
238
& mut obligations,
210
239
) {
211
240
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 ,
214
243
} ;
215
244
debug ! ( ?normalized, ?obligations, "project_and_unify_type result" ) ;
216
245
match infcx
@@ -219,11 +248,11 @@ fn project_and_unify_type<'cx, 'tcx>(
219
248
{
220
249
Ok ( InferOk { obligations : inferred_obligations, value : ( ) } ) => {
221
250
obligations. extend ( inferred_obligations) ;
222
- Ok ( Ok ( Some ( obligations) ) )
251
+ ProjectAndUnifyResult :: Holds ( obligations)
223
252
}
224
253
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 } )
227
256
}
228
257
}
229
258
}
0 commit comments