Skip to content

Commit

Permalink
pin_ergonomics: allow reborrowing as Pin<&T>
Browse files Browse the repository at this point in the history
  • Loading branch information
eholk committed Sep 19, 2024
1 parent 92a5d21 commit a18800f
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 15 deletions.
24 changes: 15 additions & 9 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -798,9 +798,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// 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<T>
let ty = match ty.kind() {
let (pin, ty) = match ty.kind() {
ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
args[0].expect_ty()
(*pin, args[0].expect_ty())
}
_ => {
debug!("can't reborrow {:?} as pinned", ty);
Expand All @@ -809,24 +809,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
};
// Make sure the T is something we understand (just `&mut U` for now)
match ty.kind() {
ty::Ref(region, ty, ty::Mutability::Mut) => Ok((*region, *ty)),
ty::Ref(region, ty, mutbl) => Ok((pin, *region, *ty, *mutbl)),
_ => {
debug!("can't reborrow pin of inner type {:?}", ty);
Err(TypeError::Mismatch)
}
}
};

let (_, _a_ty) = extract_pin_mut(a)?;
let (b_region, _b_ty) = extract_pin_mut(b)?;
let (pin, a_region, a_ty, mut_a) = extract_pin_mut(a)?;
let (_, b_region, _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()]),
);

// 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, |_inner_ty| {
vec![Adjustment {
kind: Adjust::ReborrowPin(b_region, hir::Mutability::Mut),
target: b,
}]
vec![Adjustment { kind: Adjust::ReborrowPin(b_region, mut_b), target: b }]
})
}

Expand Down
15 changes: 9 additions & 6 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,22 +181,25 @@ impl<'tcx> Cx<'tcx> {
});

// expr = &mut target
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, region, ptr_target_ty, mutbl);
let expr = self.thir.exprs.push(Expr {
temp_lifetime,
ty: Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl),
ty: new_pin_target,
span,
kind: ExprKind::Borrow {
borrow_kind: BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
arg,
},
kind: ExprKind::Borrow { borrow_kind, arg },
});

// kind = Pin { __pointer: pointer }
let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(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: pin_ty_args,
args,
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
user_ty: None,
base: None,
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/async-await/pin-reborrow-arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,22 @@ impl Foo {
fn foo(_: Pin<&mut Foo>) {
}

fn foo_const(_: Pin<&Foo>) {
}

fn bar(x: Pin<&mut Foo>) {
foo(x);
foo(x); // for this to work we need to automatically reborrow,
// as if the user had written `foo(x.as_mut())`.

Foo::baz(x);
Foo::baz(x);

foo_const(x); // make sure we can reborrow &mut as &.

let x: Pin<&Foo> = Pin::new(&Foo);

foo_const(x); // make sure reborrowing from & to & works.
}

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/async-await/pin-reborrow-const-as-mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![feature(pin_ergonomics)]
#![allow(dead_code, incomplete_features)]

// make sure we can't accidentally reborrow Pin<&T> as Pin<&mut T>

use std::pin::Pin;

struct Foo;

fn foo(_: Pin<&mut Foo>) {
}

fn bar(x: Pin<&Foo>) {
foo(x); //~ ERROR mismatched types
//| ERROR types differ in mutability
}

fn main() {}
19 changes: 19 additions & 0 deletions tests/ui/async-await/pin-reborrow-const-as-mut.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/pin-reborrow-const-as-mut.rs:14:9
|
LL | foo(x);
| --- ^ types differ in mutability
| |
| arguments to this function are incorrect
|
= note: expected struct `Pin<&mut Foo>`
found struct `Pin<&Foo>`
note: function defined here
--> $DIR/pin-reborrow-const-as-mut.rs:10:4
|
LL | fn foo(_: Pin<&mut Foo>) {
| ^^^ ----------------

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.

0 comments on commit a18800f

Please sign in to comment.