@@ -43,7 +43,7 @@ use ty::{IntType, UintType};
43
43
use ty:: { self , Ty , TyCtxt } ;
44
44
use ty:: error:: TypeError ;
45
45
use ty:: relate:: { self , Relate , RelateResult , TypeRelation } ;
46
- use traits:: PredicateObligations ;
46
+ use traits:: { Obligation , PredicateObligations } ;
47
47
48
48
use syntax:: ast;
49
49
use syntax_pos:: Span ;
@@ -206,11 +206,16 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
206
206
// `'?2` and `?3` are fresh region/type inference
207
207
// variables. (Down below, we will relate `a_ty <: b_ty`,
208
208
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
209
- let b_ty = self . generalize ( a_ty, b_vid, dir) ?;
209
+ let Generalization { ty : b_ty, needs_wf } = self . generalize ( a_ty, b_vid, dir) ?;
210
210
debug ! ( "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})" ,
211
211
a_ty, dir, b_vid, b_ty) ;
212
212
self . infcx . type_variables . borrow_mut ( ) . instantiate ( b_vid, b_ty) ;
213
213
214
+ if needs_wf {
215
+ self . obligations . push ( Obligation :: new ( self . trace . cause . clone ( ) ,
216
+ ty:: Predicate :: WellFormed ( b_ty) ) ) ;
217
+ }
218
+
214
219
// Finally, relate `b_ty` to `a_ty`, as described in previous comment.
215
220
//
216
221
// FIXME(#16847): This code is non-ideal because all these subtype
@@ -229,10 +234,9 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
229
234
230
235
/// Attempts to generalize `ty` for the type variable `for_vid`.
231
236
/// This checks for cycle -- that is, whether the type `ty`
232
- /// references `for_vid`. If `is_eq_relation` is false, it will
233
- /// also replace all regions/unbound-type-variables with fresh
234
- /// variables. Returns `TyError` in the case of a cycle, `Ok`
235
- /// otherwise.
237
+ /// references `for_vid`. The `dir` is the "direction" for which we
238
+ /// a performing the generalization (i.e., are we producing a type
239
+ /// that can be used as a supertype etc).
236
240
///
237
241
/// Preconditions:
238
242
///
@@ -241,7 +245,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
241
245
ty : Ty < ' tcx > ,
242
246
for_vid : ty:: TyVid ,
243
247
dir : RelationDir )
244
- -> RelateResult < ' tcx , Ty < ' tcx > >
248
+ -> RelateResult < ' tcx , Generalization < ' tcx > >
245
249
{
246
250
// Determine the ambient variance within which `ty` appears.
247
251
// The surrounding equation is:
@@ -261,9 +265,12 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
261
265
span : self . trace . cause . span ,
262
266
for_vid_sub_root : self . infcx . type_variables . borrow_mut ( ) . sub_root_var ( for_vid) ,
263
267
ambient_variance : ambient_variance,
268
+ needs_wf : false ,
264
269
} ;
265
270
266
- generalize. relate ( & ty, & ty)
271
+ let ty = generalize. relate ( & ty, & ty) ?;
272
+ let needs_wf = generalize. needs_wf ;
273
+ Ok ( Generalization { ty, needs_wf } )
267
274
}
268
275
}
269
276
@@ -272,6 +279,41 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
272
279
span : Span ,
273
280
for_vid_sub_root : ty:: TyVid ,
274
281
ambient_variance : ty:: Variance ,
282
+ needs_wf : bool , // see the field `needs_wf` in `Generalization`
283
+ }
284
+
285
+ /// Result from a generalization operation. This includes
286
+ /// not only the generalized type, but also a bool flag
287
+ /// indicating whether further WF checks are needed.q
288
+ struct Generalization < ' tcx > {
289
+ ty : Ty < ' tcx > ,
290
+
291
+ /// If true, then the generalized type may not be well-formed,
292
+ /// even if the source type is well-formed, so we should add an
293
+ /// additional check to enforce that it is. This arises in
294
+ /// particular around 'bivariant' type parameters that are only
295
+ /// constrained by a where-clause. As an example, imagine a type:
296
+ ///
297
+ /// struct Foo<A, B> where A: Iterator<Item=B> {
298
+ /// data: A
299
+ /// }
300
+ ///
301
+ /// here, `A` will be covariant, but `B` is
302
+ /// unconstrained. However, whatever it is, for `Foo` to be WF, it
303
+ /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
304
+ /// then after generalization we will wind up with a type like
305
+ /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
306
+ /// ?D>` (or `>:`), we will wind up with the requirement that `?A
307
+ /// <: ?C`, but no particular relationship between `?B` and `?D`
308
+ /// (after all, we do not know the variance of the normalized form
309
+ /// of `A::Item` with respect to `A`). If we do nothing else, this
310
+ /// may mean that `?D` goes unconstrained (as in #41677). So, in
311
+ /// this scenario where we create a new type variable in a
312
+ /// bivariant context, we set the `needs_wf` flag to true. This
313
+ /// will force the calling code to check that `WF(Foo<?C, ?D>)`
314
+ /// holds, which in turn implies that `?C::Item == ?D`. So once
315
+ /// `?C` is constrained, that should suffice to restrict `?D`.
316
+ needs_wf : bool ,
275
317
}
276
318
277
319
impl < ' cx , ' gcx , ' tcx > TypeRelation < ' cx , ' gcx , ' tcx > for Generalizer < ' cx , ' gcx , ' tcx > {
@@ -332,17 +374,26 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
332
374
}
333
375
None => {
334
376
match self . ambient_variance {
335
- ty:: Invariant => Ok ( t) ,
336
-
337
- ty:: Bivariant | ty:: Covariant | ty:: Contravariant => {
338
- let origin = variables. origin ( vid) ;
339
- let new_var_id = variables. new_var ( false , origin, None ) ;
340
- let u = self . tcx ( ) . mk_var ( new_var_id) ;
341
- debug ! ( "generalize: replacing original vid={:?} with new={:?}" ,
342
- vid, u) ;
343
- Ok ( u)
344
- }
377
+ // Invariant: no need to make a fresh type variable.
378
+ ty:: Invariant => return Ok ( t) ,
379
+
380
+ // Bivariant: make a fresh var, but we
381
+ // may need a WF predicate. See
382
+ // comment on `needs_wf` field for
383
+ // more info.
384
+ ty:: Bivariant => self . needs_wf = true ,
385
+
386
+ // Co/contravariant: this will be
387
+ // sufficiently constrained later on.
388
+ ty:: Covariant | ty:: Contravariant => ( ) ,
345
389
}
390
+
391
+ let origin = variables. origin ( vid) ;
392
+ let new_var_id = variables. new_var ( false , origin, None ) ;
393
+ let u = self . tcx ( ) . mk_var ( new_var_id) ;
394
+ debug ! ( "generalize: replacing original vid={:?} with new={:?}" ,
395
+ vid, u) ;
396
+ return Ok ( u) ;
346
397
}
347
398
}
348
399
}
0 commit comments