@@ -50,7 +50,8 @@ use rustc_infer::traits::{
5050} ;
5151use rustc_middle:: span_bug;
5252use rustc_middle:: ty:: adjustment:: {
53- Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability , PointerCoercion ,
53+ Adjust , Adjustment , AllowTwoPhase , AutoBorrow , AutoBorrowMutability , DerefAdjustKind ,
54+ PointerCoercion ,
5455} ;
5556use rustc_middle:: ty:: error:: TypeError ;
5657use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt } ;
@@ -231,12 +232,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
231232 return self . coerce_raw_ptr ( a, b, b_mutbl) ;
232233 }
233234 ty:: Ref ( r_b, _, mutbl_b) => {
235+ if self . tcx . features ( ) . pin_ergonomics ( )
236+ && a. pinned_ty ( ) . is_some_and ( |ty| ty. is_ref ( ) )
237+ && let Ok ( coerce) = self . commit_if_ok ( |_| self . coerce_pin_or_ref ( a, b) )
238+ {
239+ return Ok ( coerce) ;
240+ }
234241 return self . coerce_borrowed_pointer ( a, b, r_b, mutbl_b) ;
235242 }
236243 ty:: Adt ( pin, _)
237244 if self . tcx . features ( ) . pin_ergonomics ( )
238245 && self . tcx . is_lang_item ( pin. did ( ) , hir:: LangItem :: Pin ) =>
239246 {
247+ if a. is_ref ( ) && b. pinned_ty ( ) . is_some_and ( |ty| ty. is_ref ( ) ) {
248+ return self . coerce_pin_or_ref ( a, b) ;
249+ }
240250 let pin_coerce = self . commit_if_ok ( |_| self . coerce_pin_ref ( a, b) ) ;
241251 if pin_coerce. is_ok ( ) {
242252 return pin_coerce;
@@ -606,7 +616,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
606616 let mutbl = AutoBorrowMutability :: new ( mutbl_b, AllowTwoPhase :: No ) ;
607617
608618 Some ( (
609- Adjustment { kind : Adjust :: Deref ( None ) , target : ty_a } ,
619+ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : ty_a } ,
610620 Adjustment {
611621 kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
612622 target : Ty :: new_ref ( self . tcx , r_borrow, ty_a, mutbl_b) ,
@@ -617,7 +627,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
617627 coerce_mutbls ( mt_a, mt_b) ?;
618628
619629 Some ( (
620- Adjustment { kind : Adjust :: Deref ( None ) , target : ty_a } ,
630+ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : ty_a } ,
621631 Adjustment {
622632 kind : Adjust :: Borrow ( AutoBorrow :: RawPtr ( mt_b) ) ,
623633 target : Ty :: new_ptr ( self . tcx , ty_a, mt_b) ,
@@ -856,6 +866,61 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
856866 self . unify_and ( a, b, [ ] , Adjust :: ReborrowPin ( mut_b) )
857867 }
858868
869+ /// Coerce pinned reference to regular reference or vice versa
870+ ///
871+ /// - `Pin<&mut T>` <-> `&mut T` when `T: Unpin`
872+ /// - `Pin<&T>` <-> `&T` when `T: Unpin`
873+ /// - `Pin<&mut T>` <-> `Pin<&T>` when `T: Unpin`
874+ #[ instrument( skip( self ) , level = "trace" ) ]
875+ fn coerce_pin_or_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
876+ let span = self . cause . span ;
877+ let Some ( ( a_ty, a_pinnedness, a_mutbl, a_region) ) = a. maybe_pinned_ref ( ) else {
878+ span_bug ! ( span, "expect pinned reference or reference, found {:?}" , a) ;
879+ } ;
880+ let Some ( ( _b_ty, b_pinnedness, b_mutbl, _b_region) ) = b. maybe_pinned_ref ( ) else {
881+ span_bug ! ( span, "expect pinned reference or reference, found {:?}" , b) ;
882+ } ;
883+ use ty:: Pinnedness :: * ;
884+ if a_pinnedness == b_pinnedness {
885+ span_bug ! ( span, "expect different pinnedness, found {:?} and {:?}" , a, b) ;
886+ }
887+
888+ coerce_mutbls ( a_mutbl, b_mutbl) ?;
889+
890+ let ( deref, borrow) = match ( a_pinnedness, b_pinnedness) {
891+ ( Not , Not ) | ( Pinned , Pinned ) => {
892+ span_bug ! ( span, "expect different pinnedness, found {:?} and {:?}" , a, b)
893+ }
894+ ( Pinned , Not ) => {
895+ let mutbl = AutoBorrowMutability :: new ( b_mutbl, AllowTwoPhase :: Yes ) ;
896+ ( DerefAdjustKind :: Pin , AutoBorrow :: Ref ( mutbl) )
897+ }
898+ ( Not , Pinned ) => ( DerefAdjustKind :: Builtin , AutoBorrow :: Pin ( b_mutbl) ) ,
899+ } ;
900+ let mut coerce = self . unify_and (
901+ // update a with b's pinnedness and mutability since we'll be coercing pinnedness and mutability
902+ match b_pinnedness {
903+ Pinned => Ty :: new_pinned_ref ( self . tcx , a_region, a_ty, b_mutbl) ,
904+ Not => Ty :: new_ref ( self . tcx , a_region, a_ty, b_mutbl) ,
905+ } ,
906+ b,
907+ [ Adjustment { kind : Adjust :: Deref ( deref) , target : a_ty } ] ,
908+ Adjust :: Borrow ( borrow) ,
909+ ) ?;
910+
911+ // Create an obligation for `a_ty: Unpin`.
912+ let cause =
913+ self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source : a, target : b } ) ;
914+ let pred = ty:: TraitRef :: new (
915+ self . tcx ,
916+ self . tcx . require_lang_item ( hir:: LangItem :: Unpin , self . cause . span ) ,
917+ [ a_ty] ,
918+ ) ;
919+ let obligation = Obligation :: new ( self . tcx , cause, self . fcx . param_env , pred) ;
920+ coerce. obligations . push ( obligation) ;
921+ Ok ( coerce)
922+ }
923+
859924 fn coerce_from_safe_fn (
860925 & self ,
861926 fn_ty_a : ty:: PolyFnSig < ' tcx > ,
@@ -1039,7 +1104,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
10391104 self . unify_and (
10401105 a_raw,
10411106 b,
1042- [ Adjustment { kind : Adjust :: Deref ( None ) , target : mt_a. ty } ] ,
1107+ [ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : mt_a. ty } ] ,
10431108 Adjust :: Borrow ( AutoBorrow :: RawPtr ( mutbl_b) ) ,
10441109 )
10451110 } else if mt_a. mutbl != mutbl_b {
0 commit comments