@@ -114,6 +114,26 @@ fn success<'tcx>(
114114 Ok ( InferOk { value : ( adj, target) , obligations } )
115115}
116116
117+ /// Data extracted from a reference (pinned or not) for coercion to a reference (pinned or not).
118+ struct CoerceMaybePinnedRef < ' tcx > {
119+ /// coercion source, must be a pinned (i.e. `Pin<&T>` or `Pin<&mut T>`) or normal reference (`&T` or `&mut T`)
120+ a : Ty < ' tcx > ,
121+ /// coercion target, must be a pinned (i.e. `Pin<&T>` or `Pin<&mut T>`) or normal reference (`&T` or `&mut T`)
122+ b : Ty < ' tcx > ,
123+ /// referent type of the source
124+ a_ty : Ty < ' tcx > ,
125+ /// pinnedness of the source
126+ a_pin : ty:: Pinnedness ,
127+ /// mutability of the source
128+ a_mut : ty:: Mutability ,
129+ /// region of the source
130+ a_r : ty:: Region < ' tcx > ,
131+ /// pinnedness of the target
132+ b_pin : ty:: Pinnedness ,
133+ /// mutability of the target
134+ b_mut : ty:: Mutability ,
135+ }
136+
117137/// Whether to force a leak check to occur in `Coerce::unify_raw`.
118138/// Note that leak checks may still occur evn with `ForceLeakCheck::No`.
119139///
@@ -269,21 +289,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
269289 return self . coerce_to_raw_ptr ( a, b, b_mutbl) ;
270290 }
271291 ty:: Ref ( r_b, _, mutbl_b) => {
272- if self . tcx . features ( ) . pin_ergonomics ( )
273- && let Ok ( pin_coerce) =
274- self . commit_if_ok ( |_| self . coerce_pin_ref_to_ref ( a, b, mutbl_b) )
275- {
276- return Ok ( pin_coerce) ;
292+ if let Some ( pin_ref_to_ref) = self . maybe_pin_ref_to_ref ( a, b) {
293+ return self . coerce_pin_ref_to_ref ( pin_ref_to_ref) ;
277294 }
278295 return self . coerce_to_ref ( a, b, r_b, mutbl_b) ;
279296 }
280- _ if self . tcx . features ( ) . pin_ergonomics ( )
281- && let Some ( ( _, ty:: Pinnedness :: Pinned , mut_b, _) ) = b. maybe_pinned_ref ( ) =>
282- {
283- let pin_coerce = self . commit_if_ok ( |_| self . coerce_to_pin_ref ( a, b, mut_b) ) ;
284- if pin_coerce. is_ok ( ) {
285- return pin_coerce;
286- }
297+ _ if let Some ( to_pin_ref) = self . maybe_to_pin_ref ( a, b) => {
298+ return self . coerce_to_pin_ref ( to_pin_ref) ;
287299 }
288300 _ => { }
289301 }
@@ -805,37 +817,62 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
805817 PredicateObligation :: new ( self . tcx , self . cause . clone ( ) , self . param_env , pred)
806818 }
807819
820+ /// Checks if the given types are compatible for coercion to a pinned reference.
821+ fn maybe_pin_ref_to_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> Option < CoerceMaybePinnedRef < ' tcx > > {
822+ if !self . tcx . features ( ) . pin_ergonomics ( ) {
823+ return None ;
824+ }
825+ if let Some ( ( a_ty, a_pin @ ty:: Pinnedness :: Pinned , a_mut, a_r) ) = a. maybe_pinned_ref ( )
826+ && let Some ( ( _, b_pin @ ty:: Pinnedness :: Not , b_mut, _) ) = b. maybe_pinned_ref ( )
827+ {
828+ return Some ( CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut } ) ;
829+ }
830+ debug ! ( "not fitting pinned ref to ref coercion (`{:?}` -> `{:?}`)" , a, b) ;
831+ None
832+ }
833+
808834 /// Coerces from a pinned reference to a normal reference.
809835 #[ instrument( skip( self ) , level = "trace" ) ]
810836 fn coerce_pin_ref_to_ref (
811837 & self ,
812- a : Ty < ' tcx > ,
813- b : Ty < ' tcx > ,
814- mut_b : hir :: Mutability ,
838+ CoerceMaybePinnedRef { a , b , a_ty , a_pin , a_mut , a_r , b_pin , b_mut } : CoerceMaybePinnedRef <
839+ ' tcx ,
840+ > ,
815841 ) -> CoerceResult < ' tcx > {
816842 debug_assert ! ( self . shallow_resolve( a) == a) ;
817843 debug_assert ! ( self . shallow_resolve( b) == b) ;
818844 debug_assert ! ( self . tcx. features( ) . pin_ergonomics( ) ) ;
845+ debug_assert_eq ! ( a_pin, ty:: Pinnedness :: Pinned ) ;
846+ debug_assert_eq ! ( b_pin, ty:: Pinnedness :: Not ) ;
819847
820- let Some ( ( a_ty, ty:: Pinnedness :: Pinned , mut_a, r_a) ) = a. maybe_pinned_ref ( ) else {
821- debug ! ( "not fitting pinned ref to ref coercion (`{:?}` -> `{:?}`)" , a, b) ;
822- return Err ( TypeError :: Mismatch ) ;
823- } ;
824-
825- coerce_mutbls ( mut_a, mut_b) ?;
848+ coerce_mutbls ( a_mut, b_mut) ?;
826849
827- let a = Ty :: new_ref ( self . tcx , r_a , a_ty, mut_b ) ;
850+ let a = Ty :: new_ref ( self . tcx , a_r , a_ty, b_mut ) ;
828851 let mut coerce = self . unify_and (
829852 a,
830853 b,
831854 [ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Pin ) , target : a_ty } ] ,
832- Adjust :: Borrow ( AutoBorrow :: Ref ( AutoBorrowMutability :: new ( mut_b , self . allow_two_phase ) ) ) ,
855+ Adjust :: Borrow ( AutoBorrow :: Ref ( AutoBorrowMutability :: new ( b_mut , self . allow_two_phase ) ) ) ,
833856 ForceLeakCheck :: No ,
834857 ) ?;
835858 coerce. obligations . push ( self . unpin_obligation ( a_ty) ) ;
836859 Ok ( coerce)
837860 }
838861
862+ /// Checks if the given types are compatible for coercion to a pinned reference.
863+ fn maybe_to_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> Option < CoerceMaybePinnedRef < ' tcx > > {
864+ if !self . tcx . features ( ) . pin_ergonomics ( ) {
865+ return None ;
866+ }
867+ if let Some ( ( a_ty, a_pin, a_mut, a_r) ) = a. maybe_pinned_ref ( )
868+ && let Some ( ( _, b_pin @ ty:: Pinnedness :: Pinned , b_mut, _) ) = b. maybe_pinned_ref ( )
869+ {
870+ return Some ( CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut } ) ;
871+ }
872+ debug ! ( "not fitting ref to pinned ref coercion (`{:?}` -> `{:?}`)" , a, b) ;
873+ None
874+ }
875+
839876 /// Applies reborrowing and auto-borrowing that results to `Pin<&T>` or `Pin<&mut T>`:
840877 ///
841878 /// Currently we only support the following coercions:
@@ -851,42 +888,35 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
851888 #[ instrument( skip( self ) , level = "trace" ) ]
852889 fn coerce_to_pin_ref (
853890 & self ,
854- a : Ty < ' tcx > ,
855- b : Ty < ' tcx > ,
856- mut_b : hir :: Mutability ,
891+ CoerceMaybePinnedRef { a , b , a_ty , a_pin , a_mut , a_r , b_pin , b_mut } : CoerceMaybePinnedRef <
892+ ' tcx ,
893+ > ,
857894 ) -> CoerceResult < ' tcx > {
858895 debug_assert ! ( self . shallow_resolve( a) == a) ;
859896 debug_assert ! ( self . shallow_resolve( b) == b) ;
860897 debug_assert ! ( self . tcx. features( ) . pin_ergonomics( ) ) ;
898+ debug_assert_eq ! ( b_pin, ty:: Pinnedness :: Pinned ) ;
861899
862900 // We need to deref the reference first before we reborrow it to a pinned reference.
863- let ( deref, a_ty , mut_a , r_a , unpin_obligation) = match a . maybe_pinned_ref ( ) {
901+ let ( deref, unpin_obligation) = match a_pin {
864902 // no `Unpin` required when reborrowing a pinned reference to a pinned reference
865- Some ( ( a_ty, ty:: Pinnedness :: Pinned , mut_a, r_a) ) => {
866- ( DerefAdjustKind :: Pin , a_ty, mut_a, r_a, None )
867- }
903+ ty:: Pinnedness :: Pinned => ( DerefAdjustKind :: Pin , None ) ,
868904 // `Unpin` required when reborrowing a non-pinned reference to a pinned reference
869- Some ( ( a_ty, ty:: Pinnedness :: Not , mut_a, r_a) ) => {
870- ( DerefAdjustKind :: Builtin , a_ty, mut_a, r_a, Some ( self . unpin_obligation ( a_ty) ) )
871- }
872- None => {
873- debug ! ( "can't reborrow {:?} as pinned" , a) ;
874- return Err ( TypeError :: Mismatch ) ;
875- }
905+ ty:: Pinnedness :: Not => ( DerefAdjustKind :: Builtin , Some ( self . unpin_obligation ( a_ty) ) ) ,
876906 } ;
877907
878- coerce_mutbls ( mut_a , mut_b ) ?;
908+ coerce_mutbls ( a_mut , b_mut ) ?;
879909
880910 // update a with b's mutability since we'll be coercing mutability
881- let a = Ty :: new_pinned_ref ( self . tcx , r_a , a_ty, mut_b ) ;
911+ let a = Ty :: new_pinned_ref ( self . tcx , a_r , a_ty, b_mut ) ;
882912
883913 // To complete the reborrow, we need to make sure we can unify the inner types, and if so we
884914 // add the adjustments.
885915 let mut coerce = self . unify_and (
886916 a,
887917 b,
888918 [ Adjustment { kind : Adjust :: Deref ( deref) , target : a_ty } ] ,
889- Adjust :: Borrow ( AutoBorrow :: Pin ( mut_b ) ) ,
919+ Adjust :: Borrow ( AutoBorrow :: Pin ( b_mut ) ) ,
890920 ForceLeakCheck :: No ,
891921 ) ?;
892922
0 commit comments