Skip to content

Commit a18800f

Browse files
committed
pin_ergonomics: allow reborrowing as Pin<&T>
1 parent 92a5d21 commit a18800f

File tree

5 files changed

+70
-15
lines changed

5 files changed

+70
-15
lines changed

Diff for: compiler/rustc_hir_typeck/src/coercion.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -798,9 +798,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
798798
// Right now we can only reborrow if this is a `Pin<&mut T>`.
799799
let extract_pin_mut = |ty: Ty<'tcx>| {
800800
// Get the T out of Pin<T>
801-
let ty = match ty.kind() {
801+
let (pin, ty) = match ty.kind() {
802802
ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
803-
args[0].expect_ty()
803+
(*pin, args[0].expect_ty())
804804
}
805805
_ => {
806806
debug!("can't reborrow {:?} as pinned", ty);
@@ -809,24 +809,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
809809
};
810810
// Make sure the T is something we understand (just `&mut U` for now)
811811
match ty.kind() {
812-
ty::Ref(region, ty, ty::Mutability::Mut) => Ok((*region, *ty)),
812+
ty::Ref(region, ty, mutbl) => Ok((pin, *region, *ty, *mutbl)),
813813
_ => {
814814
debug!("can't reborrow pin of inner type {:?}", ty);
815815
Err(TypeError::Mismatch)
816816
}
817817
}
818818
};
819819

820-
let (_, _a_ty) = extract_pin_mut(a)?;
821-
let (b_region, _b_ty) = extract_pin_mut(b)?;
820+
let (pin, a_region, a_ty, mut_a) = extract_pin_mut(a)?;
821+
let (_, b_region, _b_ty, mut_b) = extract_pin_mut(b)?;
822+
823+
coerce_mutbls(mut_a, mut_b)?;
824+
825+
// update a with b's mutability since we'll be coercing mutability
826+
let a = Ty::new_adt(
827+
self.tcx,
828+
pin,
829+
self.tcx.mk_args(&[Ty::new_ref(self.tcx, a_region, a_ty, mut_b).into()]),
830+
);
822831

823832
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
824833
// add the adjustments.
825834
self.unify_and(a, b, |_inner_ty| {
826-
vec![Adjustment {
827-
kind: Adjust::ReborrowPin(b_region, hir::Mutability::Mut),
828-
target: b,
829-
}]
835+
vec![Adjustment { kind: Adjust::ReborrowPin(b_region, mut_b), target: b }]
830836
})
831837
}
832838

Diff for: compiler/rustc_mir_build/src/thir/cx/expr.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,25 @@ impl<'tcx> Cx<'tcx> {
181181
});
182182

183183
// expr = &mut target
184+
let borrow_kind = match mutbl {
185+
hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
186+
hir::Mutability::Not => BorrowKind::Shared,
187+
};
188+
let new_pin_target = Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl);
184189
let expr = self.thir.exprs.push(Expr {
185190
temp_lifetime,
186-
ty: Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl),
191+
ty: new_pin_target,
187192
span,
188-
kind: ExprKind::Borrow {
189-
borrow_kind: BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
190-
arg,
191-
},
193+
kind: ExprKind::Borrow { borrow_kind, arg },
192194
});
193195

194196
// kind = Pin { __pointer: pointer }
195197
let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span));
198+
let args = self.tcx.mk_args(&[new_pin_target.into()]);
196199
let kind = ExprKind::Adt(Box::new(AdtExpr {
197200
adt_def: self.tcx.adt_def(pin_did),
198201
variant_index: FIRST_VARIANT,
199-
args: pin_ty_args,
202+
args,
200203
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
201204
user_ty: None,
202205
base: None,

Diff for: tests/ui/async-await/pin-reborrow-arg.rs

+9
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,22 @@ impl Foo {
1515
fn foo(_: Pin<&mut Foo>) {
1616
}
1717

18+
fn foo_const(_: Pin<&Foo>) {
19+
}
20+
1821
fn bar(x: Pin<&mut Foo>) {
1922
foo(x);
2023
foo(x); // for this to work we need to automatically reborrow,
2124
// as if the user had written `foo(x.as_mut())`.
2225

2326
Foo::baz(x);
2427
Foo::baz(x);
28+
29+
foo_const(x); // make sure we can reborrow &mut as &.
30+
31+
let x: Pin<&Foo> = Pin::new(&Foo);
32+
33+
foo_const(x); // make sure reborrowing from & to & works.
2534
}
2635

2736
fn main() {}

Diff for: tests/ui/async-await/pin-reborrow-const-as-mut.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(pin_ergonomics)]
2+
#![allow(dead_code, incomplete_features)]
3+
4+
// make sure we can't accidentally reborrow Pin<&T> as Pin<&mut T>
5+
6+
use std::pin::Pin;
7+
8+
struct Foo;
9+
10+
fn foo(_: Pin<&mut Foo>) {
11+
}
12+
13+
fn bar(x: Pin<&Foo>) {
14+
foo(x); //~ ERROR mismatched types
15+
//| ERROR types differ in mutability
16+
}
17+
18+
fn main() {}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/pin-reborrow-const-as-mut.rs:14:9
3+
|
4+
LL | foo(x);
5+
| --- ^ types differ in mutability
6+
| |
7+
| arguments to this function are incorrect
8+
|
9+
= note: expected struct `Pin<&mut Foo>`
10+
found struct `Pin<&Foo>`
11+
note: function defined here
12+
--> $DIR/pin-reborrow-const-as-mut.rs:10:4
13+
|
14+
LL | fn foo(_: Pin<&mut Foo>) {
15+
| ^^^ ----------------
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)