@@ -42,9 +42,8 @@ use super::{MiscVariable, TypeTrace};
42
42
use ty:: { IntType , UintType } ;
43
43
use ty:: { self , Ty , TyCtxt } ;
44
44
use ty:: error:: TypeError ;
45
- use ty:: fold:: TypeFoldable ;
46
- use ty:: relate:: { RelateResult , TypeRelation } ;
47
- use traits:: PredicateObligations ;
45
+ use ty:: relate:: { self , Relate , RelateResult , TypeRelation } ;
46
+ use traits:: { Obligation , PredicateObligations } ;
48
47
49
48
use syntax:: ast;
50
49
use syntax_pos:: Span ;
@@ -207,11 +206,16 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
207
206
// `'?2` and `?3` are fresh region/type inference
208
207
// variables. (Down below, we will relate `a_ty <: b_ty`,
209
208
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
210
- let b_ty = self . generalize ( a_ty, b_vid, dir == EqTo ) ?;
209
+ let Generalization { ty : b_ty, needs_wf } = self . generalize ( a_ty, b_vid, dir) ?;
211
210
debug ! ( "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})" ,
212
211
a_ty, dir, b_vid, b_ty) ;
213
212
self . infcx . type_variables . borrow_mut ( ) . instantiate ( b_vid, b_ty) ;
214
213
214
+ if needs_wf {
215
+ self . obligations . push ( Obligation :: new ( self . trace . cause . clone ( ) ,
216
+ ty:: Predicate :: WellFormed ( b_ty) ) ) ;
217
+ }
218
+
215
219
// Finally, relate `b_ty` to `a_ty`, as described in previous comment.
216
220
//
217
221
// FIXME(#16847): This code is non-ideal because all these subtype
@@ -230,50 +234,125 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
230
234
231
235
/// Attempts to generalize `ty` for the type variable `for_vid`.
232
236
/// This checks for cycle -- that is, whether the type `ty`
233
- /// references `for_vid`. If `is_eq_relation` is false, it will
234
- /// also replace all regions/unbound-type-variables with fresh
235
- /// variables. Returns `TyError` in the case of a cycle, `Ok`
236
- /// 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).
237
240
///
238
241
/// Preconditions:
239
242
///
240
243
/// - `for_vid` is a "root vid"
241
244
fn generalize ( & self ,
242
245
ty : Ty < ' tcx > ,
243
246
for_vid : ty:: TyVid ,
244
- is_eq_relation : bool )
245
- -> RelateResult < ' tcx , Ty < ' tcx > >
247
+ dir : RelationDir )
248
+ -> RelateResult < ' tcx , Generalization < ' tcx > >
246
249
{
250
+ // Determine the ambient variance within which `ty` appears.
251
+ // The surrounding equation is:
252
+ //
253
+ // ty [op] ty2
254
+ //
255
+ // where `op` is either `==`, `<:`, or `:>`. This maps quite
256
+ // naturally.
257
+ let ambient_variance = match dir {
258
+ RelationDir :: EqTo => ty:: Invariant ,
259
+ RelationDir :: SubtypeOf => ty:: Covariant ,
260
+ RelationDir :: SupertypeOf => ty:: Contravariant ,
261
+ } ;
262
+
247
263
let mut generalize = Generalizer {
248
264
infcx : self . infcx ,
249
265
span : self . trace . cause . span ,
250
266
for_vid_sub_root : self . infcx . type_variables . borrow_mut ( ) . sub_root_var ( for_vid) ,
251
- is_eq_relation : is_eq_relation ,
252
- cycle_detected : false
267
+ ambient_variance : ambient_variance ,
268
+ needs_wf : false ,
253
269
} ;
254
- let u = ty. fold_with ( & mut generalize) ;
255
- if generalize. cycle_detected {
256
- Err ( TypeError :: CyclicTy )
257
- } else {
258
- Ok ( u)
259
- }
270
+
271
+ let ty = generalize. relate ( & ty, & ty) ?;
272
+ let needs_wf = generalize. needs_wf ;
273
+ Ok ( Generalization { ty, needs_wf } )
260
274
}
261
275
}
262
276
263
277
struct Generalizer < ' cx , ' gcx : ' cx +' tcx , ' tcx : ' cx > {
264
278
infcx : & ' cx InferCtxt < ' cx , ' gcx , ' tcx > ,
265
279
span : Span ,
266
280
for_vid_sub_root : ty:: TyVid ,
267
- is_eq_relation : bool ,
268
- cycle_detected : bool ,
281
+ ambient_variance : ty :: Variance ,
282
+ needs_wf : bool , // see the field `needs_wf` in `Generalization`
269
283
}
270
284
271
- impl < ' cx , ' gcx , ' tcx > ty:: fold:: TypeFolder < ' gcx , ' tcx > for Generalizer < ' cx , ' gcx , ' tcx > {
272
- fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' a , ' gcx , ' tcx > {
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 ,
317
+ }
318
+
319
+ impl < ' cx , ' gcx , ' tcx > TypeRelation < ' cx , ' gcx , ' tcx > for Generalizer < ' cx , ' gcx , ' tcx > {
320
+ fn tcx ( & self ) -> TyCtxt < ' cx , ' gcx , ' tcx > {
273
321
self . infcx . tcx
274
322
}
275
323
276
- fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
324
+ fn tag ( & self ) -> & ' static str {
325
+ "Generalizer"
326
+ }
327
+
328
+ fn a_is_expected ( & self ) -> bool {
329
+ true
330
+ }
331
+
332
+ fn binders < T > ( & mut self , a : & ty:: Binder < T > , b : & ty:: Binder < T > )
333
+ -> RelateResult < ' tcx , ty:: Binder < T > >
334
+ where T : Relate < ' tcx >
335
+ {
336
+ Ok ( ty:: Binder ( self . relate ( a. skip_binder ( ) , b. skip_binder ( ) ) ?) )
337
+ }
338
+
339
+ fn relate_with_variance < T : Relate < ' tcx > > ( & mut self ,
340
+ variance : ty:: Variance ,
341
+ a : & T ,
342
+ b : & T )
343
+ -> RelateResult < ' tcx , T >
344
+ {
345
+ let old_ambient_variance = self . ambient_variance ;
346
+ self . ambient_variance = self . ambient_variance . xform ( variance) ;
347
+
348
+ let result = self . relate ( a, b) ;
349
+ self . ambient_variance = old_ambient_variance;
350
+ result
351
+ }
352
+
353
+ fn tys ( & mut self , t : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
354
+ assert_eq ! ( t, t2) ; // we are abusing TypeRelation here; both LHS and RHS ought to be ==
355
+
277
356
// Check to see whether the type we are genealizing references
278
357
// any other type variable related to `vid` via
279
358
// subtyping. This is basically our "occurs check", preventing
@@ -286,41 +365,63 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
286
365
if sub_vid == self . for_vid_sub_root {
287
366
// If sub-roots are equal, then `for_vid` and
288
367
// `vid` are related via subtyping.
289
- self . cycle_detected = true ;
290
- self . tcx ( ) . types . err
368
+ return Err ( TypeError :: CyclicTy ) ;
291
369
} else {
292
370
match variables. probe_root ( vid) {
293
371
Some ( u) => {
294
372
drop ( variables) ;
295
- self . fold_ty ( u)
373
+ self . relate ( & u , & u)
296
374
}
297
375
None => {
298
- if !self . is_eq_relation {
299
- let origin = variables. origin ( vid) ;
300
- let new_var_id = variables. new_var ( false , origin, None ) ;
301
- let u = self . tcx ( ) . mk_var ( new_var_id) ;
302
- debug ! ( "generalize: replacing original vid={:?} with new={:?}" ,
303
- vid, u) ;
304
- u
305
- } else {
306
- t
376
+ match self . ambient_variance {
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 => ( ) ,
307
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) ;
308
397
}
309
398
}
310
399
}
311
400
}
401
+ ty:: TyInfer ( ty:: IntVar ( _) ) |
402
+ ty:: TyInfer ( ty:: FloatVar ( _) ) => {
403
+ // No matter what mode we are in,
404
+ // integer/floating-point types must be equal to be
405
+ // relatable.
406
+ Ok ( t)
407
+ }
312
408
_ => {
313
- t . super_fold_with ( self )
409
+ relate :: super_relate_tys ( self , t , t )
314
410
}
315
411
}
316
412
}
317
413
318
- fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
414
+ fn regions ( & mut self , r : ty:: Region < ' tcx > , r2 : ty:: Region < ' tcx > )
415
+ -> RelateResult < ' tcx , ty:: Region < ' tcx > > {
416
+ assert_eq ! ( r, r2) ; // we are abusing TypeRelation here; both LHS and RHS ought to be ==
417
+
319
418
match * r {
320
419
// Never make variables for regions bound within the type itself,
321
420
// nor for erased regions.
322
421
ty:: ReLateBound ( ..) |
323
- ty:: ReErased => { return r; }
422
+ ty:: ReErased => {
423
+ return Ok ( r) ;
424
+ }
324
425
325
426
// Early-bound regions should really have been substituted away before
326
427
// we get to this point.
@@ -342,15 +443,16 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
342
443
ty:: ReScope ( ..) |
343
444
ty:: ReVar ( ..) |
344
445
ty:: ReFree ( ..) => {
345
- if self . is_eq_relation {
346
- return r;
446
+ match self . ambient_variance {
447
+ ty:: Invariant => return Ok ( r) ,
448
+ ty:: Bivariant | ty:: Covariant | ty:: Contravariant => ( ) ,
347
449
}
348
450
}
349
451
}
350
452
351
453
// FIXME: This is non-ideal because we don't give a
352
454
// very descriptive origin for this region variable.
353
- self . infcx . next_region_var ( MiscVariable ( self . span ) )
455
+ Ok ( self . infcx . next_region_var ( MiscVariable ( self . span ) ) )
354
456
}
355
457
}
356
458
0 commit comments