@@ -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,16 +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) => {
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) ;
294+ }
272295 return self . coerce_to_ref ( a, b, r_b, mutbl_b) ;
273296 }
274- ty:: Adt ( pin, _)
275- if self . tcx . features ( ) . pin_ergonomics ( )
276- && self . tcx . is_lang_item ( pin. did ( ) , hir:: LangItem :: Pin ) =>
277- {
278- let pin_coerce = self . commit_if_ok ( |_| self . coerce_to_pin_ref ( a, b) ) ;
279- if pin_coerce. is_ok ( ) {
280- return pin_coerce;
281- }
297+ _ if let Some ( to_pin_ref) = self . maybe_to_pin_ref ( a, b) => {
298+ return self . coerce_to_pin_ref ( to_pin_ref) ;
282299 }
283300 _ => { }
284301 }
@@ -790,61 +807,131 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
790807 Ok ( ( ) )
791808 }
792809
793- /// Applies reborrowing for `Pin`
810+ /// Create an obligation for `ty: Unpin`, where .
811+ fn unpin_obligation (
812+ & self ,
813+ source : Ty < ' tcx > ,
814+ target : Ty < ' tcx > ,
815+ ty : Ty < ' tcx > ,
816+ ) -> PredicateObligation < ' tcx > {
817+ let pred = ty:: TraitRef :: new (
818+ self . tcx ,
819+ self . tcx . require_lang_item ( hir:: LangItem :: Unpin , self . cause . span ) ,
820+ [ ty] ,
821+ ) ;
822+ let cause = self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
823+ PredicateObligation :: new ( self . tcx , cause, self . param_env , pred)
824+ }
825+
826+ /// Checks if the given types are compatible for coercion from a pinned reference to a normal reference.
827+ fn maybe_pin_ref_to_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> Option < CoerceMaybePinnedRef < ' tcx > > {
828+ if !self . tcx . features ( ) . pin_ergonomics ( ) {
829+ return None ;
830+ }
831+ if let Some ( ( a_ty, a_pin @ ty:: Pinnedness :: Pinned , a_mut, a_r) ) = a. maybe_pinned_ref ( )
832+ && let Some ( ( _, b_pin @ ty:: Pinnedness :: Not , b_mut, _) ) = b. maybe_pinned_ref ( )
833+ {
834+ return Some ( CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut } ) ;
835+ }
836+ debug ! ( "not fitting pinned ref to ref coercion (`{:?}` -> `{:?}`)" , a, b) ;
837+ None
838+ }
839+
840+ /// Coerces from a pinned reference to a normal reference.
841+ #[ instrument( skip( self ) , level = "trace" ) ]
842+ fn coerce_pin_ref_to_ref (
843+ & self ,
844+ CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut } : CoerceMaybePinnedRef <
845+ ' tcx ,
846+ > ,
847+ ) -> CoerceResult < ' tcx > {
848+ debug_assert ! ( self . shallow_resolve( a) == a) ;
849+ debug_assert ! ( self . shallow_resolve( b) == b) ;
850+ debug_assert ! ( self . tcx. features( ) . pin_ergonomics( ) ) ;
851+ debug_assert_eq ! ( a_pin, ty:: Pinnedness :: Pinned ) ;
852+ debug_assert_eq ! ( b_pin, ty:: Pinnedness :: Not ) ;
853+
854+ coerce_mutbls ( a_mut, b_mut) ?;
855+
856+ let unpin_obligation = self . unpin_obligation ( a, b, a_ty) ;
857+
858+ let a = Ty :: new_ref ( self . tcx , a_r, a_ty, b_mut) ;
859+ let mut coerce = self . unify_and (
860+ a,
861+ b,
862+ [ Adjustment { kind : Adjust :: Deref ( DerefAdjustKind :: Pin ) , target : a_ty } ] ,
863+ Adjust :: Borrow ( AutoBorrow :: Ref ( AutoBorrowMutability :: new ( b_mut, self . allow_two_phase ) ) ) ,
864+ ForceLeakCheck :: No ,
865+ ) ?;
866+ coerce. obligations . push ( unpin_obligation) ;
867+ Ok ( coerce)
868+ }
869+
870+ /// Checks if the given types are compatible for coercion to a pinned reference.
871+ fn maybe_to_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> Option < CoerceMaybePinnedRef < ' tcx > > {
872+ if !self . tcx . features ( ) . pin_ergonomics ( ) {
873+ return None ;
874+ }
875+ if let Some ( ( a_ty, a_pin, a_mut, a_r) ) = a. maybe_pinned_ref ( )
876+ && let Some ( ( _, b_pin @ ty:: Pinnedness :: Pinned , b_mut, _) ) = b. maybe_pinned_ref ( )
877+ {
878+ return Some ( CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut } ) ;
879+ }
880+ debug ! ( "not fitting ref to pinned ref coercion (`{:?}` -> `{:?}`)" , a, b) ;
881+ None
882+ }
883+
884+ /// Applies reborrowing and auto-borrowing that results to `Pin<&T>` or `Pin<&mut T>`:
794885 ///
795- /// We currently only support reborrowing `Pin<&mut T>` as `Pin<&mut T>`. This is accomplished
796- /// by inserting a call to `Pin::as_mut` during MIR building.
886+ /// Currently we only support the following coercions:
887+ /// - Reborrowing `Pin<&mut T>` -> `Pin<&mut T>`
888+ /// - Reborrowing `Pin<&T>` -> `Pin<&T>`
889+ /// - Auto-borrowing `&mut T` -> `Pin<&mut T>` where `T: Unpin`
890+ /// - Auto-borrowing `&mut T` -> `Pin<&T>` where `T: Unpin`
891+ /// - Auto-borrowing `&T` -> `Pin<&T>` where `T: Unpin`
797892 ///
798893 /// In the future we might want to support other reborrowing coercions, such as:
799- /// - `Pin<&mut T>` as `Pin<&T>`
800- /// - `Pin<&T>` as `Pin<&T>`
801894 /// - `Pin<Box<T>>` as `Pin<&T>`
802895 /// - `Pin<Box<T>>` as `Pin<&mut T>`
803896 #[ instrument( skip( self ) , level = "trace" ) ]
804- fn coerce_to_pin_ref ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> CoerceResult < ' tcx > {
897+ fn coerce_to_pin_ref (
898+ & self ,
899+ CoerceMaybePinnedRef { a, b, a_ty, a_pin, a_mut, a_r, b_pin, b_mut } : CoerceMaybePinnedRef <
900+ ' tcx ,
901+ > ,
902+ ) -> CoerceResult < ' tcx > {
805903 debug_assert ! ( self . shallow_resolve( a) == a) ;
806904 debug_assert ! ( self . shallow_resolve( b) == b) ;
807-
808- // We need to make sure the two types are compatible for coercion.
809- // Then we will build a ReborrowPin adjustment and return that as an InferOk.
810-
811- // Right now we can only reborrow if this is a `Pin<&mut T>`.
812- let extract_pin_mut = |ty : Ty < ' tcx > | {
813- // Get the T out of Pin<T>
814- let ( pin, ty) = match ty. kind ( ) {
815- ty:: Adt ( pin, args) if self . tcx . is_lang_item ( pin. did ( ) , hir:: LangItem :: Pin ) => {
816- ( * pin, args[ 0 ] . expect_ty ( ) )
817- }
818- _ => {
819- debug ! ( "can't reborrow {:?} as pinned" , ty) ;
820- return Err ( TypeError :: Mismatch ) ;
821- }
822- } ;
823- // Make sure the T is something we understand (just `&mut U` for now)
824- match ty. kind ( ) {
825- ty:: Ref ( region, ty, mutbl) => Ok ( ( pin, * region, * ty, * mutbl) ) ,
826- _ => {
827- debug ! ( "can't reborrow pin of inner type {:?}" , ty) ;
828- Err ( TypeError :: Mismatch )
829- }
905+ debug_assert ! ( self . tcx. features( ) . pin_ergonomics( ) ) ;
906+ debug_assert_eq ! ( b_pin, ty:: Pinnedness :: Pinned ) ;
907+
908+ // We need to deref the reference first before we reborrow it to a pinned reference.
909+ let ( deref, unpin_obligation) = match a_pin {
910+ // no `Unpin` required when reborrowing a pinned reference to a pinned reference
911+ ty:: Pinnedness :: Pinned => ( DerefAdjustKind :: Pin , None ) ,
912+ // `Unpin` required when reborrowing a non-pinned reference to a pinned reference
913+ ty:: Pinnedness :: Not => {
914+ ( DerefAdjustKind :: Builtin , Some ( self . unpin_obligation ( a, b, a_ty) ) )
830915 }
831916 } ;
832917
833- let ( pin, a_region, a_ty, mut_a) = extract_pin_mut ( a) ?;
834- let ( _, _, _b_ty, mut_b) = extract_pin_mut ( b) ?;
835-
836- coerce_mutbls ( mut_a, mut_b) ?;
918+ coerce_mutbls ( a_mut, b_mut) ?;
837919
838920 // update a with b's mutability since we'll be coercing mutability
839- let a = Ty :: new_adt (
840- self . tcx ,
841- pin,
842- self . tcx . mk_args ( & [ Ty :: new_ref ( self . tcx , a_region, a_ty, mut_b) . into ( ) ] ) ,
843- ) ;
921+ let a = Ty :: new_pinned_ref ( self . tcx , a_r, a_ty, b_mut) ;
844922
845923 // To complete the reborrow, we need to make sure we can unify the inner types, and if so we
846924 // add the adjustments.
847- self . unify_and ( a, b, [ ] , Adjust :: ReborrowPin ( mut_b) , ForceLeakCheck :: No )
925+ let mut coerce = self . unify_and (
926+ a,
927+ b,
928+ [ Adjustment { kind : Adjust :: Deref ( deref) , target : a_ty } ] ,
929+ Adjust :: Borrow ( AutoBorrow :: Pin ( b_mut) ) ,
930+ ForceLeakCheck :: No ,
931+ ) ?;
932+
933+ coerce. obligations . extend ( unpin_obligation) ;
934+ Ok ( coerce)
848935 }
849936
850937 fn coerce_from_fn_pointer (
0 commit comments