diff options
| author | bors <bors@rust-lang.org> | 2020-05-09 21:01:19 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-05-09 21:01:19 +0000 |
| commit | 0a3619c9e51a16d08cfd9a825cb89c6a49f80ffc (patch) | |
| tree | 97ca6f473890d6bac407b65247791bba850f4532 /src | |
| parent | bad3bf622bded50a97c0a54e29350eada2a3a169 (diff) | |
| parent | ff6e4ee7ad9b61d1ac1ae85fff14c4dacb66034f (diff) | |
| download | rust-0a3619c9e51a16d08cfd9a825cb89c6a49f80ffc.tar.gz rust-0a3619c9e51a16d08cfd9a825cb89c6a49f80ffc.zip | |
Auto merge of #69530 - Aaron1011:perf/skip-coerce-var, r=nikomatsakis
[perf] Skip attempting to run coerce_unsized on an inference variable See the included comment for a detailed explanation of why this is sound.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_typeck/check/coercion.rs | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 86cafa0b8ca..4ac3f2625ab 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -452,9 +452,43 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // &[T; n] or &mut [T; n] -> &[T] // or &mut [T; n] -> &mut [T] // or &Concrete -> &Trait, etc. - fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> { + fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { debug!("coerce_unsized(source={:?}, target={:?})", source, target); + source = self.shallow_resolve(source); + target = self.shallow_resolve(target); + debug!("coerce_unsized: resolved source={:?} target={:?}", source, target); + + // These 'if' statements require some explanation. + // The `CoerceUnsized` trait is special - it is only + // possible to write `impl CoerceUnsized<B> for A` where + // A and B have 'matching' fields. This rules out the following + // two types of blanket impls: + // + // `impl<T> CoerceUnsized<T> for SomeType` + // `impl<T> CoerceUnsized<SomeType> for T` + // + // Both of these trigger a special `CoerceUnsized`-related error (E0376) + // + // We can take advantage of this fact to avoid performing unecessary work. + // If either `source` or `target` is a type variable, then any applicable impl + // would need to be generic over the self-type (`impl<T> CoerceUnsized<SomeType> for T`) + // or generic over the `CoerceUnsized` type parameter (`impl<T> CoerceUnsized<T> for + // SomeType`). + // + // However, these are exactly the kinds of impls which are forbidden by + // the compiler! Therefore, we can be sure that coercion will always fail + // when either the source or target type is a type variable. This allows us + // to skip performing any trait selection, and immediately bail out. + if source.is_ty_var() { + debug!("coerce_unsized: source is a TyVar, bailing out"); + return Err(TypeError::Mismatch); + } + if target.is_ty_var() { + debug!("coerce_unsized: target is a TyVar, bailing out"); + return Err(TypeError::Mismatch); + } + let traits = (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait()); let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { |
