diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 5fe5f0b13e54..bfc677046e0f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -807,17 +807,23 @@ fn coerce_unsized_old_solver( Ok(()) } - /// Create an obligation for `ty: Unpin`. - fn unpin_obligation(&self, ty: Ty<'tcx>) -> PredicateObligation<'tcx> { + /// Create an obligation for `ty: Unpin`, where . + fn unpin_obligation( + &self, + source: Ty<'tcx>, + target: Ty<'tcx>, + ty: Ty<'tcx>, + ) -> PredicateObligation<'tcx> { let pred = ty::TraitRef::new( self.tcx, self.tcx.require_lang_item(hir::LangItem::Unpin, self.cause.span), [ty], ); - PredicateObligation::new(self.tcx, self.cause.clone(), self.param_env, pred) + let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target }); + PredicateObligation::new(self.tcx, cause, self.param_env, pred) } - /// Checks if the given types are compatible for coercion to a pinned reference. + /// Checks if the given types are compatible for coercion from a pinned reference to a normal reference. fn maybe_pin_ref_to_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> Option> { if !self.tcx.features().pin_ergonomics() { return None; @@ -847,6 +853,8 @@ fn coerce_pin_ref_to_ref( coerce_mutbls(a_mut, b_mut)?; + let unpin_obligation = self.unpin_obligation(a, b, a_ty); + let a = Ty::new_ref(self.tcx, a_r, a_ty, b_mut); let mut coerce = self.unify_and( a, @@ -855,7 +863,7 @@ fn coerce_pin_ref_to_ref( Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::new(b_mut, self.allow_two_phase))), ForceLeakCheck::No, )?; - coerce.obligations.push(self.unpin_obligation(a_ty)); + coerce.obligations.push(unpin_obligation); Ok(coerce) } @@ -902,7 +910,9 @@ fn coerce_to_pin_ref( // no `Unpin` required when reborrowing a pinned reference to a pinned reference ty::Pinnedness::Pinned => (DerefAdjustKind::Pin, None), // `Unpin` required when reborrowing a non-pinned reference to a pinned reference - ty::Pinnedness::Not => (DerefAdjustKind::Builtin, Some(self.unpin_obligation(a_ty))), + ty::Pinnedness::Not => { + (DerefAdjustKind::Builtin, Some(self.unpin_obligation(a, b, a_ty))) + } }; coerce_mutbls(a_mut, b_mut)?; diff --git a/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr b/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr index d0558b6bf2fd..3dc59cecb3c1 100644 --- a/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr +++ b/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr @@ -21,6 +21,7 @@ LL | |x: Pin<&mut T>| -> &mut T { x }; | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `Pin<&mut T>` to `&mut T` help: consider restricting type parameter `T` with trait `Unpin` | LL | fn pin_to_ref() { @@ -34,6 +35,7 @@ LL | |x: Pin<&mut T>| -> &T { x }; | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `Pin<&mut T>` to `&T` help: consider restricting type parameter `T` with trait `Unpin` | LL | fn pin_to_ref() { @@ -47,6 +49,7 @@ LL | |x: Pin<&T>| -> &T { x }; | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `Pin<&T>` to `&T` help: consider restricting type parameter `T` with trait `Unpin` | LL | fn pin_to_ref() { @@ -90,6 +93,7 @@ LL | |x: &mut T| -> Pin<&mut T> { x }; | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `&mut T` to `Pin<&mut T>` help: consider restricting type parameter `T` with trait `Unpin` | LL | fn ref_to_pin() { @@ -103,6 +107,7 @@ LL | |x: &mut T| -> Pin<&T> { x }; | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `&mut T` to `Pin<&T>` help: consider restricting type parameter `T` with trait `Unpin` | LL | fn ref_to_pin() { @@ -116,6 +121,7 @@ LL | |x: &T| -> Pin<&T> { x }; | = note: consider using the `pin!` macro consider using `Box::pin` if you need to access the pinned value outside of the current scope + = note: required for the cast from `&T` to `Pin<&T>` help: consider restricting type parameter `T` with trait `Unpin` | LL | fn ref_to_pin() {