From b2b76fb70659f55d5e1842b28c7d6c451ae916d9 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 19 Sep 2024 11:18:00 -0700 Subject: [PATCH] Allow shortening reborrows Generating a call to `as_mut()` let to more restrictive borrows than what reborrowing usually gives us. Instead, we change the desugaring to reborrow the pin internals directly which makes things more expressive. --- compiler/rustc_hir/src/lang_items.rs | 1 - compiler/rustc_hir_typeck/src/coercion.rs | 5 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 12 +-- compiler/rustc_middle/src/ty/adjustment.rs | 5 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 96 +++++++++++-------- compiler/rustc_span/src/symbol.rs | 1 - library/core/src/pin.rs | 1 - tests/ui/async-await/pin-reborrow-shorter.rs | 14 +++ 8 files changed, 77 insertions(+), 58 deletions(-) create mode 100644 tests/ui/async-await/pin-reborrow-shorter.rs diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 60e024068e9..e7398fd2226 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -395,7 +395,6 @@ language_item_table! { IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None; PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; - PinAsMut, sym::pin_as_mut, as_mut_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct, GenericRequirement::None; RangeFull, sym::RangeFull, range_full_struct, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index d548df98bf9..d45d7f54ed4 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -824,10 +824,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // add the adjustments. self.unify_and(a, b, |_inner_ty| { vec![Adjustment { - kind: Adjust::ReborrowPin(AutoBorrow::Ref( - b_region, - AutoBorrowMutability::Mut { allow_two_phase_borrow: AllowTwoPhase::No }, - )), + kind: Adjust::ReborrowPin(b_region, hir::Mutability::Mut), target: b, }] }) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 95a3cf7b96b..3b2ddf659a1 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -781,14 +781,12 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.walk_autoref(expr, &place_with_id, autoref); } - adjustment::Adjust::ReborrowPin(ref autoref) => { + adjustment::Adjust::ReborrowPin(_, mutbl) => { // Reborrowing a Pin is like a combinations of a deref and a borrow, so we do // both. - let bk = match autoref { - adjustment::AutoBorrow::Ref(_, m) => { - ty::BorrowKind::from_mutbl((*m).into()) - } - adjustment::AutoBorrow::RawPtr(m) => ty::BorrowKind::from_mutbl(*m), + let bk = match mutbl { + ty::Mutability::Not => ty::BorrowKind::ImmBorrow, + ty::Mutability::Mut => ty::BorrowKind::MutBorrow, }; self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); } @@ -1296,7 +1294,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) | adjustment::Adjust::Borrow(_) - | adjustment::Adjust::ReborrowPin(_) + | adjustment::Adjust::ReborrowPin(..) | adjustment::Adjust::DynStar => { // Result is an rvalue. Ok(self.cat_rvalue(expr.hir_id, target)) diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 7f56e05901c..5a32078760e 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -105,9 +105,8 @@ pub enum Adjust<'tcx> { /// Cast into a dyn* object. DynStar, - /// Take a `Pin` and call either `as_mut()` or `as_ref()` to get a `Pin<&mut T>` or - /// `Pin<&T>`. - ReborrowPin(AutoBorrow<'tcx>), + /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`. + ReborrowPin(ty::Region<'tcx>, hir::Mutability), } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 8e6e13f94e0..3bb00e0b028 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -147,50 +147,64 @@ impl<'tcx> Cx<'tcx> { ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) } } Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) }, - Adjust::ReborrowPin(AutoBorrow::Ref(region, m)) => { + Adjust::ReborrowPin(region, mutbl) => { debug!("apply ReborrowPin adjustment"); - match m { - AutoBorrowMutability::Mut { .. } => { - // Rewrite `$expr` as `Pin::as_mut(&mut $expr)` - let as_mut_method = - self.tcx().require_lang_item(rustc_hir::LangItem::PinAsMut, Some(span)); - let pin_ty_args = match expr.ty.kind() { - ty::Adt(_, args) => args, - _ => bug!("ReborrowPin with non-Pin type"), - }; - let as_mut_ty = - Ty::new_fn_def(self.tcx, as_mut_method, pin_ty_args.into_iter()); + // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }` - let ty = Ty::new_ref(self.tcx, region, expr.ty, ty::Mutability::Mut); - let arg = ExprKind::Borrow { - borrow_kind: BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, - arg: self.thir.exprs.push(expr), - }; - debug!(?arg, "borrow arg"); - let arg = self.thir.exprs.push(Expr { temp_lifetime, ty, span, kind: arg }); + // We'll need these types later on + let pin_ty_args = match expr.ty.kind() { + ty::Adt(_, args) => args, + _ => bug!("ReborrowPin with non-Pin type"), + }; + let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty(); + let ptr_target_ty = match pin_ty.kind() { + ty::Ref(_, ty, _) => *ty, + _ => bug!("ReborrowPin with non-Ref type"), + }; - let kind = ExprKind::Call { - ty: as_mut_ty, - fun: self.thir.exprs.push(Expr { - temp_lifetime, - ty: as_mut_ty, - span, - kind: ExprKind::ZstLiteral { user_ty: None }, - }), - args: Box::new([arg]), - from_hir_call: true, - fn_span: span, - }; - debug!(?kind); - kind - } - AutoBorrowMutability::Not => { - // FIXME: We need to call Pin::as_ref on the expression - bug!("ReborrowPin with shared reference is not implemented yet") - } - } + // pointer = ($expr).__pointer + let pointer_target = ExprKind::Field { + lhs: self.thir.exprs.push(expr), + variant_index: FIRST_VARIANT, + name: FieldIdx::from(0u32), + }; + let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target }; + let arg = self.thir.exprs.push(arg); + + // arg = *pointer + let expr = ExprKind::Deref { arg }; + let arg = self.thir.exprs.push(Expr { + temp_lifetime, + ty: ptr_target_ty, + span, + kind: expr, + }); + + // expr = &mut target + let expr = self.thir.exprs.push(Expr { + temp_lifetime, + ty: Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl), + span, + kind: ExprKind::Borrow { + borrow_kind: BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, + arg, + }, + }); + + // kind = Pin { __pointer: pointer } + let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span)); + let kind = ExprKind::Adt(Box::new(AdtExpr { + adt_def: self.tcx.adt_def(pin_did), + variant_index: FIRST_VARIANT, + args: pin_ty_args, + fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]), + user_ty: None, + base: None, + })); + + debug!(?kind); + kind } - Adjust::ReborrowPin(AutoBorrow::RawPtr(_)) => bug!("ReborrowPin with raw pointer"), }; Expr { temp_lifetime, ty: adjustment.target, span, kind } @@ -1059,7 +1073,7 @@ impl<'tcx> Cx<'tcx> { // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for - // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. + // `Deref(Mut)::deref(_mut)` and `Index(Mut)::index(_mut)`. let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else { span_bug!(span, "overloaded_place: receiver is not a reference"); }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 979294563d7..27ff9afa92c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1418,7 +1418,6 @@ symbols! { pic, pie, pin, - pin_as_mut, pin_ergonomics, platform_intrinsics, plugin, diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index bb1196e82de..9c13662e08e 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1408,7 +1408,6 @@ impl Pin { /// } /// } /// ``` - #[cfg_attr(not(bootstrap), lang = "pin_as_mut")] #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { diff --git a/tests/ui/async-await/pin-reborrow-shorter.rs b/tests/ui/async-await/pin-reborrow-shorter.rs new file mode 100644 index 00000000000..06c266e0035 --- /dev/null +++ b/tests/ui/async-await/pin-reborrow-shorter.rs @@ -0,0 +1,14 @@ +//@check-pass + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +use std::pin::Pin; + +fn shorter<'b, T: 'b>(_: Pin<&'b mut T>) {} + +fn test<'a: 'b, 'b, T: 'a>(x: Pin<&'a mut T>) { + shorter::<'b>(x); +} + +fn main() {}