@@ -515,11 +515,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
515
515
///
516
516
/// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
517
517
#[ 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 > {
523
519
// We don't apply any coercions incase either the source or target
524
520
// aren't sufficiently well known but tend to instead just equate
525
521
// them both.
@@ -532,6 +528,46 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
532
528
return Err ( TypeError :: Mismatch ) ;
533
529
}
534
530
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
+
535
571
let traits =
536
572
( self . tcx . lang_items ( ) . unsize_trait ( ) , self . tcx . lang_items ( ) . coerce_unsized_trait ( ) ) ;
537
573
let ( Some ( unsize_did) , Some ( coerce_unsized_did) ) = traits else {
0 commit comments