@@ -258,70 +258,64 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
258
258
259
259
match ( & a. sty , & b. sty ) {
260
260
( & ty:: ty_rptr( _, ty:: mt { ty : t_a, mutbl : mutbl_a} ) , & ty:: ty_rptr( _, mt_b) ) => {
261
- self . unpack_actual_value ( t_a, |a| {
262
- match self . unsize_ty ( t_a, a, mt_b. ty ) {
263
- Some ( ( ty, kind) ) => {
264
- if !can_coerce_mutbls ( mutbl_a, mt_b. mutbl ) {
265
- return Err ( ty:: terr_mutability) ;
266
- }
267
-
268
- let coercion = Coercion ( self . trace . clone ( ) ) ;
269
- let r_borrow = self . fcx . infcx ( ) . next_region_var ( coercion) ;
270
- let ty = ty:: mk_rptr ( self . tcx ( ) ,
271
- self . tcx ( ) . mk_region ( r_borrow) ,
272
- ty:: mt { ty : ty, mutbl : mt_b. mutbl } ) ;
273
- try!( self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, b) ) ) ;
274
- debug ! ( "Success, coerced with AutoDerefRef(1, \
275
- AutoPtr(AutoUnsize({:?})))", kind) ;
276
- Ok ( Some ( AdjustDerefRef ( AutoDerefRef {
277
- autoderefs : 1 ,
278
- autoref : Some ( ty:: AutoPtr ( r_borrow, mt_b. mutbl ,
279
- Some ( box AutoUnsize ( kind) ) ) )
280
- } ) ) )
261
+ match self . unsize_ty ( t_a, mt_b. ty ) {
262
+ Some ( ( ty, kind) ) => {
263
+ if !can_coerce_mutbls ( mutbl_a, mt_b. mutbl ) {
264
+ return Err ( ty:: terr_mutability) ;
281
265
}
282
- _ => Err ( ty:: terr_mismatch)
266
+
267
+ let coercion = Coercion ( self . trace . clone ( ) ) ;
268
+ let r_borrow = self . fcx . infcx ( ) . next_region_var ( coercion) ;
269
+ let ty = ty:: mk_rptr ( self . tcx ( ) ,
270
+ self . tcx ( ) . mk_region ( r_borrow) ,
271
+ ty:: mt { ty : ty, mutbl : mt_b. mutbl } ) ;
272
+ try!( self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, b) ) ) ;
273
+ debug ! ( "Success, coerced with AutoDerefRef(1, \
274
+ AutoPtr(AutoUnsize({:?})))", kind) ;
275
+ Ok ( Some ( AdjustDerefRef ( AutoDerefRef {
276
+ autoderefs : 1 ,
277
+ autoref : Some ( ty:: AutoPtr ( r_borrow, mt_b. mutbl ,
278
+ Some ( box AutoUnsize ( kind) ) ) )
279
+ } ) ) )
283
280
}
284
- } )
281
+ _ => Err ( ty:: terr_mismatch)
282
+ }
285
283
}
286
284
( & ty:: ty_rptr( _, ty:: mt { ty : t_a, mutbl : mutbl_a} ) , & ty:: ty_ptr( mt_b) ) => {
287
- self . unpack_actual_value ( t_a, |a| {
288
- match self . unsize_ty ( t_a, a, mt_b. ty ) {
289
- Some ( ( ty, kind) ) => {
290
- if !can_coerce_mutbls ( mutbl_a, mt_b. mutbl ) {
291
- return Err ( ty:: terr_mutability) ;
292
- }
293
-
294
- let ty = ty:: mk_ptr ( self . tcx ( ) ,
295
- ty:: mt { ty : ty, mutbl : mt_b. mutbl } ) ;
296
- try!( self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, b) ) ) ;
297
- debug ! ( "Success, coerced with AutoDerefRef(1, \
298
- AutoPtr(AutoUnsize({:?})))", kind) ;
299
- Ok ( Some ( AdjustDerefRef ( AutoDerefRef {
300
- autoderefs : 1 ,
301
- autoref : Some ( ty:: AutoUnsafe ( mt_b. mutbl ,
302
- Some ( box AutoUnsize ( kind) ) ) )
303
- } ) ) )
285
+ match self . unsize_ty ( t_a, mt_b. ty ) {
286
+ Some ( ( ty, kind) ) => {
287
+ if !can_coerce_mutbls ( mutbl_a, mt_b. mutbl ) {
288
+ return Err ( ty:: terr_mutability) ;
304
289
}
305
- _ => Err ( ty:: terr_mismatch)
290
+
291
+ let ty = ty:: mk_ptr ( self . tcx ( ) ,
292
+ ty:: mt { ty : ty, mutbl : mt_b. mutbl } ) ;
293
+ try!( self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, b) ) ) ;
294
+ debug ! ( "Success, coerced with AutoDerefRef(1, \
295
+ AutoPtr(AutoUnsize({:?})))", kind) ;
296
+ Ok ( Some ( AdjustDerefRef ( AutoDerefRef {
297
+ autoderefs : 1 ,
298
+ autoref : Some ( ty:: AutoUnsafe ( mt_b. mutbl ,
299
+ Some ( box AutoUnsize ( kind) ) ) )
300
+ } ) ) )
306
301
}
307
- } )
302
+ _ => Err ( ty:: terr_mismatch)
303
+ }
308
304
}
309
305
( & ty:: ty_uniq( t_a) , & ty:: ty_uniq( t_b) ) => {
310
- self . unpack_actual_value ( t_a, |a| {
311
- match self . unsize_ty ( t_a, a, t_b) {
312
- Some ( ( ty, kind) ) => {
313
- let ty = ty:: mk_uniq ( self . tcx ( ) , ty) ;
314
- try!( self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, b) ) ) ;
315
- debug ! ( "Success, coerced with AutoDerefRef(1, \
316
- AutoUnsizeUniq({:?}))", kind) ;
317
- Ok ( Some ( AdjustDerefRef ( AutoDerefRef {
318
- autoderefs : 1 ,
319
- autoref : Some ( ty:: AutoUnsizeUniq ( kind) )
320
- } ) ) )
321
- }
322
- _ => Err ( ty:: terr_mismatch)
306
+ match self . unsize_ty ( t_a, t_b) {
307
+ Some ( ( ty, kind) ) => {
308
+ let ty = ty:: mk_uniq ( self . tcx ( ) , ty) ;
309
+ try!( self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, b) ) ) ;
310
+ debug ! ( "Success, coerced with AutoDerefRef(1, \
311
+ AutoUnsizeUniq({:?}))", kind) ;
312
+ Ok ( Some ( AdjustDerefRef ( AutoDerefRef {
313
+ autoderefs : 1 ,
314
+ autoref : Some ( ty:: AutoUnsizeUniq ( kind) )
315
+ } ) ) )
323
316
}
324
- } )
317
+ _ => Err ( ty:: terr_mismatch)
318
+ }
325
319
}
326
320
_ => Err ( ty:: terr_mismatch)
327
321
}
@@ -332,112 +326,134 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
332
326
// E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
333
327
fn unsize_ty ( & self ,
334
328
ty_a : Ty < ' tcx > ,
335
- a : Ty < ' tcx > , // TODO unwrap ty_a here, not in the caller
336
329
ty_b : Ty < ' tcx > )
337
330
-> Option < ( Ty < ' tcx > , ty:: UnsizeKind < ' tcx > ) >
338
331
{
339
332
let tcx = self . tcx ( ) ;
340
333
341
- self . unpack_actual_value ( ty_b, |b| {
342
- debug ! ( "unsize_ty(a={}, b={})" , a. repr( self . tcx( ) ) , b. repr( self . tcx( ) ) ) ;
343
- match ( & a. sty , & b. sty ) {
344
- ( & ty:: ty_vec( t_a, Some ( len) ) , & ty:: ty_vec( _, None ) ) => {
345
- let ty = ty:: mk_vec ( tcx, t_a, None ) ;
346
- Some ( ( ty, ty:: UnsizeLength ( len) ) )
347
- }
348
- ( & ty:: ty_trait( ref data_a) , & ty:: ty_trait( ref data_b) ) => {
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`
363
- let bounds_a1 = ty:: ExistentialBounds {
364
- // From type b
365
- region_bound : data_b. bounds . region_bound ,
366
- builtin_bounds : data_b. bounds . builtin_bounds ,
367
-
368
- // From type a
369
- projection_bounds : data_a. bounds . projection_bounds . clone ( ) ,
370
- } ;
371
- let ty_a1 = ty:: mk_trait ( tcx, data_a. principal . clone ( ) , bounds_a1) ;
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 {
383
- Ok ( _) => Some ( ( ty_b, ty:: UnsizeUpcast ( ty_b) ) ) ,
384
- Err ( _) => None ,
385
- }
386
- } else {
387
- None
334
+ self . unpack_actual_value ( ty_a, |a| {
335
+ self . unpack_actual_value ( ty_b, |b| {
336
+ debug ! ( "unsize_ty(a={}, b={})" , a. repr( self . tcx( ) ) , b. repr( self . tcx( ) ) ) ;
337
+ match ( & a. sty , & b. sty ) {
338
+ ( & ty:: ty_vec( t_a, Some ( len) ) , & ty:: ty_vec( _, None ) ) => {
339
+ let ty = ty:: mk_vec ( tcx, t_a, None ) ;
340
+ Some ( ( ty, ty:: UnsizeLength ( len) ) )
388
341
}
389
- }
390
- ( _, & ty:: ty_trait( ref data) ) => {
391
- Some ( ( ty_b, ty:: UnsizeVtable ( ty:: TyTrait { principal : data. principal . clone ( ) ,
392
- bounds : data. bounds . clone ( ) } ,
393
- ty_a) ) )
394
- }
395
- ( & ty:: ty_struct( did_a, substs_a) , & ty:: ty_struct( did_b, substs_b) )
396
- if did_a == did_b => {
397
- debug ! ( "unsizing a struct" ) ;
398
- // Try unsizing each type param in turn to see if we end up with ty_b.
399
- let ty_substs_a = substs_a. types . get_slice ( subst:: TypeSpace ) ;
400
- let ty_substs_b = substs_b. types . get_slice ( subst:: TypeSpace ) ;
401
- assert ! ( ty_substs_a. len( ) == ty_substs_b. len( ) ) ;
402
-
403
- let mut result = None ;
404
- let tps = ty_substs_a. iter ( ) . zip ( ty_substs_b. iter ( ) ) . enumerate ( ) ;
405
- for ( i, ( tp_a, tp_b) ) in tps {
406
- if self . fcx . infcx ( ) . try ( |_| self . subtype ( * tp_a, * tp_b) ) . is_ok ( ) {
407
- continue ;
342
+ ( & ty:: ty_trait( ref data_a) , & ty:: ty_trait( ref data_b) ) => {
343
+ // Upcasts permit two things:
344
+ //
345
+ // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
346
+ // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
347
+ //
348
+ // Note that neither of these changes requires any
349
+ // change at runtime. Eventually this will be
350
+ // generalized.
351
+ //
352
+ // We always upcast when we can because of reason
353
+ // #2 (region bounds).
354
+ if data_a. bounds . builtin_bounds . is_superset ( & data_b. bounds . builtin_bounds ) {
355
+ // construct a type `a1` which is a version of
356
+ // `a` using the upcast bounds from `b`
357
+ let bounds_a1 = ty:: ExistentialBounds {
358
+ // From type b
359
+ region_bound : data_b. bounds . region_bound ,
360
+ builtin_bounds : data_b. bounds . builtin_bounds ,
361
+
362
+ // From type a
363
+ projection_bounds : data_a. bounds . projection_bounds . clone ( ) ,
364
+ } ;
365
+ let ty_a1 = ty:: mk_trait ( tcx, data_a. principal . clone ( ) , bounds_a1) ;
366
+
367
+ // relate `a1` to `b`
368
+ let result = self . fcx . infcx ( ) . try ( |_| {
369
+ // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
370
+ try!( self . outlives ( data_a. bounds . region_bound ,
371
+ data_b. bounds . region_bound ) ) ;
372
+ self . subtype ( ty_a1, ty_b)
373
+ } ) ;
374
+
375
+ // if that was successful, we have a coercion
376
+ match result {
377
+ Ok ( _) => Some ( ( ty_b, ty:: UnsizeUpcast ( ty_b) ) ) ,
378
+ Err ( _) => None ,
379
+ }
380
+ } else {
381
+ None
408
382
}
409
- match
410
- self . unpack_actual_value (
411
- * tp_a,
412
- |tp| self . unsize_ty ( * tp_a, tp, * tp_b) )
383
+ }
384
+ ( & ty:: ty_trait( ref data_a) , & ty:: ty_trait( ref data_b) ) => {
385
+ // For now, we only support upcasts from
386
+ // `Foo+Send` to `Foo` (really, any time there are
387
+ // fewer builtin bounds then before). These are
388
+ // convenient because they don't require any sort
389
+ // of change to the vtable at runtime.
390
+ if data_a. bounds . builtin_bounds != data_b. bounds . builtin_bounds &&
391
+ data_a. bounds . builtin_bounds . is_superset ( & data_b. bounds . builtin_bounds )
413
392
{
414
- Some ( ( new_tp, k) ) => {
415
- // Check that the whole types match.
416
- let mut new_substs = substs_a. clone ( ) ;
417
- new_substs. types . get_mut_slice ( subst:: TypeSpace ) [ i] = new_tp;
418
- let ty = ty:: mk_struct ( tcx, did_a, tcx. mk_substs ( new_substs) ) ;
419
- if self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, ty_b) ) . is_err ( ) {
420
- debug ! ( "Unsized type parameter '{}', but still \
421
- could not match types {} and {}",
422
- ppaux:: ty_to_string( tcx, * tp_a) ,
423
- ppaux:: ty_to_string( tcx, ty) ,
424
- ppaux:: ty_to_string( tcx, ty_b) ) ;
425
- // We can only unsize a single type parameter, so
426
- // if we unsize one and it doesn't give us the
427
- // type we want, then we won't succeed later.
393
+ let bounds_a1 = ty:: ExistentialBounds {
394
+ region_bound : data_a. bounds . region_bound ,
395
+ builtin_bounds : data_b. bounds . builtin_bounds ,
396
+ projection_bounds : data_a. bounds . projection_bounds . clone ( ) ,
397
+ } ;
398
+ let ty_a1 = ty:: mk_trait ( tcx, data_a. principal . clone ( ) , bounds_a1) ;
399
+ match self . fcx . infcx ( ) . try ( |_| self . subtype ( ty_a1, ty_b) ) {
400
+ Ok ( _) => Some ( ( ty_b, ty:: UnsizeUpcast ( ty_b) ) ) ,
401
+ Err ( _) => None ,
402
+ }
403
+ } else {
404
+ None
405
+ }
406
+ }
407
+ ( _, & ty:: ty_trait( ref data) ) => {
408
+ Some ( ( ty_b, ty:: UnsizeVtable ( ty:: TyTrait {
409
+ principal : data. principal . clone ( ) ,
410
+ bounds : data. bounds . clone ( )
411
+ } ,
412
+ ty_a) ) )
413
+ }
414
+ ( & ty:: ty_struct( did_a, substs_a) , & ty:: ty_struct( did_b, substs_b) )
415
+ if did_a == did_b => {
416
+ debug ! ( "unsizing a struct" ) ;
417
+ // Try unsizing each type param in turn to see if we end up with ty_b.
418
+ let ty_substs_a = substs_a. types . get_slice ( subst:: TypeSpace ) ;
419
+ let ty_substs_b = substs_b. types . get_slice ( subst:: TypeSpace ) ;
420
+ assert ! ( ty_substs_a. len( ) == ty_substs_b. len( ) ) ;
421
+
422
+ let mut result = None ;
423
+ let tps = ty_substs_a. iter ( ) . zip ( ty_substs_b. iter ( ) ) . enumerate ( ) ;
424
+ for ( i, ( tp_a, tp_b) ) in tps {
425
+ if self . fcx . infcx ( ) . try ( |_| self . subtype ( * tp_a, * tp_b) ) . is_ok ( ) {
426
+ continue ;
427
+ }
428
+ match self . unsize_ty ( * tp_a, * tp_b) {
429
+ Some ( ( new_tp, k) ) => {
430
+ // Check that the whole types match.
431
+ let mut new_substs = substs_a. clone ( ) ;
432
+ new_substs. types . get_mut_slice ( subst:: TypeSpace ) [ i] = new_tp;
433
+ let ty = ty:: mk_struct ( tcx, did_a, tcx. mk_substs ( new_substs) ) ;
434
+ if self . fcx . infcx ( ) . try ( |_| self . subtype ( ty, ty_b) ) . is_err ( ) {
435
+ debug ! ( "Unsized type parameter '{}', but still \
436
+ could not match types {} and {}",
437
+ ppaux:: ty_to_string( tcx, * tp_a) ,
438
+ ppaux:: ty_to_string( tcx, ty) ,
439
+ ppaux:: ty_to_string( tcx, ty_b) ) ;
440
+ // We can only unsize a single type parameter, so
441
+ // if we unsize one and it doesn't give us the
442
+ // type we want, then we won't succeed later.
443
+ break ;
444
+ }
445
+
446
+ result = Some ( ( ty, ty:: UnsizeStruct ( box k, i) ) ) ;
428
447
break ;
429
448
}
430
-
431
- result = Some ( ( ty, ty:: UnsizeStruct ( box k, i) ) ) ;
432
- break ;
449
+ None => { }
433
450
}
434
- None => { }
435
451
}
452
+ result
436
453
}
437
- result
454
+ _ => None
438
455
}
439
- _ => None
440
- }
456
+ } )
441
457
} )
442
458
}
443
459
0 commit comments