@@ -42,8 +42,7 @@ 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 } ;
45
+ use ty:: relate:: { self , Relate , RelateResult , TypeRelation } ;
47
46
use traits:: PredicateObligations ;
48
47
49
48
use syntax:: ast;
@@ -207,7 +206,7 @@ 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 b_ty = 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) ;
@@ -241,39 +240,77 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
241
240
fn generalize ( & self ,
242
241
ty : Ty < ' tcx > ,
243
242
for_vid : ty:: TyVid ,
244
- is_eq_relation : bool )
243
+ dir : RelationDir )
245
244
-> RelateResult < ' tcx , Ty < ' tcx > >
246
245
{
246
+ // Determine the ambient variance within which `ty` appears.
247
+ // The surrounding equation is:
248
+ //
249
+ // ty [op] ty2
250
+ //
251
+ // where `op` is either `==`, `<:`, or `:>`. This maps quite
252
+ // naturally.
253
+ let ambient_variance = match dir {
254
+ RelationDir :: EqTo => ty:: Invariant ,
255
+ RelationDir :: SubtypeOf => ty:: Covariant ,
256
+ RelationDir :: SupertypeOf => ty:: Contravariant ,
257
+ } ;
258
+
247
259
let mut generalize = Generalizer {
248
260
infcx : self . infcx ,
249
261
span : self . trace . cause . span ,
250
262
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
263
+ ambient_variance : ambient_variance,
253
264
} ;
254
- let u = ty. fold_with ( & mut generalize) ;
255
- if generalize. cycle_detected {
256
- Err ( TypeError :: CyclicTy )
257
- } else {
258
- Ok ( u)
259
- }
265
+
266
+ generalize. relate ( & ty, & ty)
260
267
}
261
268
}
262
269
263
270
struct Generalizer < ' cx , ' gcx : ' cx +' tcx , ' tcx : ' cx > {
264
271
infcx : & ' cx InferCtxt < ' cx , ' gcx , ' tcx > ,
265
272
span : Span ,
266
273
for_vid_sub_root : ty:: TyVid ,
267
- is_eq_relation : bool ,
268
- cycle_detected : bool ,
274
+ ambient_variance : ty:: Variance ,
269
275
}
270
276
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 > {
277
+ impl < ' cx , ' gcx , ' tcx > TypeRelation < ' cx , ' gcx , ' tcx > for Generalizer < ' cx , ' gcx , ' tcx > {
278
+ fn tcx ( & self ) -> TyCtxt < ' cx , ' gcx , ' tcx > {
273
279
self . infcx . tcx
274
280
}
275
281
276
- fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
282
+ fn tag ( & self ) -> & ' static str {
283
+ "Generalizer"
284
+ }
285
+
286
+ fn a_is_expected ( & self ) -> bool {
287
+ true
288
+ }
289
+
290
+ fn binders < T > ( & mut self , a : & ty:: Binder < T > , b : & ty:: Binder < T > )
291
+ -> RelateResult < ' tcx , ty:: Binder < T > >
292
+ where T : Relate < ' tcx >
293
+ {
294
+ Ok ( ty:: Binder ( self . relate ( a. skip_binder ( ) , b. skip_binder ( ) ) ?) )
295
+ }
296
+
297
+ fn relate_with_variance < T : Relate < ' tcx > > ( & mut self ,
298
+ variance : ty:: Variance ,
299
+ a : & T ,
300
+ b : & T )
301
+ -> RelateResult < ' tcx , T >
302
+ {
303
+ let old_ambient_variance = self . ambient_variance ;
304
+ self . ambient_variance = self . ambient_variance . xform ( variance) ;
305
+
306
+ let result = self . relate ( a, b) ;
307
+ self . ambient_variance = old_ambient_variance;
308
+ result
309
+ }
310
+
311
+ fn tys ( & mut self , t : Ty < ' tcx > , t2 : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
312
+ assert_eq ! ( t, t2) ; // we are abusing TypeRelation here; both LHS and RHS ought to be ==
313
+
277
314
// Check to see whether the type we are genealizing references
278
315
// any other type variable related to `vid` via
279
316
// subtyping. This is basically our "occurs check", preventing
@@ -286,41 +323,54 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
286
323
if sub_vid == self . for_vid_sub_root {
287
324
// If sub-roots are equal, then `for_vid` and
288
325
// `vid` are related via subtyping.
289
- self . cycle_detected = true ;
290
- self . tcx ( ) . types . err
326
+ return Err ( TypeError :: CyclicTy ) ;
291
327
} else {
292
328
match variables. probe_root ( vid) {
293
329
Some ( u) => {
294
330
drop ( variables) ;
295
- self . fold_ty ( u)
331
+ self . relate ( & u , & u)
296
332
}
297
333
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
334
+ 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
+ }
307
345
}
308
346
}
309
347
}
310
348
}
311
349
}
350
+ ty:: TyInfer ( ty:: IntVar ( _) ) |
351
+ ty:: TyInfer ( ty:: FloatVar ( _) ) => {
352
+ // No matter what mode we are in,
353
+ // integer/floating-point types must be equal to be
354
+ // relatable.
355
+ Ok ( t)
356
+ }
312
357
_ => {
313
- t . super_fold_with ( self )
358
+ relate :: super_relate_tys ( self , t , t )
314
359
}
315
360
}
316
361
}
317
362
318
- fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
363
+ fn regions ( & mut self , r : ty:: Region < ' tcx > , r2 : ty:: Region < ' tcx > )
364
+ -> RelateResult < ' tcx , ty:: Region < ' tcx > > {
365
+ assert_eq ! ( r, r2) ; // we are abusing TypeRelation here; both LHS and RHS ought to be ==
366
+
319
367
match * r {
320
368
// Never make variables for regions bound within the type itself,
321
369
// nor for erased regions.
322
370
ty:: ReLateBound ( ..) |
323
- ty:: ReErased => { return r; }
371
+ ty:: ReErased => {
372
+ return Ok ( r) ;
373
+ }
324
374
325
375
// Early-bound regions should really have been substituted away before
326
376
// we get to this point.
@@ -342,15 +392,16 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
342
392
ty:: ReScope ( ..) |
343
393
ty:: ReVar ( ..) |
344
394
ty:: ReFree ( ..) => {
345
- if self . is_eq_relation {
346
- return r;
395
+ match self . ambient_variance {
396
+ ty:: Invariant => return Ok ( r) ,
397
+ ty:: Bivariant | ty:: Covariant | ty:: Contravariant => ( ) ,
347
398
}
348
399
}
349
400
}
350
401
351
402
// FIXME: This is non-ideal because we don't give a
352
403
// very descriptive origin for this region variable.
353
- self . infcx . next_region_var ( MiscVariable ( self . span ) )
404
+ Ok ( self . infcx . next_region_var ( MiscVariable ( self . span ) ) )
354
405
}
355
406
}
356
407
0 commit comments