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