Skip to content

Commit 32c360b

Browse files
committed
[perf] Skip attempting to run coerce_unsized on an inference variable
See the included comment for a detailed explanation of why this is sound.
1 parent 6d69cab commit 32c360b

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

src/librustc_typeck/check/coercion.rs

+30
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)