@@ -452,9 +452,43 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
452
452
// &[T; n] or &mut [T; n] -> &[T]
453
453
// or &mut [T; n] -> &mut [T]
454
454
// or &Concrete -> &Trait, etc.
455
- fn coerce_unsized ( & self , source : Ty < ' tcx > , target : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
455
+ fn coerce_unsized ( & self , mut source : Ty < ' tcx > , mut target : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
456
456
debug ! ( "coerce_unsized(source={:?}, target={:?})" , source, target) ;
457
457
458
+ source = self . shallow_resolve ( source) ;
459
+ target = self . shallow_resolve ( target) ;
460
+ debug ! ( "coerce_unsized: resolved source={:?} target={:?}" , source, target) ;
461
+
462
+ // These 'if' statements require some explanation.
463
+ // The `CoerceUnsized` trait is special - it is only
464
+ // possible to write `impl CoerceUnsized<B> for A` where
465
+ // A and B have 'matching' fields. This rules out the following
466
+ // two types of blanket impls:
467
+ //
468
+ // `impl<T> CoerceUnsized<T> for SomeType`
469
+ // `impl<T> CoerceUnsized<SomeType> for T`
470
+ //
471
+ // Both of these trigger a special `CoerceUnsized`-related error (E0376)
472
+ //
473
+ // We can take advantage of this fact to avoid performing unecessary work.
474
+ // If either `source` or `target` is a type variable, then any applicable impl
475
+ // would need to be generic over the self-type (`impl<T> CoerceUnsized<SomeType> for T`)
476
+ // or generic over the `CoerceUnsized` type parameter (`impl<T> CoerceUnsized<T> for
477
+ // SomeType`).
478
+ //
479
+ // However, these are exactly the kinds of impls which are forbidden by
480
+ // the compiler! Therefore, we can be sure that coercion will always fail
481
+ // when either the source or target type is a type variable. This allows us
482
+ // to skip performing any trait selection, and immediately bail out.
483
+ if source. is_ty_var ( ) {
484
+ debug ! ( "coerce_unsized: source is a TyVar, bailing out" ) ;
485
+ return Err ( TypeError :: Mismatch ) ;
486
+ }
487
+ if target. is_ty_var ( ) {
488
+ debug ! ( "coerce_unsized: target is a TyVar, bailing out" ) ;
489
+ return Err ( TypeError :: Mismatch ) ;
490
+ }
491
+
458
492
let traits =
459
493
( self . tcx . lang_items ( ) . unsize_trait ( ) , self . tcx . lang_items ( ) . coerce_unsized_trait ( ) ) ;
460
494
let ( unsize_did, coerce_unsized_did) = if let ( Some ( u) , Some ( cu) ) = traits {
0 commit comments