@@ -534,9 +534,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
534534 return Err ( TypeError :: Mismatch ) ;
535535 }
536536
537+ // This is an optimization because coercion is one of the most common
538+ // operations that we do in typeck, since it happens at every assignment
539+ // and call arg (among other positions).
540+ //
537541 // These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
538542 // That's because these are built-in types for which a core-provided impl
539543 // doesn't exist, and for which a user-written impl is invalid.
544+ //
545+ // This is technically incomplete when users write impossible bounds like
546+ // `where T: CoerceUnsized<usize>`, for example, but that trait is unstable
547+ // and coercion is allowed to be incomplete. The only case where this matters
548+ // is impossible bounds.
549+ //
550+ // Note that some of these types implement `LHS: Unsize<RHS>`, but they
551+ // do not implement *`CoerceUnsized`* which is the root obligation of the
552+ // check below.
540553 match target. kind ( ) {
541554 ty:: Bool
542555 | ty:: Char
@@ -558,6 +571,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
558571 | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
559572 _ => { }
560573 }
574+ // Additionally, we ignore `&str -> &str` coercions, which happen very
575+ // commonly since strings are one of the most used argument types in Rust,
576+ // we do coercions when type checking call expressions.
577+ if let ty:: Ref ( _, source_pointee, ty:: Mutability :: Not ) = * source. kind ( )
578+ && source_pointee. is_str ( )
579+ && let ty:: Ref ( _, target_pointee, ty:: Mutability :: Not ) = * target. kind ( )
580+ && target_pointee. is_str ( )
581+ {
582+ return Err ( TypeError :: Mismatch ) ;
583+ }
561584
562585 let traits =
563586 ( self . tcx . lang_items ( ) . unsize_trait ( ) , self . tcx . lang_items ( ) . coerce_unsized_trait ( ) ) ;
0 commit comments