@@ -515,11 +515,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
515515 ///
516516 /// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
517517 #[ instrument( skip( self ) , level = "debug" ) ]
518- fn coerce_unsized ( & self , mut source : Ty < ' tcx > , mut target : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
519- source = self . shallow_resolve ( source) ;
520- target = self . shallow_resolve ( target) ;
521- debug ! ( ?source, ?target) ;
522-
518+ fn coerce_unsized ( & self , source : Ty < ' tcx > , target : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
523519 // We don't apply any coercions incase either the source or target
524520 // aren't sufficiently well known but tend to instead just equate
525521 // them both.
@@ -532,6 +528,46 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
532528 return Err ( TypeError :: Mismatch ) ;
533529 }
534530
531+ // These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
532+ // That's because these are built-in types for which a core-provided impl
533+ // doesn't exist, and for which a user-written impl is invalid.
534+ //
535+ // This is technically incomplete when users write impossible bounds like
536+ // `where T: CoerceUnsized<usize>`, for example, but that trait is unstable
537+ // and coercion is allowed to be incomplete. The only case where this matters
538+ // is impossible bounds.
539+ match target. kind ( ) {
540+ ty:: Bool
541+ | ty:: Char
542+ | ty:: Int ( _)
543+ | ty:: Uint ( _)
544+ | ty:: Float ( _)
545+ | ty:: Infer ( ty:: IntVar ( _) | ty:: FloatVar ( _) )
546+ | ty:: Str
547+ | ty:: Array ( _, _)
548+ | ty:: Slice ( _)
549+ | ty:: FnDef ( _, _)
550+ | ty:: FnPtr ( _, _)
551+ | ty:: Dynamic ( _, _, _)
552+ | ty:: Closure ( _, _)
553+ | ty:: CoroutineClosure ( _, _)
554+ | ty:: Coroutine ( _, _)
555+ | ty:: CoroutineWitness ( _, _)
556+ | ty:: Never
557+ | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
558+ _ => { }
559+ }
560+ // Additionally, we ignore `&str -> &str` coercions, which happen very
561+ // commonly since strings are one of the most used argument types in Rust,
562+ // we do coercions when type checking call expressions.
563+ if let ty:: Ref ( _, source_pointee, ty:: Mutability :: Not ) = * source. kind ( )
564+ && source_pointee. is_str ( )
565+ && let ty:: Ref ( _, target_pointee, ty:: Mutability :: Not ) = * target. kind ( )
566+ && target_pointee. is_str ( )
567+ {
568+ return Err ( TypeError :: Mismatch ) ;
569+ }
570+
535571 let traits =
536572 ( self . tcx . lang_items ( ) . unsize_trait ( ) , self . tcx . lang_items ( ) . coerce_unsized_trait ( ) ) ;
537573 let ( Some ( unsize_did) , Some ( coerce_unsized_did) ) = traits else {
0 commit comments