@@ -92,6 +92,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
9292 Ok ( None ) // No coercion required.
9393 }
9494
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+
95101 fn unpack_actual_value < T , F > ( & self , a : Ty < ' tcx > , f : F ) -> T where
96102 F : FnOnce ( Ty < ' tcx > ) -> T ,
97103 {
@@ -340,21 +346,40 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
340346 Some ( ( ty, ty:: UnsizeLength ( len) ) )
341347 }
342348 ( & 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`
351363 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 ,
353366 builtin_bounds : data_b. bounds . builtin_bounds ,
367+
368+ // From type a
354369 projection_bounds : data_a. bounds . projection_bounds . clone ( ) ,
355370 } ;
356371 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 {
358383 Ok ( _) => Some ( ( ty_b, ty:: UnsizeUpcast ( ty_b) ) ) ,
359384 Err ( _) => None ,
360385 }
0 commit comments