From 3dc5b4ad326ae5ad522b0e78a15be8ec4f3da215 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Jun 2025 02:00:39 +0000 Subject: [PATCH 1/2] Shallowly bail from coerce_unsized more --- compiler/rustc_hir_typeck/src/coercion.rs | 31 +++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 24092c01125fc..acad255062afc 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -515,11 +515,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// /// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions) #[instrument(skip(self), level = "debug")] - fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { - source = self.shallow_resolve(source); - target = self.shallow_resolve(target); - debug!(?source, ?target); - + fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> { // We don't apply any coercions incase either the source or target // aren't sufficiently well known but tend to instead just equate // them both. @@ -532,6 +528,31 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } + // These targets are known to never be RHS in `LHS: CoerceUnsized`. + // That's because these are built-in types for which a core-provided impl + // doesn't exist, and for which a user-written impl is invalid. + match target.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Tuple(_) => return Err(TypeError::Mismatch), + _ => {} + } + let traits = (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait()); let (Some(unsize_did), Some(coerce_unsized_did)) = traits else { From 3d115acf976ffa4a2d461144280e606089b5f028 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Jun 2025 16:47:25 +0000 Subject: [PATCH 2/2] Add a note and one more fast path --- compiler/rustc_hir_typeck/src/coercion.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index acad255062afc..cb8bda8d01a5a 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -531,6 +531,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // These targets are known to never be RHS in `LHS: CoerceUnsized`. // That's because these are built-in types for which a core-provided impl // doesn't exist, and for which a user-written impl is invalid. + // + // This is technically incomplete when users write impossible bounds like + // `where T: CoerceUnsized`, for example, but that trait is unstable + // and coercion is allowed to be incomplete. The only case where this matters + // is impossible bounds. match target.kind() { ty::Bool | ty::Char @@ -552,6 +557,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { | ty::Tuple(_) => return Err(TypeError::Mismatch), _ => {} } + // Additionally, we ignore `&str -> &str` coercions, which happen very + // commonly since strings are one of the most used argument types in Rust, + // we do coercions when type checking call expressions. + if let ty::Ref(_, source_pointee, ty::Mutability::Not) = *source.kind() + && source_pointee.is_str() + && let ty::Ref(_, target_pointee, ty::Mutability::Not) = *target.kind() + && target_pointee.is_str() + { + return Err(TypeError::Mismatch); + } let traits = (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait());