diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index d45d7f54ed4..94b8541075e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -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 - 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); @@ -809,7 +809,7 @@ 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) @@ -817,16 +817,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } }; - 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 }] }) } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 3bb00e0b028..3f730b5d183 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -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, diff --git a/tests/ui/async-await/pin-reborrow-arg.rs b/tests/ui/async-await/pin-reborrow-arg.rs index b3e8718d036..2008bd1f52d 100644 --- a/tests/ui/async-await/pin-reborrow-arg.rs +++ b/tests/ui/async-await/pin-reborrow-arg.rs @@ -15,6 +15,9 @@ 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, @@ -22,6 +25,12 @@ fn bar(x: Pin<&mut Foo>) { 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() {} diff --git a/tests/ui/async-await/pin-reborrow-const-as-mut.rs b/tests/ui/async-await/pin-reborrow-const-as-mut.rs new file mode 100644 index 00000000000..27c70a7b4df --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-const-as-mut.rs @@ -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() {} diff --git a/tests/ui/async-await/pin-reborrow-const-as-mut.stderr b/tests/ui/async-await/pin-reborrow-const-as-mut.stderr new file mode 100644 index 00000000000..2c2d9ec2717 --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-const-as-mut.stderr @@ -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`.