@@ -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 , Ty , TyCtxt , TypeVisitableExt } ;
@@ -268,12 +269,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
268269 return self . coerce_to_raw_ptr ( a, b, b_mutbl) ;
269270 }
270271 ty:: Ref ( r_b, _, mutbl_b) => {
272+ if self . tcx . features ( ) . pin_ergonomics ( )
273+ && a. pinned_ty ( ) . is_some_and ( |ty| ty. is_ref ( ) )
274+ && let Ok ( coerce) = self . commit_if_ok ( |_| self . coerce_maybe_pinned_ref ( a, b) )
275+ {
276+ return Ok ( coerce) ;
277+ }
271278 return self . coerce_to_ref ( a, b, r_b, mutbl_b) ;
272279 }
273280 ty:: Adt ( pin, _)
274281 if self . tcx . features ( ) . pin_ergonomics ( )
275282 && self . tcx . is_lang_item ( pin. did ( ) , hir:: LangItem :: Pin ) =>
276283 {
284+ if a. is_ref ( ) && b. pinned_ty ( ) . is_some_and ( |ty| ty. is_ref ( ) ) {
285+ return self . coerce_maybe_pinned_ref ( a, b) ;
286+ }
277287 let pin_coerce = self . commit_if_ok ( |_| self . coerce_to_pin_ref ( a, b) ) ;
278288 if pin_coerce. is_ok ( ) {
279289 return pin_coerce;
@@ -595,7 +605,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
595605 let mutbl = AutoBorrowMutability :: new ( mutbl_b, AllowTwoPhase :: No ) ;
596606
597607 Some ( (
598- Adjustment { kind : Adjust :: Deref ( None ) , target : ty_a } ,
608+ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : ty_a } ,
599609 Adjustment {
600610 kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
601611 target : Ty :: new_ref ( self . tcx , r_borrow, ty_a, mutbl_b) ,
@@ -606,7 +616,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
606616 coerce_mutbls ( mt_a, mt_b) ?;
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 :: RawPtr ( mt_b) ) ,
612622 target : Ty :: new_ptr ( self . tcx , ty_a, mt_b) ,
@@ -846,6 +856,62 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
846856 self . unify_and ( a, b, [ ] , Adjust :: ReborrowPin ( mut_b) , ForceLeakCheck :: No )
847857 }
848858
859+ /// Coerce pinned reference to regular reference or vice versa
860+ ///
861+ /// - `Pin<&mut T>` <-> `&mut T` when `T: Unpin`
862+ /// - `Pin<&T>` <-> `&T` when `T: Unpin`
863+ /// - `Pin<&mut T>` <-> `Pin<&T>` when `T: Unpin`
864+ #[ instrument( skip( self ) , level = "trace" ) ]
865+ fn coerce_maybe_pinned_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
866+ let span = self . cause . span ;
867+ let Some ( ( a_ty, a_pinnedness, a_mutbl, a_region) ) = a. maybe_pinned_ref ( ) else {
868+ span_bug ! ( span, "expect pinned reference or reference, found {:?}" , a) ;
869+ } ;
870+ let Some ( ( _b_ty, b_pinnedness, b_mutbl, _b_region) ) = b. maybe_pinned_ref ( ) else {
871+ span_bug ! ( span, "expect pinned reference or reference, found {:?}" , b) ;
872+ } ;
873+ use ty:: Pinnedness :: * ;
874+ if a_pinnedness == b_pinnedness {
875+ span_bug ! ( span, "expect different pinnedness, found {:?} and {:?}" , a, b) ;
876+ }
877+
878+ coerce_mutbls ( a_mutbl, b_mutbl) ?;
879+
880+ let ( deref, borrow) = match ( a_pinnedness, b_pinnedness) {
881+ ( Not , Not ) | ( Pinned , Pinned ) => {
882+ span_bug ! ( span, "expect different pinnedness, found {:?} and {:?}" , a, b)
883+ }
884+ ( Pinned , Not ) => {
885+ let mutbl = AutoBorrowMutability :: new ( b_mutbl, AllowTwoPhase :: Yes ) ;
886+ ( DerefAdjustKind :: Pin , AutoBorrow :: Ref ( mutbl) )
887+ }
888+ ( Not , Pinned ) => ( DerefAdjustKind :: Builtin , AutoBorrow :: Pin ( b_mutbl) ) ,
889+ } ;
890+ let mut coerce = self . unify_and (
891+ // update a with b's pinnedness and mutability since we'll be coercing pinnedness and mutability
892+ match b_pinnedness {
893+ Pinned => Ty :: new_pinned_ref ( self . tcx , a_region, a_ty, b_mutbl) ,
894+ Not => Ty :: new_ref ( self . tcx , a_region, a_ty, b_mutbl) ,
895+ } ,
896+ b,
897+ [ Adjustment { kind : Adjust :: Deref ( deref) , target : a_ty } ] ,
898+ Adjust :: Borrow ( borrow) ,
899+ ForceLeakCheck :: No ,
900+ ) ?;
901+
902+ // Create an obligation for `a_ty: Unpin`.
903+ let cause =
904+ self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source : a, target : b } ) ;
905+ let pred = ty:: TraitRef :: new (
906+ self . tcx ,
907+ self . tcx . require_lang_item ( hir:: LangItem :: Unpin , self . cause . span ) ,
908+ [ a_ty] ,
909+ ) ;
910+ let obligation = Obligation :: new ( self . tcx , cause, self . fcx . param_env , pred) ;
911+ coerce. obligations . push ( obligation) ;
912+ Ok ( coerce)
913+ }
914+
849915 fn coerce_from_fn_pointer (
850916 & self ,
851917 a : Ty < ' tcx > ,
@@ -936,7 +1002,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
9361002 self . unify_and (
9371003 a_raw,
9381004 b,
939- [ Adjustment { kind : Adjust :: Deref ( None ) , target : mt_a. ty } ] ,
1005+ [ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Builtin ) , target : mt_a. ty } ] ,
9401006 Adjust :: Borrow ( AutoBorrow :: RawPtr ( mutbl_b) ) ,
9411007 ForceLeakCheck :: No ,
9421008 )
0 commit comments