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.
This commit is contained in:
Eric Holk 2024-09-19 11:18:00 -07:00
parent a73c8b1171
commit b2b76fb706
No known key found for this signature in database
GPG Key ID: F1A772BB658A63E1
8 changed files with 77 additions and 58 deletions

View File

@ -395,7 +395,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None; 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; 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; RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct, GenericRequirement::None;
RangeFull, sym::RangeFull, range_full_struct, Target::Struct, GenericRequirement::None; RangeFull, sym::RangeFull, range_full_struct, Target::Struct, GenericRequirement::None;

View File

@ -824,10 +824,7 @@ fn coerce_pin(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
// add the adjustments. // add the adjustments.
self.unify_and(a, b, |_inner_ty| { self.unify_and(a, b, |_inner_ty| {
vec![Adjustment { vec![Adjustment {
kind: Adjust::ReborrowPin(AutoBorrow::Ref( kind: Adjust::ReborrowPin(b_region, hir::Mutability::Mut),
b_region,
AutoBorrowMutability::Mut { allow_two_phase_borrow: AllowTwoPhase::No },
)),
target: b, target: b,
}] }]
}) })

View File

@ -781,14 +781,12 @@ fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
self.walk_autoref(expr, &place_with_id, autoref); 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 // Reborrowing a Pin is like a combinations of a deref and a borrow, so we do
// both. // both.
let bk = match autoref { let bk = match mutbl {
adjustment::AutoBorrow::Ref(_, m) => { ty::Mutability::Not => ty::BorrowKind::ImmBorrow,
ty::BorrowKind::from_mutbl((*m).into()) ty::Mutability::Mut => ty::BorrowKind::MutBorrow,
}
adjustment::AutoBorrow::RawPtr(m) => ty::BorrowKind::from_mutbl(*m),
}; };
self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
} }
@ -1296,7 +1294,7 @@ fn cat_expr_adjusted_with<F>(
adjustment::Adjust::NeverToAny adjustment::Adjust::NeverToAny
| adjustment::Adjust::Pointer(_) | adjustment::Adjust::Pointer(_)
| adjustment::Adjust::Borrow(_) | adjustment::Adjust::Borrow(_)
| adjustment::Adjust::ReborrowPin(_) | adjustment::Adjust::ReborrowPin(..)
| adjustment::Adjust::DynStar => { | adjustment::Adjust::DynStar => {
// Result is an rvalue. // Result is an rvalue.
Ok(self.cat_rvalue(expr.hir_id, target)) Ok(self.cat_rvalue(expr.hir_id, target))

View File

@ -105,9 +105,8 @@ pub enum Adjust<'tcx> {
/// Cast into a dyn* object. /// Cast into a dyn* object.
DynStar, DynStar,
/// Take a `Pin<Ptr>` and call either `as_mut()` or `as_ref()` to get a `Pin<&mut T>` or /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`.
/// `Pin<&T>`. ReborrowPin(ty::Region<'tcx>, hir::Mutability),
ReborrowPin(AutoBorrow<'tcx>),
} }
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`

View File

@ -147,50 +147,64 @@ fn apply_adjustment(
ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) } ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) }
} }
Adjust::DynStar => ExprKind::Cast { source: 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"); debug!("apply ReborrowPin adjustment");
match m { // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }`
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());
let ty = Ty::new_ref(self.tcx, region, expr.ty, ty::Mutability::Mut); // We'll need these types later on
let arg = ExprKind::Borrow { let pin_ty_args = match expr.ty.kind() {
borrow_kind: BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, ty::Adt(_, args) => args,
arg: self.thir.exprs.push(expr), _ => bug!("ReborrowPin with non-Pin type"),
}; };
debug!(?arg, "borrow arg"); let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty();
let arg = self.thir.exprs.push(Expr { temp_lifetime, ty, span, kind: arg }); let ptr_target_ty = match pin_ty.kind() {
ty::Ref(_, ty, _) => *ty,
_ => bug!("ReborrowPin with non-Ref type"),
};
let kind = ExprKind::Call { // pointer = ($expr).__pointer
ty: as_mut_ty, let pointer_target = ExprKind::Field {
fun: self.thir.exprs.push(Expr { lhs: self.thir.exprs.push(expr),
temp_lifetime, variant_index: FIRST_VARIANT,
ty: as_mut_ty, name: FieldIdx::from(0u32),
span, };
kind: ExprKind::ZstLiteral { user_ty: None }, let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target };
}), let arg = self.thir.exprs.push(arg);
args: Box::new([arg]),
from_hir_call: true, // arg = *pointer
fn_span: span, let expr = ExprKind::Deref { arg };
}; let arg = self.thir.exprs.push(Expr {
debug!(?kind); temp_lifetime,
kind ty: ptr_target_ty,
} span,
AutoBorrowMutability::Not => { kind: expr,
// FIXME: We need to call Pin::as_ref on the expression });
bug!("ReborrowPin with shared reference is not implemented yet")
} // 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 } Expr { temp_lifetime, ty: adjustment.target, span, kind }
@ -1059,7 +1073,7 @@ fn overloaded_place(
// Reconstruct the output assuming it's a reference with the // Reconstruct the output assuming it's a reference with the
// same region and mutability as the receiver. This holds for // 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 { let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
span_bug!(span, "overloaded_place: receiver is not a reference"); span_bug!(span, "overloaded_place: receiver is not a reference");
}; };

View File

@ -1418,7 +1418,6 @@
pic, pic,
pie, pie,
pin, pin,
pin_as_mut,
pin_ergonomics, pin_ergonomics,
platform_intrinsics, platform_intrinsics,
plugin, plugin,

View File

@ -1408,7 +1408,6 @@ impl<Ptr: DerefMut> Pin<Ptr> {
/// } /// }
/// } /// }
/// ``` /// ```
#[cfg_attr(not(bootstrap), lang = "pin_as_mut")]
#[stable(feature = "pin", since = "1.33.0")] #[stable(feature = "pin", since = "1.33.0")]
#[inline(always)] #[inline(always)]
pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> {

View File

@ -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() {}