@@ -92,6 +92,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
92
92
Ok ( None ) // No coercion required.
93
93
}
94
94
95
+ fn outlives ( & self , a : ty:: Region , b : ty:: Region ) -> cres < ' tcx , ( ) > {
96
+ let sub = Sub ( self . fcx . infcx ( ) . combine_fields ( false , self . trace . clone ( ) ) ) ;
97
+ try!( sub. regions ( b, a) ) ;
98
+ Ok ( ( ) )
99
+ }
100
+
95
101
fn unpack_actual_value < T , F > ( & self , a : Ty < ' tcx > , f : F ) -> T where
96
102
F : FnOnce ( Ty < ' tcx > ) -> T ,
97
103
{
@@ -340,21 +346,40 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
340
346
Some ( ( ty, ty:: UnsizeLength ( len) ) )
341
347
}
342
348
( & ty:: ty_trait( ref data_a) , & ty:: ty_trait( ref data_b) ) => {
343
- // For now, we only support upcasts from
344
- // `Foo+Send` to `Foo` (really, any time there are
345
- // fewer builtin bounds then before). These are
346
- // convenient because they don't require any sort
347
- // of change to the vtable at runtime.
348
- if data_a. bounds . builtin_bounds != data_b. bounds . builtin_bounds &&
349
- data_a. bounds . builtin_bounds . is_superset ( & data_b. bounds . builtin_bounds )
350
- {
349
+ // Upcasts permit two things:
350
+ //
351
+ // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
352
+ // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
353
+ //
354
+ // Note that neither of these changes requires any
355
+ // change at runtime. Eventually this will be
356
+ // generalized.
357
+ //
358
+ // We always upcast when we can because of reason
359
+ // #2 (region bounds).
360
+ if data_a. bounds . builtin_bounds . is_superset ( & data_b. bounds . builtin_bounds ) {
361
+ // construct a type `a1` which is a version of
362
+ // `a` using the upcast bounds from `b`
351
363
let bounds_a1 = ty:: ExistentialBounds {
352
- region_bound : data_a. bounds . region_bound ,
364
+ // From type b
365
+ region_bound : data_b. bounds . region_bound ,
353
366
builtin_bounds : data_b. bounds . builtin_bounds ,
367
+
368
+ // From type a
354
369
projection_bounds : data_a. bounds . projection_bounds . clone ( ) ,
355
370
} ;
356
371
let ty_a1 = ty:: mk_trait ( tcx, data_a. principal . clone ( ) , bounds_a1) ;
357
- match self . fcx . infcx ( ) . try ( |_| self . subtype ( ty_a1, ty_b) ) {
372
+
373
+ // relate `a1` to `b`
374
+ let result = self . fcx . infcx ( ) . try ( |_| {
375
+ // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
376
+ try!( self . outlives ( data_a. bounds . region_bound ,
377
+ data_b. bounds . region_bound ) ) ;
378
+ self . subtype ( ty_a1, ty_b)
379
+ } ) ;
380
+
381
+ // if that was successful, we have a coercion
382
+ match result {
358
383
Ok ( _) => Some ( ( ty_b, ty:: UnsizeUpcast ( ty_b) ) ) ,
359
384
Err ( _) => None ,
360
385
}
0 commit comments