@@ -278,8 +278,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
278
278
/// fall back to subtyping (`unify_and`).
279
279
fn coerce_from_inference_variable ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
280
280
debug ! ( "coerce_from_inference_variable(a={:?}, b={:?})" , a, b) ;
281
- assert ! ( a. is_ty_var( ) && self . shallow_resolve( a) == a) ;
282
- assert ! ( self . shallow_resolve( b) == b) ;
281
+ debug_assert ! ( a. is_ty_var( ) && self . shallow_resolve( a) == a) ;
282
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
283
283
284
284
if b. is_ty_var ( ) {
285
285
// Two unresolved type variables: create a `Coerce` predicate.
@@ -323,6 +323,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
323
323
mutbl_b : hir:: Mutability ,
324
324
) -> CoerceResult < ' tcx > {
325
325
debug ! ( "coerce_borrowed_pointer(a={:?}, b={:?})" , a, b) ;
326
+ debug_assert ! ( self . shallow_resolve( a) == a) ;
327
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
326
328
327
329
// If we have a parameter of type `&M T_a` and the value
328
330
// provided is `expr`, we will be adding an implicit borrow,
@@ -514,10 +516,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
514
516
///
515
517
/// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
516
518
#[ instrument( skip( self ) , level = "debug" ) ]
517
- fn coerce_unsized ( & self , mut source : Ty < ' tcx > , mut target : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
518
- source = self . shallow_resolve ( source) ;
519
- target = self . shallow_resolve ( target) ;
519
+ fn coerce_unsized ( & self , source : Ty < ' tcx > , target : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
520
520
debug ! ( ?source, ?target) ;
521
+ debug_assert ! ( self . shallow_resolve( source) == source) ;
522
+ debug_assert ! ( self . shallow_resolve( target) == target) ;
521
523
522
524
// We don't apply any coercions incase either the source or target
523
525
// aren't sufficiently well known but tend to instead just equate
@@ -531,6 +533,54 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
531
533
return Err ( TypeError :: Mismatch ) ;
532
534
}
533
535
536
+ // This is an optimization because coercion is one of the most common
537
+ // operations that we do in typeck, since it happens at every assignment
538
+ // and call arg (among other positions).
539
+ //
540
+ // These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
541
+ // That's because these are built-in types for which a core-provided impl
542
+ // doesn't exist, and for which a user-written impl is invalid.
543
+ //
544
+ // This is technically incomplete when users write impossible bounds like
545
+ // `where T: CoerceUnsized<usize>`, for example, but that trait is unstable
546
+ // and coercion is allowed to be incomplete. The only case where this matters
547
+ // is impossible bounds.
548
+ //
549
+ // Note that some of these types implement `LHS: Unsize<RHS>`, but they
550
+ // do not implement *`CoerceUnsized`* which is the root obligation of the
551
+ // check below.
552
+ match target. kind ( ) {
553
+ ty:: Bool
554
+ | ty:: Char
555
+ | ty:: Int ( _)
556
+ | ty:: Uint ( _)
557
+ | ty:: Float ( _)
558
+ | ty:: Infer ( ty:: IntVar ( _) | ty:: FloatVar ( _) )
559
+ | ty:: Str
560
+ | ty:: Array ( _, _)
561
+ | ty:: Slice ( _)
562
+ | ty:: FnDef ( _, _)
563
+ | ty:: FnPtr ( _, _)
564
+ | ty:: Dynamic ( _, _, _)
565
+ | ty:: Closure ( _, _)
566
+ | ty:: CoroutineClosure ( _, _)
567
+ | ty:: Coroutine ( _, _)
568
+ | ty:: CoroutineWitness ( _, _)
569
+ | ty:: Never
570
+ | ty:: Tuple ( _) => return Err ( TypeError :: Mismatch ) ,
571
+ _ => { }
572
+ }
573
+ // Additionally, we ignore `&str -> &str` coercions, which happen very
574
+ // commonly since strings are one of the most used argument types in Rust,
575
+ // we do coercions when type checking call expressions.
576
+ if let ty:: Ref ( _, source_pointee, ty:: Mutability :: Not ) = * source. kind ( )
577
+ && source_pointee. is_str ( )
578
+ && let ty:: Ref ( _, target_pointee, ty:: Mutability :: Not ) = * target. kind ( )
579
+ && target_pointee. is_str ( )
580
+ {
581
+ return Err ( TypeError :: Mismatch ) ;
582
+ }
583
+
534
584
let traits =
535
585
( self . tcx . lang_items ( ) . unsize_trait ( ) , self . tcx . lang_items ( ) . coerce_unsized_trait ( ) ) ;
536
586
let ( Some ( unsize_did) , Some ( coerce_unsized_did) ) = traits else {
@@ -800,6 +850,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
800
850
/// - `Pin<Box<T>>` as `Pin<&mut T>`
801
851
#[ instrument( skip( self ) , level = "trace" ) ]
802
852
fn coerce_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
853
+ debug_assert ! ( self . shallow_resolve( a) == a) ;
854
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
855
+
803
856
// We need to make sure the two types are compatible for coercion.
804
857
// Then we will build a ReborrowPin adjustment and return that as an InferOk.
805
858
@@ -848,6 +901,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
848
901
b : Ty < ' tcx > ,
849
902
adjustment : Option < Adjust > ,
850
903
) -> CoerceResult < ' tcx > {
904
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
905
+
851
906
self . commit_if_ok ( |snapshot| {
852
907
let outer_universe = self . infcx . universe ( ) ;
853
908
@@ -888,24 +943,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
888
943
fn_ty_a : ty:: PolyFnSig < ' tcx > ,
889
944
b : Ty < ' tcx > ,
890
945
) -> CoerceResult < ' tcx > {
891
- //! Attempts to coerce from the type of a Rust function item
892
- //! into a closure or a `proc`.
893
- //!
894
-
895
- let b = self . shallow_resolve ( b) ;
896
946
debug ! ( ?fn_ty_a, ?b, "coerce_from_fn_pointer" ) ;
947
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
897
948
898
949
self . coerce_from_safe_fn ( fn_ty_a, b, None )
899
950
}
900
951
901
952
fn coerce_from_fn_item ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
902
- //! Attempts to coerce from the type of a Rust function item
903
- //! into a closure or a `proc`.
953
+ debug ! ( "coerce_from_fn_item(a={:?}, b={:?})" , a, b) ;
954
+ debug_assert ! ( self . shallow_resolve( a) == a) ;
955
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
904
956
905
- let b = self . shallow_resolve ( b) ;
906
957
let InferOk { value : b, mut obligations } =
907
958
self . at ( & self . cause , self . param_env ) . normalize ( b) ;
908
- debug ! ( "coerce_from_fn_item(a={:?}, b={:?})" , a, b) ;
909
959
910
960
match b. kind ( ) {
911
961
ty:: FnPtr ( _, b_hdr) => {
@@ -955,18 +1005,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
955
1005
}
956
1006
}
957
1007
1008
+ /// Attempts to coerce from the type of a non-capturing closure
1009
+ /// into a function pointer.
958
1010
fn coerce_closure_to_fn (
959
1011
& self ,
960
1012
a : Ty < ' tcx > ,
961
1013
closure_def_id_a : DefId ,
962
1014
args_a : GenericArgsRef < ' tcx > ,
963
1015
b : Ty < ' tcx > ,
964
1016
) -> CoerceResult < ' tcx > {
965
- //! Attempts to coerce from the type of a non-capturing closure
966
- //! into a function pointer.
967
- //!
968
-
969
- let b = self . shallow_resolve ( b) ;
1017
+ debug_assert ! ( self . shallow_resolve( a) == a) ;
1018
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
970
1019
971
1020
match b. kind ( ) {
972
1021
// At this point we haven't done capture analysis, which means
@@ -1010,6 +1059,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
1010
1059
mutbl_b : hir:: Mutability ,
1011
1060
) -> CoerceResult < ' tcx > {
1012
1061
debug ! ( "coerce_raw_ptr(a={:?}, b={:?})" , a, b) ;
1062
+ debug_assert ! ( self . shallow_resolve( a) == a) ;
1063
+ debug_assert ! ( self . shallow_resolve( b) == b) ;
1013
1064
1014
1065
let ( is_ref, mt_a) = match * a. kind ( ) {
1015
1066
ty:: Ref ( _, ty, mutbl) => ( true , ty:: TypeAndMut { ty, mutbl } ) ,
0 commit comments