From 04220972a7ef4c7f7df0ca90c1c7c2b4ee7eb2d5 Mon Sep 17 00:00:00 2001 From: Frank King Date: Fri, 30 Jan 2026 10:48:18 +0800 Subject: [PATCH 1/2] Support coercion between references and pinned references --- compiler/rustc_hir_analysis/src/autoderef.rs | 2 + compiler/rustc_hir_typeck/src/autoderef.rs | 4 + compiler/rustc_hir_typeck/src/coercion.rs | 65 +++++ .../rustc_hir_typeck/src/expr_use_visitor.rs | 12 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 3 + compiler/rustc_lint/src/autorefs.rs | 4 +- compiler/rustc_middle/src/ty/adjustment.rs | 5 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 44 ++++ .../pin-coercion-check.normal.stderr | 227 ++++++++++++++++++ .../pin-coercion-check.pin_ergonomics.stderr | 155 ++++++++++++ tests/ui/pin-ergonomics/pin-coercion-check.rs | 66 +++++ tests/ui/pin-ergonomics/pin-coercion.rs | 56 +++++ 12 files changed, 640 insertions(+), 3 deletions(-) create mode 100644 tests/ui/pin-ergonomics/pin-coercion-check.normal.stderr create mode 100644 tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr create mode 100644 tests/ui/pin-ergonomics/pin-coercion-check.rs create mode 100644 tests/ui/pin-ergonomics/pin-coercion.rs diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 1f06b1c94237d..aae20f369b916 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -17,6 +17,8 @@ pub enum AutoderefKind { Builtin, /// A type which must dispatch to a `Deref` implementation. Overloaded, + /// A pinned reference type, such as `Pin<&T>` and `Pin<&mut T>`. + Pin, } struct AutoderefSnapshot<'tcx> { at_start: bool, diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index f7700179d2a3a..8ae4918edbfdd 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -6,6 +6,7 @@ use itertools::Itertools; use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind}; use rustc_infer::infer::InferOk; use rustc_infer::traits::PredicateObligations; +use rustc_middle::bug; use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind, OverloadedDeref}; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; @@ -62,6 +63,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .unwrap_or(DerefAdjustKind::Builtin) } + AutoderefKind::Pin => { + bug!("Pin autoderef kind should not be present in the steps") + } AutoderefKind::Builtin => DerefAdjustKind::Builtin, }) .zip_eq(targets) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 36a07b361d9de..794c4132469f7 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -269,12 +269,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return self.coerce_to_raw_ptr(a, b, b_mutbl); } ty::Ref(r_b, _, mutbl_b) => { + if self.tcx.features().pin_ergonomics() + && a.pinned_ty().is_some_and(|ty| ty.is_ref()) + && let Ok(coerce) = self.commit_if_ok(|_| self.coerce_maybe_pinned_ref(a, b)) + { + return Ok(coerce); + } return self.coerce_to_ref(a, b, r_b, mutbl_b); } ty::Adt(pin, _) if self.tcx.features().pin_ergonomics() && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { + if a.is_ref() && b.pinned_ty().is_some_and(|ty| ty.is_ref()) { + return self.coerce_maybe_pinned_ref(a, b); + } let pin_coerce = self.commit_if_ok(|_| self.coerce_to_pin_ref(a, b)); if pin_coerce.is_ok() { return pin_coerce; @@ -847,6 +856,62 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b), ForceLeakCheck::No) } + /// Coerce pinned reference to regular reference or vice versa + /// + /// - `Pin<&mut T>` <-> `&mut T` when `T: Unpin` + /// - `Pin<&T>` <-> `&T` when `T: Unpin` + /// - `Pin<&mut T>` <-> `Pin<&T>` when `T: Unpin` + #[instrument(skip(self), level = "trace")] + fn coerce_maybe_pinned_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + let span = self.cause.span; + let Some((a_ty, a_pinnedness, a_mutbl, a_region)) = a.maybe_pinned_ref() else { + span_bug!(span, "expect pinned reference or reference, found {:?}", a); + }; + let Some((_b_ty, b_pinnedness, b_mutbl, _b_region)) = b.maybe_pinned_ref() else { + span_bug!(span, "expect pinned reference or reference, found {:?}", b); + }; + use ty::Pinnedness::*; + if a_pinnedness == b_pinnedness { + span_bug!(span, "expect different pinnedness, found {:?} and {:?}", a, b); + } + + coerce_mutbls(a_mutbl, b_mutbl)?; + + let (deref, borrow) = match (a_pinnedness, b_pinnedness) { + (Not, Not) | (Pinned, Pinned) => { + span_bug!(span, "expect different pinnedness, found {:?} and {:?}", a, b) + } + (Pinned, Not) => { + let mutbl = AutoBorrowMutability::new(b_mutbl, AllowTwoPhase::Yes); + (DerefAdjustKind::Pin, AutoBorrow::Ref(mutbl)) + } + (Not, Pinned) => (DerefAdjustKind::Builtin, AutoBorrow::Pin(b_mutbl)), + }; + let mut coerce = self.unify_and( + // update a with b's pinnedness and mutability since we'll be coercing pinnedness and mutability + match b_pinnedness { + Pinned => Ty::new_pinned_ref(self.tcx, a_region, a_ty, b_mutbl), + Not => Ty::new_ref(self.tcx, a_region, a_ty, b_mutbl), + }, + b, + [Adjustment { kind: Adjust::Deref(deref), target: a_ty }], + Adjust::Borrow(borrow), + ForceLeakCheck::No, + )?; + + // Create an obligation for `a_ty: Unpin`. + let cause = + self.cause(self.cause.span, ObligationCauseCode::Coercion { source: a, target: b }); + let pred = ty::TraitRef::new( + self.tcx, + self.tcx.require_lang_item(hir::LangItem::Unpin, self.cause.span), + [a_ty], + ); + let obligation = Obligation::new(self.tcx, cause, self.fcx.param_env, pred); + coerce.obligations.push(obligation); + Ok(coerce) + } + fn coerce_from_fn_pointer( &self, a: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 171184d3a562b..90bd5672d24fd 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -734,7 +734,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.consume_or_copy(&place_with_id, place_with_id.hir_id); } - adjustment::Adjust::Deref(DerefAdjustKind::Builtin) => {} + adjustment::Adjust::Deref(DerefAdjustKind::Builtin | DerefAdjustKind::Pin) => {} // Autoderefs for overloaded Deref calls in fact reference // their receiver. That is, if we have `(*x)` where `x` @@ -798,6 +798,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ty::BorrowKind::from_mutbl(m), ); } + + adjustment::AutoBorrow::Pin(m) => { + debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place); + + self.delegate.borrow_mut().borrow( + base_place, + base_place.hir_id, + ty::BorrowKind::from_mutbl(m), + ); + } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 67007523a0671..ac775257cc684 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -279,6 +279,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Adjust::Deref(DerefAdjustKind::Builtin) => { // FIXME(const_trait_impl): We *could* enforce `&T: [const] Deref` here. } + Adjust::Deref(DerefAdjustKind::Pin) => { + // FIXME(const_trait_impl): We *could* enforce `Pin<&T>: [const] Deref` here. + } Adjust::Pointer(_pointer_coercion) => { // FIXME(const_trait_impl): We should probably enforce these. } diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 5bb7df80ffb36..b39bc65516c8e 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -174,7 +174,7 @@ fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Muta Adjust::NeverToAny | Adjust::Pointer(..) | Adjust::ReborrowPin(..) - | Adjust::Deref(DerefAdjustKind::Builtin) - | Adjust::Borrow(AutoBorrow::RawPtr(..)) => None, + | Adjust::Deref(DerefAdjustKind::Builtin | DerefAdjustKind::Pin) + | Adjust::Borrow(AutoBorrow::RawPtr(..) | AutoBorrow::Pin(..)) => None, } } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 6d546aede4cf4..58687be7440b5 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -105,6 +105,7 @@ pub enum Adjust { Pointer(PointerCoercion), /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`. + // FIXME(pin_ergonomics): This can be replaced with a `Deref(Pin)` followed by a `Borrow(Pin)` ReborrowPin(hir::Mutability), } @@ -112,6 +113,7 @@ pub enum Adjust { pub enum DerefAdjustKind { Builtin, Overloaded(OverloadedDeref), + Pin, } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` @@ -196,6 +198,9 @@ pub enum AutoBorrow { /// Converts from T to *T. RawPtr(hir::Mutability), + + /// Converts from T to Pin<&T>. + Pin(hir::Mutability), } /// Information for `CoerceUnsized` impls, storing information we diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 0117a10e3a8c6..9bccb56b23598 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -144,6 +144,19 @@ impl<'tcx> ThirBuildCx<'tcx> { adjust_span(&mut expr); ExprKind::Deref { arg: self.thir.exprs.push(expr) } } + Adjust::Deref(DerefAdjustKind::Pin) => { + adjust_span(&mut expr); + // pointer = ($expr).pointer + let pin_ty = expr.ty.pinned_ty().expect("Deref(Pin) with non-Pin type"); + let pointer_target = ExprKind::Field { + lhs: self.thir.exprs.push(expr), + variant_index: FIRST_VARIANT, + name: FieldIdx::ZERO, + }; + let expr = Expr { temp_scope_id, ty: pin_ty, span, kind: pointer_target }; + // expr = *pointer + ExprKind::Deref { arg: self.thir.exprs.push(expr) } + } Adjust::Deref(DerefAdjustKind::Overloaded(deref)) => { // We don't need to do call adjust_span here since // deref coercions always start with a built-in deref. @@ -178,6 +191,37 @@ impl<'tcx> ThirBuildCx<'tcx> { Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) } } + Adjust::Borrow(AutoBorrow::Pin(mutbl)) => { + // expr = &pin (mut|const|) arget + let borrow_kind = match mutbl { + hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, + hir::Mutability::Not => BorrowKind::Shared, + }; + let new_pin_target = + Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, expr.ty, mutbl); + let arg = self.thir.exprs.push(expr); + let expr = self.thir.exprs.push(Expr { + temp_scope_id, + ty: new_pin_target, + span, + kind: ExprKind::Borrow { borrow_kind, arg }, + }); + + // kind = Pin { pointer } + let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span); + let args = self.tcx.mk_args(&[new_pin_target.into()]); + let kind = ExprKind::Adt(Box::new(AdtExpr { + adt_def: self.tcx.adt_def(pin_did), + variant_index: FIRST_VARIANT, + args, + fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]), + user_ty: None, + base: AdtExprBase::None, + })); + + debug!(?kind); + kind + } Adjust::ReborrowPin(mutbl) => { debug!("apply ReborrowPin adjustment"); // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }` diff --git a/tests/ui/pin-ergonomics/pin-coercion-check.normal.stderr b/tests/ui/pin-ergonomics/pin-coercion-check.normal.stderr new file mode 100644 index 0000000000000..0806ad64448c4 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-check.normal.stderr @@ -0,0 +1,227 @@ +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:9:36 + | +LL | |x: Pin<&mut T>| -> &mut T { x.get_mut() }; + | ^^^^^^^ the trait `Unpin` is not implemented for `T` + | + = 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 by a bound in `Pin::<&'a mut T>::get_mut` + --> $SRC_DIR/core/src/pin.rs:LL:COL +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn get() { + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:18:34 + | +LL | |x: Pin<&mut T>| -> &mut T { x }; + | ------ ^ expected `&mut T`, found `Pin<&mut T>` + | | + | expected `&mut T` because of return type + | + = note: expected mutable reference `&mut T` + found struct `Pin<&mut T>` +help: consider mutably borrowing here + | +LL | |x: Pin<&mut T>| -> &mut T { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:21:30 + | +LL | |x: Pin<&mut T>| -> &T { x }; + | -- ^ expected `&T`, found `Pin<&mut T>` + | | + | expected `&T` because of return type + | + = note: expected reference `&T` + found struct `Pin<&mut T>` +help: consider borrowing here + | +LL | |x: Pin<&mut T>| -> &T { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:24:26 + | +LL | |x: Pin<&T>| -> &T { x }; + | -- ^ expected `&T`, found `Pin<&T>` + | | + | expected `&T` because of return type + | + = note: expected reference `&T` + found struct `Pin<&T>` +help: consider borrowing here + | +LL | |x: Pin<&T>| -> &T { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:27:30 + | +LL | |x: Pin<&T>| -> &mut T { x }; + | ------ ^ expected `&mut T`, found `Pin<&T>` + | | + | expected `&mut T` because of return type + | + = note: expected mutable reference `&mut T` + found struct `Pin<&T>` +help: consider mutably borrowing here + | +LL | |x: Pin<&T>| -> &mut T { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:31:34 + | +LL | |x: Pin<&mut U>| -> &mut U { x }; + | ------ ^ expected `&mut U`, found `Pin<&mut U>` + | | + | expected `&mut U` because of return type + | + = note: expected mutable reference `&mut U` + found struct `Pin<&mut U>` +help: consider mutably borrowing here + | +LL | |x: Pin<&mut U>| -> &mut U { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:33:30 + | +LL | |x: Pin<&mut U>| -> &U { x }; + | -- ^ expected `&U`, found `Pin<&mut U>` + | | + | expected `&U` because of return type + | + = note: expected reference `&U` + found struct `Pin<&mut U>` +help: consider borrowing here + | +LL | |x: Pin<&mut U>| -> &U { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:35:26 + | +LL | |x: Pin<&U>| -> &U { x }; + | -- ^ expected `&U`, found `Pin<&U>` + | | + | expected `&U` because of return type + | + = note: expected reference `&U` + found struct `Pin<&U>` +help: consider borrowing here + | +LL | |x: Pin<&U>| -> &U { &x }; + | + + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:37:30 + | +LL | |x: Pin<&U>| -> &mut U { x }; + | ------ ^ expected `&mut U`, found `Pin<&U>` + | | + | expected `&mut U` because of return type + | + = note: expected mutable reference `&mut U` + found struct `Pin<&U>` +help: consider mutably borrowing here + | +LL | |x: Pin<&U>| -> &mut U { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:43:34 + | +LL | |x: &mut T| -> Pin<&mut T> { x }; + | ----------- ^ expected `Pin<&mut T>`, found `&mut T` + | | + | expected `Pin<&mut T>` because of return type + | + = note: expected struct `Pin<&mut T>` + found mutable reference `&mut T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:46:30 + | +LL | |x: &mut T| -> Pin<&T> { x }; + | ------- ^ expected `Pin<&T>`, found `&mut T` + | | + | expected `Pin<&T>` because of return type + | + = note: expected struct `Pin<&T>` + found mutable reference `&mut T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:49:26 + | +LL | |x: &T| -> Pin<&T> { x }; + | ------- ^ expected `Pin<&T>`, found `&T` + | | + | expected `Pin<&T>` because of return type + | + = note: expected struct `Pin<&T>` + found reference `&T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:52:30 + | +LL | |x: &T| -> Pin<&mut T> { x }; + | ----------- ^ expected `Pin<&mut T>`, found `&T` + | | + | expected `Pin<&mut T>` because of return type + | + = note: expected struct `Pin<&mut T>` + found reference `&T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:56:34 + | +LL | |x: &mut U| -> Pin<&mut U> { x }; + | ----------- ^ expected `Pin<&mut U>`, found `&mut U` + | | + | expected `Pin<&mut U>` because of return type + | + = note: expected struct `Pin<&mut U>` + found mutable reference `&mut U` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:58:30 + | +LL | |x: &mut U| -> Pin<&U> { x }; + | ------- ^ expected `Pin<&U>`, found `&mut U` + | | + | expected `Pin<&U>` because of return type + | + = note: expected struct `Pin<&U>` + found mutable reference `&mut U` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:60:26 + | +LL | |x: &U| -> Pin<&U> { x }; + | ------- ^ expected `Pin<&U>`, found `&U` + | | + | expected `Pin<&U>` because of return type + | + = note: expected struct `Pin<&U>` + found reference `&U` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:62:30 + | +LL | |x: &U| -> Pin<&mut U> { x }; + | ----------- ^ expected `Pin<&mut U>`, found `&U` + | | + | expected `Pin<&mut U>` because of return type + | + = note: expected struct `Pin<&mut U>` + found reference `&U` + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr b/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr new file mode 100644 index 0000000000000..ce343fd24a5b8 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr @@ -0,0 +1,155 @@ +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:9:36 + | +LL | |x: Pin<&mut T>| -> &mut T { x.get_mut() }; + | ^^^^^^^ the trait `Unpin` is not implemented for `T` + | + = 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 by a bound in `Pin::<&'a mut T>::get_mut` + --> $SRC_DIR/core/src/pin.rs:LL:COL +help: consider restricting type parameter `T` with trait `Unpin` + | +LL | fn get() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:18:34 + | +LL | |x: Pin<&mut T>| -> &mut T { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = 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() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:21:30 + | +LL | |x: Pin<&mut T>| -> &T { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = 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() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:24:26 + | +LL | |x: Pin<&T>| -> &T { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = 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() { + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:27:30 + | +LL | |x: Pin<&T>| -> &mut T { x }; + | ------ ^ expected `&mut T`, found `Pin<&T>` + | | + | expected `&mut T` because of return type + | + = note: expected mutable reference `&mut T` + found struct `Pin<&T>` +help: consider mutably borrowing here + | +LL | |x: Pin<&T>| -> &mut T { &mut x }; + | ++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:37:30 + | +LL | |x: Pin<&U>| -> &mut U { x }; + | ------ ^ expected `&mut U`, found `Pin<&U>` + | | + | expected `&mut U` because of return type + | + = note: expected mutable reference `&mut U` + found struct `Pin<&U>` +help: consider mutably borrowing here + | +LL | |x: Pin<&U>| -> &mut U { &mut x }; + | ++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:43:34 + | +LL | |x: &mut T| -> Pin<&mut T> { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = 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() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:46:30 + | +LL | |x: &mut T| -> Pin<&T> { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = 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() { + | ++++++++++++++++++++ + +error[E0277]: `T` cannot be unpinned + --> $DIR/pin-coercion-check.rs:49:26 + | +LL | |x: &T| -> Pin<&T> { x }; + | ^ the trait `Unpin` is not implemented for `T` + | + = 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() { + | ++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:52:30 + | +LL | |x: &T| -> Pin<&mut T> { x }; + | ----------- ^ types differ in mutability + | | + | expected `Pin<&mut T>` because of return type + | + = note: expected struct `Pin<&mut T>` + found reference `&T` + +error[E0308]: mismatched types + --> $DIR/pin-coercion-check.rs:62:30 + | +LL | |x: &U| -> Pin<&mut U> { x }; + | ----------- ^ types differ in mutability + | | + | expected `Pin<&mut U>` because of return type + | + = note: expected struct `Pin<&mut U>` + found reference `&U` + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/pin-ergonomics/pin-coercion-check.rs b/tests/ui/pin-ergonomics/pin-coercion-check.rs new file mode 100644 index 0000000000000..9b51851219ccd --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-check.rs @@ -0,0 +1,66 @@ +//@ revisions: pin_ergonomics normal +//@ edition:2024 +#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))] +#![allow(incomplete_features)] + +use std::pin::Pin; + +fn get() { + |x: Pin<&mut T>| -> &mut T { x.get_mut() }; //~ ERROR `T` cannot be unpinned + |x: Pin<&T>| -> &T { x.get_ref() }; + + |x: Pin<&mut U>| -> &mut U { x.get_mut() }; + |x: Pin<&U>| -> &U { x.get_ref() }; +} + +fn pin_to_ref() { + // T: !Unpin + |x: Pin<&mut T>| -> &mut T { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: Pin<&mut T>| -> &T { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: Pin<&T>| -> &T { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: Pin<&T>| -> &mut T { x }; + //~^ ERROR mismatched types + + // U: Unpin + |x: Pin<&mut U>| -> &mut U { x }; + //[normal]~^ ERROR mismatched types + |x: Pin<&mut U>| -> &U { x }; + //[normal]~^ ERROR mismatched types + |x: Pin<&U>| -> &U { x }; + //[normal]~^ ERROR mismatched types + |x: Pin<&U>| -> &mut U { x }; + //~^ ERROR mismatched types +} + +fn ref_to_pin() { + // T: !Unpin + |x: &mut T| -> Pin<&mut T> { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: &mut T| -> Pin<&T> { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: &T| -> Pin<&T> { x }; + //[normal]~^ ERROR mismatched types + //[pin_ergonomics]~^^ ERROR `T` cannot be unpinned + |x: &T| -> Pin<&mut T> { x }; + //~^ ERROR mismatched types + + // U: Unpin + |x: &mut U| -> Pin<&mut U> { x }; + //[normal]~^ ERROR mismatched types + |x: &mut U| -> Pin<&U> { x }; + //[normal]~^ ERROR mismatched types + |x: &U| -> Pin<&U> { x }; + //[normal]~^ ERROR mismatched types + |x: &U| -> Pin<&mut U> { x }; + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pin-coercion.rs b/tests/ui/pin-ergonomics/pin-coercion.rs new file mode 100644 index 0000000000000..6ace4b97edb34 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion.rs @@ -0,0 +1,56 @@ +//@ run-pass +//@ edition:2024 +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] +#![deny(dead_code)] + +use std::cell::RefCell; + +fn coerce_mut_to_pin_mut(x: &mut T) -> &pin mut T { + x +} +fn coerce_ref_to_pin_ref(x: &T) -> &pin const T { + x +} +fn coerce_pin_mut_to_mut(x: &pin mut T) -> &mut T { + x +} +fn coerce_pin_ref_to_ref(x: &pin const T) -> &T { + x +} + +fn coerce_pin_mut_to_ref(x: &pin mut T) -> &T { + x +} +fn coerce_mut_to_pin_ref(x: &mut T) -> &pin const T { + x +} + +fn test(x: &mut RefCell) { + let mut x: &pin mut _ = coerce_mut_to_pin_mut(x); + x.get_mut().get_mut().push_str("&mut T -> &pin mut T\n"); + let x_ref: &_ = coerce_pin_mut_to_ref(x.as_mut()); + x_ref.borrow_mut().push_str("&pin mut T -> &T\n"); + let x: &mut _ = coerce_pin_mut_to_mut(x); + x.get_mut().push_str("&pin mut T -> &mut T\n"); + let x: &pin const _ = coerce_mut_to_pin_ref(x); + x.borrow_mut().push_str("&mut T -> &pin const T\n"); + let x: &_ = coerce_pin_ref_to_ref(x); + x.borrow_mut().push_str("&pin const T -> &T\n"); + let x: &pin const _ = coerce_ref_to_pin_ref(x); + x.borrow_mut().push_str("&T -> &pin const T\n"); +} + +fn main() { + let mut x = RefCell::new(String::new()); + test(&mut x); + assert_eq!( + x.borrow().as_str(), + "&mut T -> &pin mut T\n\ + &pin mut T -> &T\n\ + &pin mut T -> &mut T\n\ + &mut T -> &pin const T\n\ + &pin const T -> &T\n\ + &T -> &pin const T\n" + ); +} From ae0c73c3253ebf101545bc5f71be06be2db534ae Mon Sep 17 00:00:00 2001 From: Frank King Date: Wed, 4 Feb 2026 16:59:16 +0800 Subject: [PATCH 2/2] Remove `coerce_maybe_pinned_ref`. Use `coerce_to_pin_ref` and `coerce_pin_ref_to_ref` instead. --- compiler/rustc_hir_analysis/src/autoderef.rs | 2 - compiler/rustc_hir_typeck/src/autoderef.rs | 4 - compiler/rustc_hir_typeck/src/coercion.rs | 174 ++++++++---------- .../rustc_hir_typeck/src/expr_use_visitor.rs | 12 +- compiler/rustc_middle/src/ty/sty.rs | 8 + .../pin-coercion-check.pin_ergonomics.stderr | 10 +- 6 files changed, 89 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index aae20f369b916..1f06b1c94237d 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -17,8 +17,6 @@ pub enum AutoderefKind { Builtin, /// A type which must dispatch to a `Deref` implementation. Overloaded, - /// A pinned reference type, such as `Pin<&T>` and `Pin<&mut T>`. - Pin, } struct AutoderefSnapshot<'tcx> { at_start: bool, diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 8ae4918edbfdd..f7700179d2a3a 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -6,7 +6,6 @@ use itertools::Itertools; use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind}; use rustc_infer::infer::InferOk; use rustc_infer::traits::PredicateObligations; -use rustc_middle::bug; use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind, OverloadedDeref}; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; @@ -63,9 +62,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .unwrap_or(DerefAdjustKind::Builtin) } - AutoderefKind::Pin => { - bug!("Pin autoderef kind should not be present in the steps") - } AutoderefKind::Builtin => DerefAdjustKind::Builtin, }) .zip_eq(targets) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 794c4132469f7..db920fd585c7f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -270,21 +270,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } ty::Ref(r_b, _, mutbl_b) => { if self.tcx.features().pin_ergonomics() - && a.pinned_ty().is_some_and(|ty| ty.is_ref()) - && let Ok(coerce) = self.commit_if_ok(|_| self.coerce_maybe_pinned_ref(a, b)) + && let Ok(pin_coerce) = + self.commit_if_ok(|_| self.coerce_pin_ref_to_ref(a, b, mutbl_b)) { - return Ok(coerce); + return Ok(pin_coerce); } return self.coerce_to_ref(a, b, r_b, mutbl_b); } - ty::Adt(pin, _) - if self.tcx.features().pin_ergonomics() - && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => + _ if self.tcx.features().pin_ergonomics() + && let Some((_, ty::Pinnedness::Pinned, mut_b, _)) = b.maybe_pinned_ref() => { - if a.is_ref() && b.pinned_ty().is_some_and(|ty| ty.is_ref()) { - return self.coerce_maybe_pinned_ref(a, b); - } - let pin_coerce = self.commit_if_ok(|_| self.coerce_to_pin_ref(a, b)); + let pin_coerce = self.commit_if_ok(|_| self.coerce_to_pin_ref(a, b, mut_b)); if pin_coerce.is_ok() { return pin_coerce; } @@ -799,116 +795,102 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(()) } - /// Applies reborrowing for `Pin` + /// Create an obligation for `ty: Unpin`. + fn unpin_obligation(&self, 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) + } + + /// Coerces from a pinned reference to a normal reference. + #[instrument(skip(self), level = "trace")] + fn coerce_pin_ref_to_ref( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + mut_b: hir::Mutability, + ) -> CoerceResult<'tcx> { + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); + debug_assert!(self.tcx.features().pin_ergonomics()); + + let Some((a_ty, ty::Pinnedness::Pinned, mut_a, r_a)) = a.maybe_pinned_ref() else { + debug!("not fitting pinned ref to ref coercion (`{:?}` -> `{:?}`)", a, b); + return Err(TypeError::Mismatch); + }; + + coerce_mutbls(mut_a, mut_b)?; + + let a = Ty::new_ref(self.tcx, r_a, a_ty, mut_b); + let mut coerce = self.unify_and( + a, + b, + [Adjustment { kind: Adjust::Deref(DerefAdjustKind::Pin), target: a_ty }], + Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::new(mut_b, self.allow_two_phase))), + ForceLeakCheck::No, + )?; + coerce.obligations.push(self.unpin_obligation(a_ty)); + Ok(coerce) + } + + /// Applies reborrowing and auto-borrowing that results to `Pin<&T>` or `Pin<&mut T>`: /// - /// We currently only support reborrowing `Pin<&mut T>` as `Pin<&mut T>`. This is accomplished - /// by inserting a call to `Pin::as_mut` during MIR building. + /// Currently we only support the following coercions: + /// - Reborrowing `Pin<&mut T>` -> `Pin<&mut T>` + /// - Reborrowing `Pin<&T>` -> `Pin<&T>` + /// - Auto-borrowing `&mut T` -> `Pin<&mut T>` where `T: Unpin` + /// - Auto-borrowing `&mut T` -> `Pin<&T>` where `T: Unpin` + /// - Auto-borrowing `&T` -> `Pin<&T>` where `T: Unpin` /// /// In the future we might want to support other reborrowing coercions, such as: - /// - `Pin<&mut T>` as `Pin<&T>` - /// - `Pin<&T>` as `Pin<&T>` /// - `Pin>` as `Pin<&T>` /// - `Pin>` as `Pin<&mut T>` #[instrument(skip(self), level = "trace")] - fn coerce_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + fn coerce_to_pin_ref( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + mut_b: hir::Mutability, + ) -> CoerceResult<'tcx> { debug_assert!(self.shallow_resolve(a) == a); debug_assert!(self.shallow_resolve(b) == b); + debug_assert!(self.tcx.features().pin_ergonomics()); - // We need to make sure the two types are compatible for coercion. - // Then we will build a ReborrowPin adjustment and return that as an InferOk. - - // Right now we can only reborrow if this is a `Pin<&mut T>`. - let extract_pin_mut = |ty: Ty<'tcx>| { - // Get the T out of Pin - let (pin, ty) = match ty.kind() { - ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { - (*pin, args[0].expect_ty()) - } - _ => { - debug!("can't reborrow {:?} as pinned", ty); - return Err(TypeError::Mismatch); - } - }; - // Make sure the T is something we understand (just `&mut U` for now) - match ty.kind() { - ty::Ref(region, ty, mutbl) => Ok((pin, *region, *ty, *mutbl)), - _ => { - debug!("can't reborrow pin of inner type {:?}", ty); - Err(TypeError::Mismatch) - } + // We need to deref the reference first before we reborrow it to a pinned reference. + let (deref, a_ty, mut_a, r_a, unpin_obligation) = match a.maybe_pinned_ref() { + // no `Unpin` required when reborrowing a pinned reference to a pinned reference + Some((a_ty, ty::Pinnedness::Pinned, mut_a, r_a)) => { + (DerefAdjustKind::Pin, a_ty, mut_a, r_a, None) + } + // `Unpin` required when reborrowing a non-pinned reference to a pinned reference + Some((a_ty, ty::Pinnedness::Not, mut_a, r_a)) => { + (DerefAdjustKind::Builtin, a_ty, mut_a, r_a, Some(self.unpin_obligation(a_ty))) + } + None => { + debug!("can't reborrow {:?} as pinned", a); + return Err(TypeError::Mismatch); } }; - let (pin, a_region, a_ty, mut_a) = extract_pin_mut(a)?; - let (_, _, _b_ty, mut_b) = extract_pin_mut(b)?; - coerce_mutbls(mut_a, mut_b)?; // update a with b's mutability since we'll be coercing mutability - let a = Ty::new_adt( - self.tcx, - pin, - self.tcx.mk_args(&[Ty::new_ref(self.tcx, a_region, a_ty, mut_b).into()]), - ); + let a = Ty::new_pinned_ref(self.tcx, r_a, a_ty, mut_b); // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. - self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b), ForceLeakCheck::No) - } - - /// Coerce pinned reference to regular reference or vice versa - /// - /// - `Pin<&mut T>` <-> `&mut T` when `T: Unpin` - /// - `Pin<&T>` <-> `&T` when `T: Unpin` - /// - `Pin<&mut T>` <-> `Pin<&T>` when `T: Unpin` - #[instrument(skip(self), level = "trace")] - fn coerce_maybe_pinned_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - let span = self.cause.span; - let Some((a_ty, a_pinnedness, a_mutbl, a_region)) = a.maybe_pinned_ref() else { - span_bug!(span, "expect pinned reference or reference, found {:?}", a); - }; - let Some((_b_ty, b_pinnedness, b_mutbl, _b_region)) = b.maybe_pinned_ref() else { - span_bug!(span, "expect pinned reference or reference, found {:?}", b); - }; - use ty::Pinnedness::*; - if a_pinnedness == b_pinnedness { - span_bug!(span, "expect different pinnedness, found {:?} and {:?}", a, b); - } - - coerce_mutbls(a_mutbl, b_mutbl)?; - - let (deref, borrow) = match (a_pinnedness, b_pinnedness) { - (Not, Not) | (Pinned, Pinned) => { - span_bug!(span, "expect different pinnedness, found {:?} and {:?}", a, b) - } - (Pinned, Not) => { - let mutbl = AutoBorrowMutability::new(b_mutbl, AllowTwoPhase::Yes); - (DerefAdjustKind::Pin, AutoBorrow::Ref(mutbl)) - } - (Not, Pinned) => (DerefAdjustKind::Builtin, AutoBorrow::Pin(b_mutbl)), - }; let mut coerce = self.unify_and( - // update a with b's pinnedness and mutability since we'll be coercing pinnedness and mutability - match b_pinnedness { - Pinned => Ty::new_pinned_ref(self.tcx, a_region, a_ty, b_mutbl), - Not => Ty::new_ref(self.tcx, a_region, a_ty, b_mutbl), - }, + a, b, [Adjustment { kind: Adjust::Deref(deref), target: a_ty }], - Adjust::Borrow(borrow), + Adjust::Borrow(AutoBorrow::Pin(mut_b)), ForceLeakCheck::No, )?; - // Create an obligation for `a_ty: Unpin`. - let cause = - self.cause(self.cause.span, ObligationCauseCode::Coercion { source: a, target: b }); - let pred = ty::TraitRef::new( - self.tcx, - self.tcx.require_lang_item(hir::LangItem::Unpin, self.cause.span), - [a_ty], - ); - let obligation = Obligation::new(self.tcx, cause, self.fcx.param_env, pred); - coerce.obligations.push(obligation); + coerce.obligations.extend(unpin_obligation); Ok(coerce) } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 90bd5672d24fd..e3e467f9532a8 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -789,17 +789,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ); } - adjustment::AutoBorrow::RawPtr(m) => { - debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place); - - self.delegate.borrow_mut().borrow( - base_place, - base_place.hir_id, - ty::BorrowKind::from_mutbl(m), - ); - } - - adjustment::AutoBorrow::Pin(m) => { + adjustment::AutoBorrow::RawPtr(m) | adjustment::AutoBorrow::Pin(m) => { debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place); self.delegate.borrow_mut().borrow( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4be30d8b6c918..f505d47b8acd9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1336,6 +1336,14 @@ impl<'tcx> Ty<'tcx> { } } + /// Returns the type, pinnedness, mutability, and the region of a reference (`&T` or `&mut T`) + /// or a pinned-reference type (`Pin<&T>` or `Pin<&mut T>`). + /// + /// Regarding the [`pin_ergonomics`] feature, one of the goals is to make pinned references + /// (`Pin<&T>` and `Pin<&mut T>`) behaves similar to normal references (`&T` and `&mut T`). + /// This function is useful when references and pinned references are processed similarly. + /// + /// [`pin_ergonomics`]: https://github.com/rust-lang/rust/issues/130494 pub fn maybe_pinned_ref( self, ) -> Option<(Ty<'tcx>, ty::Pinnedness, ty::Mutability, Region<'tcx>)> { 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 ce343fd24a5b8..2046af91d69c8 100644 --- a/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr +++ b/tests/ui/pin-ergonomics/pin-coercion-check.pin_ergonomics.stderr @@ -21,7 +21,6 @@ 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() { @@ -35,7 +34,6 @@ 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() { @@ -49,7 +47,6 @@ 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() { @@ -93,7 +90,6 @@ 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() { @@ -107,7 +103,6 @@ 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() { @@ -121,7 +116,6 @@ 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() { @@ -131,7 +125,7 @@ error[E0308]: mismatched types --> $DIR/pin-coercion-check.rs:52:30 | LL | |x: &T| -> Pin<&mut T> { x }; - | ----------- ^ types differ in mutability + | ----------- ^ expected `Pin<&mut T>`, found `&T` | | | expected `Pin<&mut T>` because of return type | @@ -142,7 +136,7 @@ error[E0308]: mismatched types --> $DIR/pin-coercion-check.rs:62:30 | LL | |x: &U| -> Pin<&mut U> { x }; - | ----------- ^ types differ in mutability + | ----------- ^ expected `Pin<&mut U>`, found `&U` | | | expected `Pin<&mut U>` because of return type |