@@ -534,9 +534,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
534
534
return Err ( TypeError :: Mismatch ) ;
535
535
}
536
536
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
+ //
537
541
// These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
538
542
// That's because these are built-in types for which a core-provided impl
539
543
// 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.
540
553
match target. kind ( ) {
541
554
ty:: Bool
542
555
| ty:: Char
@@ -558,6 +571,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
558
571
| ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
559
572
_ => { }
560
573
}
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
+ }
561
584
562
585
let traits =
563
586
( self . tcx . lang_items ( ) . unsize_trait ( ) , self . tcx . lang_items ( ) . coerce_unsized_trait ( ) ) ;
0 commit comments