Support coercion between references and pinned references

This commit is contained in:
Frank King
2026-01-30 10:48:18 +08:00
parent 595f14b022
commit 8caaf1d1e0
12 changed files with 640 additions and 3 deletions
@@ -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,
@@ -6,6 +6,7 @@
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 @@ pub(crate) fn adjust_steps_as_infer_ok(
})
.unwrap_or(DerefAdjustKind::Builtin)
}
AutoderefKind::Pin => {
bug!("Pin autoderef kind should not be present in the steps")
}
AutoderefKind::Builtin => DerefAdjustKind::Builtin,
})
.zip_eq(targets)
+65
View File
@@ -269,12 +269,21 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'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 @@ fn coerce_to_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'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>,
@@ -736,7 +736,7 @@ fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
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`
@@ -800,6 +800,16 @@ fn walk_autoref(
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),
);
}
}
}
@@ -331,6 +331,9 @@ pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment
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.
}
+2 -2
View File
@@ -173,7 +173,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,
}
}
@@ -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
@@ -143,6 +143,19 @@ fn apply_adjustment(
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.
@@ -177,6 +190,37 @@ fn apply_adjustment(
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 }`
@@ -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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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`.
@@ -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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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<T: std::marker::Unpin, U: Unpin>() {
| ++++++++++++++++++++
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`.
@@ -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<T, U: Unpin>() {
|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, U: Unpin>() {
// 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, U: Unpin>() {
// 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() {}
+56
View File
@@ -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<T: Unpin>(x: &mut T) -> &pin mut T {
x
}
fn coerce_ref_to_pin_ref<T: Unpin>(x: &T) -> &pin const T {
x
}
fn coerce_pin_mut_to_mut<T: Unpin>(x: &pin mut T) -> &mut T {
x
}
fn coerce_pin_ref_to_ref<T: Unpin>(x: &pin const T) -> &T {
x
}
fn coerce_pin_mut_to_ref<T: Unpin>(x: &pin mut T) -> &T {
x
}
fn coerce_mut_to_pin_ref<T: Unpin>(x: &mut T) -> &pin const T {
x
}
fn test(x: &mut RefCell<String>) {
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"
);
}